Spring源码02

60 阅读6分钟

是根据黑马Spring源码课程总结的

首先使用SpringBoot来启动,java8即可,添加Spring的基本功能即可,如果需要后面可以继续加。

第二讲、容器实现

1、BeanFactory的实现

初始代码:

public class TestBeanFactory {

    public static void main(String[] args) {
        
    }

    @Configuration
    static class Config{
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }
    }

    interface Inter{

    }

    static class Bean3 implements Inter{

    }

    static class Bean4 implements Inter{

    }

    static class Bean1{
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1(){
            log.debug("构造 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2(){
            return bean2;
        }
    }

    static class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
}

它用到了DefaultListableBeanFactory这个BeanFactory的实现类,而它也是最最核心的BeanFactory的实现类,现在可以定义bean并且创建bean,代码如下:

public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    //设置bean的定义,就如同xml文件设置bean一样,现在还不是创建bean的对象
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
            .setScope("singleton").getBeanDefinition();
    //使用beanFactory创建bean
    beanFactory.registerBeanDefinition("config",beanDefinition);
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }
}

但是会发现,只有一个结果:

config

这是因为@Bean、@Autowired、@Resource等注解的功能还没加入,因为BeanFactory的功能没有其他的多。

如何添加注解的功能呢?

可以使用以下代码,给BeanFactory添加一些后置处理器,也就是一些新的功能:

AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

这样还不够,后置处理器功能还没生效呢。但是可以在console中看出来,已经有一些后置处理器被加了进来:

config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory

接下来就是让它们执行其相应功能的逻辑,遍历beanFactory中的所有bean,然后获取类型是BeanFactoryPostProcessor的,让它们执行后置处理器:

beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
    beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});

可以看出打印结果变成了下面这样:

config
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
bean1
bean2

也就是@Bean注解声明的对象也被加入到了beanFactory容器中了。

下面试着获取一下Bean1这个对象的Bean2参数,看看@Autowired注解是否把Bean2给引入进来了。

System.out.println(beanFactory.getBean(Bean1.class).getBean2());

结果发现并没有:

[main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
null

也就是说上面的后处理器并没有把@Autowired和@Resource等注解的功能加进去,上面的那些后置处理器是BeanFactory级别的,还有一些是Bean级别的。(通过上面的getBeansOfType()可以选择是哪种类型的后置处理器),这些是针对Bean生命周期各个阶段的扩展。

那么怎么扩展BeanPostProcessor呢?

public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    //设置bean的定义,就如同xml文件设置bean一样,现在还不是创建bean的对象
    AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
        .setScope("singleton").getBeanDefinition();
    //使用beanFactory创建bean
    beanFactory.registerBeanDefinition("config",beanDefinition);

    //给BeanFactory添加一些后置处理器
    AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

    beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
        beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
    });

    System.out.println("----------");


    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }

    beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
        beanFactory.addBeanPostProcessor(beanPostProcessor);
    });

    System.out.println(beanFactory.getBean(Bean1.class).getBean2());

}

这回看结果可以发现:

[main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
[main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean2 - 构造 Bean2()
com.oliver.spring_source.a02.TestBeanFactory$Bean2@35083305

查看各个bean是否为懒加载?

在getBean2()前打印一个分割行,看看构造方法是否是在分割行后面才执行?发现确实是,说明是懒加载。

------------------------------
16:06:19.685 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
16:06:19.687 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'config'
16:06:19.701 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
16:06:19.711 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
16:06:19.711 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean2 - 构造 Bean2()
com.oliver.spring_source.a02.TestBeanFactory$Bean2@35083305

创建对象的时机可以提前吗?

可以的,使用beanFactory.preInstantiateSingletons();来提前加载:

16:07:58.735 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean1'
16:07:58.750 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean1 - 构造 Bean1()
16:07:58.763 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean2'
16:07:58.764 [main] DEBUG com.oliver.spring_source.a02.TestBeanFactory$Bean2 - 构造 Bean2()
------------------------------
com.oliver.spring_source.a02.TestBeanFactory$Bean2@20d3d15a

2、后置处理器的排序

可以通过查看源码,看看这些注解是怎么加载进来的,看AnnotationConfigUtils类:

if (!registry.containsBeanDefinition(AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    RootBeanDefinition def = new RootBeanDefinition(AutowiredAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, AUTOWIRED_ANNOTATION_PROCESSOR_BEAN_NAME));
}

// Check for JSR-250 support, and if present add the CommonAnnotationBeanPostProcessor.
if (jsr250Present && !registry.containsBeanDefinition(COMMON_ANNOTATION_PROCESSOR_BEAN_NAME)) {
    RootBeanDefinition def = new RootBeanDefinition(CommonAnnotationBeanPostProcessor.class);
    def.setSource(source);
    beanDefs.add(registerPostProcessor(registry, def, COMMON_ANNOTATION_PROCESSOR_BEAN_NAME));
}

Autowired就是@Autowired注解,Common就是@Resource注解。

如果在某个对象上既加了@Autowired,又加了@Resource注解,那么哪个先生效呢?

先重新设置一下源代码:

public class TestBeanFactory {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        //设置bean的定义,就如同xml文件设置bean一样,现在还不是创建bean的对象
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(Config.class)
            .setScope("singleton").getBeanDefinition();
        //使用beanFactory创建bean
        beanFactory.registerBeanDefinition("config",beanDefinition);

        //给BeanFactory添加一些后置处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });
        
        System.out.println(beanFactory.getBean(Bean1.class).getInter());
    }

    @Configuration
    static class Config{
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2() {
            return new Bean2();
        }

        @Bean
        public Bean3 bean3(){
            return new Bean3();
        }

        @Bean
        public Bean4 bean4(){
            return new Bean4();
        }
    }

    interface Inter{

    }

    static class Bean3 implements Inter{

    }

    static class Bean4 implements Inter{

    }

    static class Bean1{
        private static final Logger log = LoggerFactory.getLogger(Bean1.class);

        public Bean1(){
            log.debug("构造 Bean1()");
        }

        @Autowired
        private Bean2 bean2;

        public Bean2 getBean2(){
            return bean2;
        }

        private Inter inter;

        public Inter getInter(){
            return inter;
        }
    }

    static class Bean2 {
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);

        public Bean2() {
            log.debug("构造 Bean2()");
        }
    }
}

这样还是按照原来的方式,把Bean1类的Inter属性加上@Autowired注解。然后还是获取bean1,发现报错:

Caused by: org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.oliver.spring_source.a02.TestBeanFactory$Inter' available: expected single matching bean but found 2: bean3,bean4

也就是说@Autowired发现了两个Inter类型的bean对象,不知道应该放哪个。可以把Bean1的Inter参数名设置为bean3,这样在参数类型发现多个的时候可以按照对象名注入。

@Autowired
private Inter bean3;

public Inter getInter(){
    return bean3;
}

也可以使用@Qualifier("bean3")

再试试@Resource注解,把名称还改成inter。还是报同样的错。

但是可以设置bean的名字,根据这个名字去找,而不是参数名找,下面这个例子找到的是Bean3的对象,而不是Bean4的对象。

@Resource(name = "bean3")
private Inter bean4;

public Inter getInter(){
    return bean4;
}

这个时候加两个注解怎么办?哪个生效?

@Autowired
@Resource(name = "bean3")
private Inter bean4;

public Inter getInter(){
    return bean4;
}

如果按照上面这个,最终如果是bean4被注入,说明@Autowired被注入,如果是bean3被注入说明@Resource起了作用。最后发现是bean4起了作用。

16:34:46.922 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'bean4'

其实是后处理器哪个先添加进beanFactory容器,哪个先生效,可以打印看一下:

beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor -> {
    System.out.println(beanPostProcessor);
    beanFactory.addBeanPostProcessor(beanPostProcessor);
});

打印结果如下:

[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
[main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@3f200884
org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@4d339552

可以看出是Autowired先添加进来。

那么可以改顺序吗?

当然可以,可以通过比较器对象来设置。

beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
    .sorted(beanFactory.getDependencyComparator())
    .forEach(beanPostProcessor -> {
        System.out.println(beanPostProcessor);
        beanFactory.addBeanPostProcessor(beanPostProcessor);
    });

变成上面这样可以通过结果看出,加载顺序确实变了:

org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@4d339552
org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@f0f2775

查看一下源码

public static Set<BeanDefinitionHolder> registerAnnotationConfigProcessors(BeanDefinitionRegistry registry, @Nullable Object source) {
    DefaultListableBeanFactory beanFactory = unwrapDefaultListableBeanFactory(registry);
    if (beanFactory != null) {
        if (!(beanFactory.getDependencyComparator() instanceof AnnotationAwareOrderComparator)) {
            beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
        }

        if (!(beanFactory.getAutowireCandidateResolver() instanceof ContextAnnotationAutowireCandidateResolver)) {
            beanFactory.setAutowireCandidateResolver(new ContextAnnotationAutowireCandidateResolver());
        }
    }

registerAnnotationConfigProcessors()中的setDependencyComparator设置了比较器。

顺序也可以看一下:AutowiredAnnotationBeanPostProcessor类中顺序,使用setOrder()设置:

private int order = Ordered.LOWEST_PRECEDENCE - 2;

public void setOrder(int order) {
    this.order = order;
}

@Override
public int getOrder() {
    return this.order;
}

而CommonAnnotationBeanPostProcessor类是这样设置的:

public CommonAnnotationBeanPostProcessor() {
    this.setOrder(Ordered.LOWEST.PRECEDENCE - 3);
    this.setInitAnnotationType(PostConstruct.class);
    this.setDestroyAnnotationType(PreDestroy.class);
    this.ignoreResourceType("javax.xml.ws.WebServiceContext");
}

因为Common这个注解 - 3,而Autowired注解 - 2,也就是Common注解优先级更高。

3、ApplicationContext的实现

ApplicationContext比BeanFactory多了很多功能,首先可以使用不同的方式创建容器,获取bean实例。

先看最基础的代码:

public class A02 {
    private static final Logger log = LoggerFactory.getLogger(A02.class);

    public static void main(String[] args) {
        testClassPathXmlApplicationContext();
        testFileSystemXmlApplicationContext();
        testAnnotationConfigApplicationContext();
        testAnnotationConfigServletWebServerApplicationContext();
    }

    private static void testClassPathXmlApplicationContext() {
    }

    private static void testFileSystemXmlApplicationContext(){
    }

    private static void testAnnotationConfigApplicationContext() {
    }

    private static void testAnnotationConfigServletWebServerApplicationContext() {
    }

    @Configuration
    static class WebConfig {
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){
            return new TomcatServletWebServerFactory();
        }
        @Bean
        public DispatcherServlet dispatcherServlet() {
            return new DispatcherServlet();
        }
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet) {
            return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
        }
        @Bean("/hello")
        public Controller controller1() {
            return (request, response) -> {
                response.getWriter().print("hello");
                return null;
            };
        }
    }

    @Configuration
    static class Config {
        @Bean
        public Bean1 bean1() {
            return new Bean1();
        }

        @Bean
        public Bean2 bean2(Bean1 bean1) {
            Bean2 bean2 = new Bean2();
            bean2.setBean1(bean1);
            return bean2;
        }
    }

    static class Bean1 {
    }

    static class Bean2 {

        private Bean1 bean1;

        public void setBean1(Bean1 bean1) {
            this.bean1 = bean1;
        }

        public Bean1 getBean1() {
            return bean1;
        }
    }
}
  • ClassPathXmlApplicationContext的代码
private static void testClassPathXmlApplicationContext() {
    ClassPathXmlApplicationContext context =
        new ClassPathXmlApplicationContext("a02.xml");
    for (String name : context.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    System.out.println(context.getBean(Bean2.class).getBean1());
}
  • FileSystemXmlApplicationContext的代码
private static void testFileSystemXmlApplicationContext(){
    FileSystemXmlApplicationContext context =
        new FileSystemXmlApplicationContext("src/main/resources/a02.xml");
    for (String name : context.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    System.out.println(context.getBean(Bean2.class).getBean1());
}
  • AnnotationConfigApplicationContext的代码
private static void testAnnotationConfigApplicationContext() {
    AnnotationConfigApplicationContext context =
            new AnnotationConfigApplicationContext(Config.class);
    for (String name : context.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    System.out.println(context.getBean(Bean2.class).getBean1());
}

BeanFactory又是怎样读取文件的呢?

private static void testBeanFactory(){
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    System.out.println("读取之前...");
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }
    XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
    reader.loadBeanDefinitions("a02.xml");
    System.out.println("读取之后...");
    for (String name : beanFactory.getBeanDefinitionNames()) {
        System.out.println(name);
    }
}

通过XmlBeanDefinitionReader读取资源文件,然后使用reader.loadBeanDefinitions("a02.xml")加载bean定义。