美文网首页
Spring源码阅读整体介绍

Spring源码阅读整体介绍

作者: 逍遥白亦 | 来源:发表于2020-11-26 20:39 被阅读0次

    本系列开篇第一文,从整体梳理Spring的脉络。

    1. 闲聊创建对象

    首先先来看,如果没有Spring这个框架,在Java里如何创建对象。

       Class A = new Class();
    

    基本有Java基础的人可以很简单的写出上面代码,那么当我们希望调用其他对象的时候,比如有一个ClassA,里边有一个成员变量name,在对该类初始化的时候,对name属性进行赋值,最终希望可以获得这个name。

    public class ClassA {
        private String name;
    
        public ClassA(String name) {
            this.name = name;
        }
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    }
    
    

    调用类

    public class AppClass {
    
        public static void main(String[] args) {
            ClassA classA = new ClassA("Spring");
            System.out.println(classA.getName());
    
        }
    
    }
    
    

    如此就可以在AppClass里调用ClassA的方法了。

    1.1 如果类很多呢?

    上边的代码如果只是简单的写写Demo那还可以忍受,但是学代码可不只是为了写Demo,我们是有理想有抱负的,要面向工资....哦不,要使代码整体简洁一点,要解耦。

    那么我们就希望在调用类里,将ClassA变为一个成员变量,那么不实例化的情况下,怎么可以获取ClassA的所有属性呢?

    稍微学过Java基础的朋友,会想到反射。

    1.2 用反射获取对象

    举一个日常搬砖的常用例子,有一个UserController类,在这个类会接收所有的用户服务的请求,并调用UserService类,对请求的参数做处理,比如去数据库查询用户信息。那么代码会写成如下这样:

    UserController类

    package controller;
    
    import service.UserService;
    
    public class UserController {
    
        private UserService userService;
    
        public UserService getUserService() {
            return userService;
        }
    
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    }
    
    
    

    UserService类

    package service;
    
    public class UserService {
    
    }
    
    

    测试类

    import controller.UserController;
    import org.junit.Test;
    import service.UserService;
    
    import java.lang.reflect.Field;
    import java.lang.reflect.Method;
    
    public class AppClass {
    
        @Test
        public void reflectionTest() throws Exception{
            UserController userController = new UserController();
    
            Class<? extends  UserController> clazz = userController.getClass();
    
            //创建对象
            UserService userService = new UserService();
    
            //获取所有的属性
            Field serviceField = clazz.getDeclaredField("userService");
    
            serviceField.setAccessible(true);
    
            //只有通过方法才能够设置具体的属性值
            String name = serviceField.getName();
    
            //拼接方法的名称
            name = name.substring(0,1).toUpperCase() + name.substring(1, name.length());
            String setMethodName = "set" + name;
            //通过方法注入属性的对象
            Method method = clazz.getMethod(setMethodName, UserService.class);
            //反射
            method.invoke(userController,userService);
            System.out.println(userController.getUserService());
        }
    }
    

    1.3 加注解实现

    上述代码通过反射创建了UserService对象,但是实际情况一般是用Spring里的一个@Autowired注解来实现,那么接下来,就自己实现一个该注解。

    注解

    package com.demo;
    
    import java.lang.annotation.ElementType;
    import java.lang.annotation.Retention;
    import java.lang.annotation.RetentionPolicy;
    import java.lang.annotation.Target;
    
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.FIELD)
    public @interface AutoWired {
    }
    
    

    UserController类

    package com.demo.controller;
    
    import com.demo.service.UserService;
    import com.demo.AutoWired;
    
    public class UserController {
    
        @AutoWired
        private UserService userService;
    
        public UserService getUserService() {
            return userService;
        }
    
        public void setUserService(UserService userService) {
            this.userService = userService;
        }
    }
    
    

    UserService类不变,测试类

    package com.demo;
    
    import com.demo.controller.UserController;
    import org.junit.Test;
    
    import java.util.stream.Stream;
    
    public class AppClass {
    
        @Test
        public void reflectionTest() throws Exception{
            UserController userController = new UserController();
    
            Class<? extends UserController> clazz = userController.getClass();
    
            Stream.of(clazz.getDeclaredFields()).forEach( field -> {
                String name = field.getName();
                AutoWired annotation = field.getAnnotation(AutoWired.class);
                if (annotation != null){
                    field.setAccessible(true);
                    //获取属性的类型
                    Class<?> type = field.getType();
                    try {
                        Object o= type.newInstance();
                        field.set(userController, o);
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            });
            System.out.println(userController.getUserService());
        }
    
    
    }
    
    

    这样,我们可以不用写死UserService类,可以通过注解,注入多个类。

    2. Spring做了什么

    我们在使用Spring的时候,注入Bean会通过注解、XML文件以及配置类等方式,最终将类注入到IOC容器中,在容易中对类进行实例化。那么如果我们不看源码的话,这些功能怎么实现呢?

    2.1 读取XML文件、注解以及配置类(BeanDefinitionReader)

    首先我们会先抽象出一层,将这些来源的类读取出来,所以会先抽象出一层来对这些类进行读取、处理,这在Spring里边是由BeanDefinitionReader实现的。

    2.2 创建对象的工厂

    提到创建对象,就会想到一个很熟悉的思想,就是工厂类,用工厂类创建对象,Spring提供了BeanFactory进行对象的创建。

    2.2.1 BeanFactory与FactoryBean

    我们想下如果所有的对象只能通过一种方式创建,而用户自己无法更改,是一种很不好的设计。举个例子,比如远古传说中有女娲造人,女娲把地上的泥土都按照一种方式捏出来,变成人,这种方式就是BeanFactory,但是久而久之,所有人都一样,那么就无法进行区分,这时女娲想到,可以创造出不同的作坊,再给这些作坊制定一个负责人,由负责人自己进行创造,可以捏出男人、女人、高的人、矮的人等等。这些作坊的思想就是FactoryBean。

    用户可以自己定义一个FactoryBean类,最终通过该类的getObjcet方法,返回一个用户自定义的实例,增强了扩展性,大名鼎鼎的FeignClient就是通过这种方式创建的。

    2.3 各种后置处理器

    当这些Bean在进入容器之前或者进入容器之后时,我们需要对类进行一些扩展,所以就有了BeanFactoryPostProcessor以及BeanPostProcessor后置处理器。大名鼎鼎的AOP就是通过BeanPostProcessor进行扩展的。

    2.4 bean的生命周期

    在IOC容器里,bean会经过实例化、填充属性、初始化以及各种后置处理之后,放入对象池里,这其中就有一个bean的生命周期的概念。

    生命周期大体是这样(后续看源码的时候,会对其进行验证):

    1. 实例化Bean对象,这个时候Bean的对象是非常低级的,基本不能够被我们使用,因为连最基本的属性都没有设置,可以理解为 连Autowired注解都是没有解析的;
    2. 填充属性,当做完这一步,Bean对象基本是完整的了,可以理解为Autowired注解已经解析完毕,依赖注入完成了;
    3. 如果Bean实现了BeanNameAware接口,则调用setBeanName方法;
    4. 如果Bean实现了BeanClassLoaderAware接口,则调用setBeanClassLoader方法;
    5. 如果Bean实现了BeanFactoryAware接口,则调用setBeanFactory方法;
    6. 调用BeanPostProcessor的postProcessBeforeInitialization方法;
    7. 如果Bean实现了InitializingBean接口,调用afterPropertiesSet方法;
    8. 如果Bean定义了init-method方法,则调用Bean的init-method方法;
    9. 调用BeanPostProcessor的postProcessAfterInitialization方法;当进行到这一步,Bean已经被准备就绪了,一直停留在应用的 上下文中,直到被销毁;
    10. 如果应用的上下文被销毁了,如果Bean实现了DisposableBean接口,则调用destroy方法,如果Bean定义了destory-method 声明了销毁方法也会被调用。

    2.5 监听器

    这里边因为会在bean对象的不同阶段对其进行处理,所以还会用到一个很重要的思想,叫观察者模式,Spring里还有许多监听器。

    2.6 环境

    我们在使用Spring时,还有一些配置文件,注入xx.properties或者xx.yml等,会通过Environment类加载到容器中。

    3. 结语

    至此,Spring整体的代码以及设计思路,就简单的分析完了,下篇开始进入撸源码阶段。

    最后附上整体结构图


    image

    相关文章

      网友评论

          本文标题:Spring源码阅读整体介绍

          本文链接:https://www.haomeiwen.com/subject/opbziktx.html