手撕Spring----Spring源码解读-IOC、DI

一、框架解读:

二、源码:

#web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xmlns="http://java.sun.com/xml/ns/j2ee" xmlns:javaee="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
         xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
         version="2.4">
  <display-name>Jason Web Application</display-name>
  <servlet>
    <servlet-name>jasonmvc</servlet-name>
    <servlet-class>com.jason.spring.framework.webmvc.JasonDispatchServlet</servlet-class>
    <init-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>application.properties</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
  </servlet>
  <servlet-mapping>
    <servlet-name>jasonmvc</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
package com.jason.spring.framework.webmvc;

import com.jason.spring.framework.annoation.*;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.net.URL;
import java.util.*;

/**
 * @program: Jason-spring-1.0-ioc
 * @description
 * @author: 大龄程序猿
 * @create: 2020-04-10 20:47
 **/
public class JasonDispatchServlet  extends HttpServlet {
    private Properties  contextConfig=new Properties();
    public List<String> classNameList=new ArrayList<>();
    public Map<String,Object> ioc=new HashMap<>();
    public Map<String,Method> handleMapping=new HashMap<>();
    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req,resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //6、委派  根据URL隐射对应的handleMapping
        try {
            doDispatch(req,resp);
        } catch (Exception e) {
            e.printStackTrace();
            resp.getWriter().write("500 Exception,Detail:"+Arrays.toString(e.getStackTrace()));
        }

    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
           String url=req.getRequestURI();
           String contextPath=req.getContextPath();
           url=url.replaceAll(contextPath,"").replaceAll("/+","/");
           if(!handleMapping.containsKey(url)){
                  resp.getWriter().write("404 Not Found!!!");
                  return;
           }
           Map<String,String[]> params=req.getParameterMap();
           Method method=handleMapping.get(url);

        //获取形参列表
        Class<?> [] parameterTypes = method.getParameterTypes();
        Object [] paramValues = new Object[parameterTypes.length];

        for (int i = 0; i < parameterTypes.length; i++) {
            Class paramterType = parameterTypes[i];
            if(paramterType == HttpServletRequest.class){
                paramValues[i] = req;
            }else if(paramterType == HttpServletResponse.class){
                paramValues[i] = resp;
            }else if(paramterType == String.class){
                //通过运行时的状态去拿到你
                Annotation[] [] pa = method.getParameterAnnotations();
                for (int j = 0; j < pa.length ; j ++) {
                    for(Annotation a : pa[i]){
                        if(a instanceof JasonRequestParam){
                            String paramName = ((JasonRequestParam) a).value();
                            if(!"".equals(paramName.trim())){
                                String value = Arrays.toString(params.get(paramName))
                                        .replaceAll("\\[|\\]","")
                                        .replaceAll("\\s+",",");
                                paramValues[i] = value;
                            }
                        }
                    }
                }

            }
        }


        //暂时硬编码
        String beanName = toLowerFirsCase(method.getDeclaringClass().getSimpleName());
        //赋值实参列表
        System.out.println("ioc.get("+beanName+")="+ioc.get(beanName));
        System.out.println("paramValues="+paramValues);

        method.invoke(ioc.get(beanName),paramValues);
    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        System.out.println("Jason Spring framework init start!");

        //1.加载配置文件
        doLoadConfig(config.getInitParameter("contextConfigLocation"));

        //2、扫描相关的类
        doScanner(contextConfig.getProperty("scanPackage"));

        /**********************IOC*******************************/
        //3、初始化IOC容器,将扫描到的类相关实例,保存到IOC容器
        doInstance();
        /**********************AOP*******************************/
        //新生成的代理对象,需要在DI之前

        /**********************DI*******************************/
        //4、完成依赖注入
        doAutoWired();

        /**********************MVC*******************************/
        //5、初始化handlerMapping
        doInitHandlerMapping();

        System.out.println("Jason Spring framework init finished!");
    }

    private void doInitHandlerMapping() {
        if(ioc.isEmpty())
        {
            return;
        }
        //只取public方法
        for(Map.Entry entry:ioc.entrySet())
        {
            Class<?> clazz=entry.getValue().getClass();
            if(!clazz.isAnnotationPresent(JasonController.class))
            {
                continue;
            }
            String baseUrl="";
            if(clazz.isAnnotationPresent(JasonRequestMapping.class))
            {
                baseUrl=clazz.getAnnotation(JasonRequestMapping.class).value().trim();
            }
            for(Method method:clazz.getMethods())
            {
               if(!method.isAnnotationPresent(JasonRequestMapping.class))
               {
                   continue;
               }
               JasonRequestMapping  jasonRequestMapping=method.getAnnotation(JasonRequestMapping.class);
                String url = ("/" + baseUrl + "/" + jasonRequestMapping.value()).replaceAll("/+","/");
                handleMapping.put(url,method);
                System.out.println("初始化handleMapping方法隐射:"+url+"---"+method);
            }
        }
    }

    private void doAutoWired() {
        if(ioc.isEmpty())
        {
            return;
        }
        for(Map.Entry<String,Object> entry:ioc.entrySet())
        {
            //获取private,public,default所有的属性
            for(Field field:entry.getValue().getClass().getDeclaredFields())
            {
                if(!field.isAnnotationPresent(JasonAutowired.class))
                {
                    continue;
                }
                String beanName=field.getAnnotation(JasonAutowired.class).value();

                if("".equals(beanName.trim()))
                {
                    beanName=field.getType().getName();
                }
                System.out.println("doAutoWired="+beanName);
                field.setAccessible(true);
                try {
                    field.set(entry.getValue(),ioc.get(beanName));
                    System.out.println("ioc.get("+beanName+")="+ioc.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void doInstance() {
        if(classNameList.isEmpty()){
            return;
        }
        for(String className:classNameList)
        {
            try
            {
                Class<?>  clazz=Class.forName(className);

                if(clazz.isAnnotationPresent(JasonController.class))
                {
                    Object  obj=clazz.newInstance();
                    String beanName=toLowerFirsCase(clazz.getSimpleName());
                    ioc.put(beanName,obj);
                }else if(clazz.isAnnotationPresent(JasonService.class))
                {
                    //1.在多个包路径下,同名service,只能自己起一个全局唯一的名称@JasonService("AService")  @JasonService("BService")
                    String  beanName=clazz.getAnnotation(JasonService.class).value();
                    if("".equals(beanName.trim()))
                    {
                        //2.默认的类首字母小写
                        beanName=toLowerFirsCase(clazz.getSimpleName());
                    }

                    Object  obj=clazz.newInstance();
                    ioc.put(beanName,obj);

                    //3.如果是接口,判断有多少个实现类,如果有多个实现类,则抛出异常。如果只有一个,则默认就是实现类。
                    for(Class<?> i:clazz.getInterfaces())
                    {
                        if(ioc.containsKey(i.getName()))
                        {
                            throw  new Exception("The "+i.getName()+" is Exists!!");
                        }
                        ioc.put(i.getName(),obj);
                    }

                }else
                {
                    continue;
                }

            }catch (Exception e)
            {
                e.printStackTrace();
            }

        }
        System.out.println("IOC容器初始化结果:"+ioc);


    }

    private String toLowerFirsCase(String simpleName) {
            char[] chars=simpleName.toCharArray();
            chars[0]+=32;
            return  String.valueOf(chars);
    }

    private void doScanner(String scanPackage) {
        URL  url=this.getClass().getClassLoader().getResource(scanPackage.replaceAll("\\.","/"));
        System.out.println("url.getFile="+url.getFile());
        File  classPath=new File(url.getFile());
        for(File file:classPath.listFiles())
        {
            if(file.isDirectory())
            {
                doScanner(scanPackage+"."+file.getName());
            }else
            {
                if(!file.getName().endsWith(".class")) {continue;}
                classNameList.add(scanPackage+"."+file.getName().replace(".class",""));
            }
        }


    }

    private void doLoadConfig(String contextConfigLocation) {
        System.out.println("contextConfigLocation="+contextConfigLocation);
        InputStream inputStream=this.getClass().getClassLoader().getResourceAsStream("application.properties");
        System.out.println("inputStream="+inputStream);
        try {
            contextConfig.load(inputStream);
            System.out.println("初始化,读取配置文件:--------------"+contextConfig.getProperty("scanPackage"));

        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                if(inputStream!=null)
                    inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }


    }
}

三、测试类:

package com.jason.demo.action;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.jason.demo.service.IDemoService;
import com.jason.spring.framework.annoation.JasonAutowired;
import com.jason.spring.framework.annoation.JasonController;
import com.jason.spring.framework.annoation.JasonRequestMapping;
import com.jason.spring.framework.annoation.JasonRequestParam;


//虽然,用法一样,但是没有功能
@JasonController
@JasonRequestMapping("/demo")
public class DemoAction {

  	@JasonAutowired
	private IDemoService demoService;

	@JasonRequestMapping("/query")
	public void query(HttpServletRequest req, HttpServletResponse resp,
					  @JasonRequestParam("name") String name){
		System.out.println("---------------------"+demoService);
		String result = demoService.get(name);
		System.out.println(result);
		try {
			resp.getWriter().write(result);
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@JasonRequestMapping("/add")
	public void add(HttpServletRequest req, HttpServletResponse resp,
					@JasonRequestParam("a") Integer a, @JasonRequestParam("b") Integer b){
		try {
			resp.getWriter().write(a + "+" + b + "=" + (a + b));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@JasonRequestMapping("/sub")
	public void add(HttpServletRequest req, HttpServletResponse resp,
					@JasonRequestParam("a") Double a, @JasonRequestParam("b") Double b){
		try {
			resp.getWriter().write(a + "-" + b + "=" + (a - b));
		} catch (IOException e) {
			e.printStackTrace();
		}
	}

	@JasonRequestMapping("/remove")
	public String  remove(@JasonRequestParam("id") Integer id){
		return "" + id;
	}

}

四、浏览器测试:

猜你喜欢

转载自blog.csdn.net/jason_jiahongfei/article/details/105450917