work hard work smart

专注于Java后端开发。 不断总结,举一反三。
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

手写Spring框架学习笔记

Posted on 2018-11-21 15:03  work hard work smart  阅读(498)  评论(0编辑  收藏  举报

以下是咕泡公开课的学习笔记

一、创建工程springdemo

 

二、在pom中配置servlet

  <dependency>
      <groupId>javax.servlet</groupId>
      <artifactId>servlet-api</artifactId>
      <version>2.5</version>
      <scope>provided</scope>
    </dependency>

 

三、web.xml文件

<!DOCTYPE web-app PUBLIC
 "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN"
 "http://java.sun.com/dtd/web-app_2_3.dtd" >

<web-app>
  <display-name>Archetype Created Web Application</display-name>

  <servlet>
    <servlet-name>mvc</servlet-name>
    <servlet-class>com.example.mvcframework.servlet.DispatcherServlet</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>mvc</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>

  

四、资源文件

application.properties文件

scanPackage=com.example.demo

 

五、创建注解

1、Autowired 

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    String value() default  "";
}

  

2、Controller 

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Controller {
    String value() default  "";
}

  

3、RequestMapping 

@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestMapping {
    String value() default  "";
}

  

4、RequestParam 

@Target({ElementType.PARAMETER})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface RequestParam {
    String value() default  "";
}

  

5、Service

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Service {
    String value() default  "";
}

  

六、创建DispatcherServlet

public class DispatcherServlet extends HttpServlet {

    private Properties contextConfig = new Properties();

    private List<String> classNames = new ArrayList<>();

    private Map<String, Object> ioc = new HashMap<>();

    private Map<String,Method> handlerMapping = 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 {
        //运行阶段,根据用户请求的URL进行自动分发和调度
        try {
            doDispatch(req,resp);
        } catch (Exception e) {
            e.printStackTrace();
            resp.getWriter().write("500 Detail:" + Arrays.toString(e.getStackTrace()));
        }
    }

    private void doDispatch(HttpServletRequest req, HttpServletResponse resp) throws Exception {
        if(this.handlerMapping.isEmpty()){
            return;
        }
        //绝对路径
        String url  = req.getRequestURI();
        //处理成相对路径
        String contextPath = req.getContextPath();
        url = url.replace(contextPath, "").replaceAll("/+", "/");
        if(!this.handlerMapping.containsKey(url)){
            resp.getWriter().write("404 Not found");
            return;
        }

        Method method = this.handlerMapping.get(url);
        //如何拿到实例?
        //唯一的方式从IOC容器中拿
        //继续投机取巧
        String beanName =  lowerFirstCase(method.getDeclaringClass().getSimpleName());
        System.out.println("beanName:" + beanName);
        Map<String,String[]> params = req.getParameterMap();

        method.invoke(ioc.get(beanName), new Object[]{req, resp,params.get("name")[0]});


       // System.out.println(method);
    }


    @Override
    public void init(ServletConfig config) throws ServletException {
        //1、加载配置文件
        doLoadConfig(config.getInitParameter("contextConfigLocation"));

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

        //3.初始化刚刚扫描到所有相关的类,并且把它保存在IOC容器中
        doInstance();

        //4. 实现依赖注入 DI 自动赋值
        doAutowired();

        //5. 初始化handlerMapping
        initHandleMapping();

        System.out.println("Spring is init");
    }

    private void initHandleMapping() {
        if(ioc.isEmpty()){
            return;
        }

        for(Map.Entry<String, Object> entry: ioc.entrySet()) {
            Class<?> clazz = entry.getValue().getClass();
            if(!clazz.isAnnotationPresent(Controller.class)){
                continue;
            }

            String baseUrl = "";
            if(clazz.isAnnotationPresent(RequestMapping.class)){
                RequestMapping requestMapping = clazz.getAnnotation(RequestMapping.class);
                baseUrl =  requestMapping.value();
            }

            Method[] methods = clazz.getMethods(); //只认public的方法
            for(Method method : methods){
                if(!method.isAnnotationPresent(RequestMapping.class)){
                    continue;
                }
                RequestMapping requestMapping =  method.getAnnotation(RequestMapping.class);
               String url = ("/" + baseUrl + "/" + requestMapping.value()).replaceAll("/+", "/");
                handlerMapping.put(url,method);
                System.out.println("Mapped:" + url +"," + method);
            }

            Field[] fields = entry.getValue().getClass().getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }
            }
        }
    }

    private void doAutowired() {
        if(ioc.isEmpty()){
            return;
        }

        for(Map.Entry<String, Object> entry: ioc.entrySet()){
           Field[] fields = entry.getValue().getClass().getDeclaredFields();
           for(Field field: fields){
               if(!field.isAnnotationPresent(Autowired.class)){
                   continue;
               }

              Autowired autowired =  field.getAnnotation(Autowired.class);
              String beanName = autowired.value().trim();
              if("".equals(beanName)){
                  beanName = field.getType().getName();
              }

              field.setAccessible(true); //强制暴力访问
               try {
                   field.set(entry.getValue(), ioc.get(beanName));
               } catch (IllegalAccessException e) {
                   e.printStackTrace();
                   continue;
               }

           }
        }
    }

    private void doInstance() {
        if(classNames.isEmpty()){
            return;
        }

        try{
            for (String className: classNames) {
               Class<?> clazz =  Class.forName(className);
               //实例化,把实例化的对象保存到IOC容器之中

                if(clazz.isAnnotationPresent(Controller.class)){
                    Object instance = clazz.newInstance();
                    String beanName = lowerFirstCase(clazz.getSimpleName());
                    ioc.put(beanName, instance);
                } else if(clazz.isAnnotationPresent(Service.class)){
                    //因为Service有可能注入的不是它本身,有可能是它的实现类
                    //1、默认类名首字母小写

                    //2、自定义的beanName
                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    if("".equals(beanName)){
                         beanName = lowerFirstCase(clazz.getSimpleName());
                    }
                    Object instance = clazz.newInstance();
                    ioc.put(beanName, instance);

                    //3、如果是接口,投机取巧的方式,用它的接口类型作为key
                    Class<?>[] interfaces = clazz.getInterfaces();
                    for(Class<?> i : interfaces){
                        if(ioc.containsKey(i.getName())){
                            throw  new Exception("The beanName is exists");
                        }
                        ioc.put(i.getName(), instance);
                    }

                }else{
                    continue;
                }

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

    }

    /**
     * 类名首字母小写
     */
    private String lowerFirstCase(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("\\.", "/"));
        File classDir = new File(url.getFile());
        for(File file : classDir.listFiles()){
            if(file.isDirectory()){
                doScanner(scanPackage + "." + file.getName());
            }else{
                if(file.getName().endsWith(".class")){
                    String classname = (scanPackage + "." +file.getName()).replace(".class","");
                    classNames.add(classname);
                }
            }
        }
    }

    private void doLoadConfig(String contextConfigLocation) {
        InputStream is = this.getClass().getClassLoader().getResourceAsStream(contextConfigLocation);
        try {
            contextConfig.load(is);
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            if(is != null){
                try {
                    is.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }
}

  

七、使用

1、创建接口

public interface IDemoService {
    String get(String name);
}

  

2、创建服务

@Service
public class DemoService implements IDemoService {
    @Override
    public String get(String name) {
        return "hello," + name;
    }
}

  

3、创建Controller

@Controller
@RequestMapping("/demo")
public class DemoAction {

    @Autowired
    private IDemoService demoService;

    @RequestMapping("/query")
    public  void query(HttpServletRequest req, HttpServletResponse resp, @RequestParam("name") String name){
        String result = demoService.get(name);
        try {
            resp.getWriter().write(result);
        }catch (IOException e){
            e.printStackTrace();
        }
    }

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

    @RequestMapping("/remove")
    public  void remove(HttpServletRequest req, HttpServletResponse resp,  @RequestParam("id")Integer id){

    }
}

  

八、测试

 

九、Spring十大优势

1、面向接口编程
2、IOC容器的问世
3、AOP思想,使得程序员把大部分精力投入到业务
4、Spring生态完善,Spring不仅仅只是一个框架
5、兼容程度高。只要有Java的地方就有Spring的用武之地
6、Spring的模块化拆分的非常精准,避免过度依赖(低耦合)
7、轻量级,所有的操作都建立在JavaBean之上
8、Spring与时俱进,全面支持Annotation,简化配置。如今的Spring可以实现配置裕兴
9、内部工具类非常丰富,简化开发,提升开发效率
10、Spring与各个开源框架可以实现无缝集成(Dubbo框架也是与Spring集成)
核心:提升开发效