• 一、容器接口
    1、BeanFactory与ApplicationContext
    2、BeanFactory接口
    ① DefaultListableBeanFactory类
    3、ApplicationContext接口
    ① 实现MessageSource接口
    ② 实现ResourcePatternResolver接口
    ③ 实现EnvironmentCapable接口
    ④ 实现ApplicationEventPublisher接口

  • 二、容器实现
    1、BeanFactory实现
    ① DefaultListableBeanFactory类
    ② 注册各类后置处理器
    ③ beanFactory后置处理器
    ④ bean后置处理器
    ⑤ preInstantiateSingletons初始化
    补充:AnnotationConfigUtils类
    2、ApplicationContext实现
    ① ClassPathXmlApplicationContext类
    ② FileSystemXmlApplicationContext类
    补充:XmlBeanDefinitionReader类
    ③ AnnotationConfigApplicationContext类
    补充:<context:annotation-config/>
    ④ AnnotationConfigServletWebServerApplicationContext类

一、容器接口

0、基础准备

添加最基础的Spring Boot依赖,如下:


<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

1、BeanFactory与ApplicationContext

  • ① Spring Boot启动类

SpringApplication.run(A01.class, args);的返回值为ConfigurableApplicationContext对象,如下:


@SpringBootApplication
public class SpringOriginDemoApplication {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(SpringOriginDemoApplication.class, args);
    }

}

【Spring原理分析-BeanFactory与ApplicationContext】_xml


BeanFactory是:

Ⅰ ApplicationContext 的父接口

Ⅱ 是 Spring 的核心容器, 主要的 ApplicationContext 实现都【组合】了它的功能。

2、BeanFactory接口

BeanFactory接口,最基础的待实现方法是getBean();方法。

另外,像控制反转基本的依赖注入、直至 Bean 的生命周期的各种功能,都是依赖于BeanFactory接口实现的。


  • ① DefaultListableBeanFactory类

是Spring项目中BeanFactory功能最完善的实现类,关系图如下:

【Spring原理分析-BeanFactory与ApplicationContext】_System_02


  • ② 通过反射获取singletonObjects成员变量案例

DefaultSingletonBeanRegistry类,如下:

【Spring原理分析-BeanFactory与ApplicationContext】_System_03


通过反射获取beanFactory中的singletonObjects,如下:


// 通过反射获取 Field 对象singletonObjects
Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
// 暴力反射
singletonObjects.setAccessible(true);
// 获取beanFactory中的singletonObjects,并遍历
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
Map<String, Object> map = (Map<String, Object>) singletonObjects.get(beanFactory);
map.entrySet()
        .stream().filter(e -> e.getKey().startsWith("component"))
        .forEach(e -> System.out.println(e.getKey() + " = " + e.getValue()));

【Spring原理分析-BeanFactory与ApplicationContext】_System_04


3、ApplicationContext接口

  • ① 实现MessageSource接口

Ⅰ 在/resources目录下编写配置文件

语言代码表:Language Code Table (lingoes.cn),此处设置配置文件地区可以省略不写,一般写成zh、ja、en就可以(推荐)。

【Spring原理分析-BeanFactory与ApplicationContext】_spring_05


【Spring原理分析-BeanFactory与ApplicationContext】_System_06


Ⅱ 编写测试代码


System.out.println(context.getMessage("hi", null, Locale.ENGLISH));
System.out.println(context.getMessage("hi", null, Locale.CHINA));
System.out.println(context.getMessage("hi", null, Locale.JAPAN));

【Spring原理分析-BeanFactory与ApplicationContext】_spring_07


  • ② 实现ResourcePatternResolver接口

Ⅰ 获取类路径下指定资源classpath:


Resource[] resources = context.getResources("classpath:application.properties");
for (Resource resource : resources) {
    System.out.println(resource); // 输出 class path resource [application.properties]
}

Ⅱ 获取jar包其他资源classpath*:


Resource[] resources = context.getResources("classpath*:META-INF/spring.factories");

【Spring原理分析-BeanFactory与ApplicationContext】_System_08


  • ③ 实现EnvironmentCapable接口

Ⅰ 获取变量键值

该方法可以获取配置文件(如:application.properties)内的键值,也可以拿到环境变量的键值,如下:


System.out.println(context.getEnvironment().getProperty("java_home")); // 输出 C:\Program Files\Java\jdk1.8.0_311
System.out.println(context.getEnvironment().getProperty("server.port")); // 输出 8080
  • ④ 实现ApplicationEventPublisher接口

Ⅰ 编写事件类(实现ApplicationEvent )


public class UserRegisterEvent extends ApplicationEvent {
    public UserRegisterEvent(Object source) {
        super(source);
    }
}

Ⅱ 编写事件发布类


@Component
public class Component1 {
    private static final Logger log = LoggerFactory.getLogger(Component1.class);
    @Autowired
    private ApplicationEventPublisher context;
    public void register() {
        log.debug("用户注册");
        context.publishEvent(new UserRegisteredEvent(this));
    }
}

Ⅲ 编写事件监听类


@Component
public class Component2 {
    private static final Logger log = LoggerFactory.getLogger(Component2.class);
    @EventListener
    public void aaa(UserRegisteredEvent event) {
        log.debug("{}", event);
        log.debug("发送短信");
    }
}

此处我们是debug输出的,在application.properties中自定义一下日志输出:logging.level.com.stone=debug
Ⅳ 测试


context.getBean(Component1.class).register();

【Spring原理分析-BeanFactory与ApplicationContext】_System_09


实际使用场景中的作用:解耦合。


  • ⑤ 总结

ApplicationContext接口拓展功能:

Ⅰ 国际化支持(MessageSource);

Ⅱ 通配符获取资源(ResourcePatternResolver);

Ⅲ 获取环境变量(EnvironmentCapable);

Ⅳ 发送事件(ApplicationEventPublisher)。


二、容器实现

1、BeanFactory实现

  • ① DefaultListableBeanFactory类

Ⅰ 准备测试类


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

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

    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(Bean1.class);

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

Ⅱ 编写main方法


public static void main(String[] args) {
    DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
    // Bean 的定义信息 class、scope、initMethod、destroyMethod 等
    AbstractBeanDefinition bd
            = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
    beanFactory.registerBeanDefinition("config", bd);

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

可以看到我们@Configuration注解的配置类并没有被扫描,所以@Bean相关的Bean没有输出,如下:

【Spring原理分析-BeanFactory与ApplicationContext】_System_10


至此,我们可以看出基础的DefaultListableBeanFactory类并不直接支持此类注解扫描。

  • ② 注册各类后置处理器


// 给 beanFactory 添加常用的后置处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);

【Spring原理分析-BeanFactory与ApplicationContext】_System_11


可以看到,此时bean1和bean2仍然没有被扫描放入容器。以为还没有调用beanFactory的后置处理器。添加的后置处理器:
a、ConfigurationAnnotationProcessor;(BeanFactory后置处理器)
b、AutowiredAnnotationProcessor;
c、CommonAnnotationProcessor;
d、EventListenerProcessor;
e、EventListenerFactory。

  • ③ beanFactory后置处理器

获取beanFactory的后置处理器,并调用,如下:


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

【Spring原理分析-BeanFactory与ApplicationContext】_xml_12


至此,我们知道BeanFactoryPostProcessor是对BeanDifinition的一些补充。另外,我们尝试获取一下bean1、bean2,如下:


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

【Spring原理分析-BeanFactory与ApplicationContext】_xml_13


Creating shared instance of singleton bean 'bean1'可以看到Bean对象在我们获取的时候才去创建,并且bean1对象内部并没有注入构造好的bean2。此时我们就需要用到Bean后置处理器。

  • ④ bean后置处理器

其作用是对bean生命周期的各个阶段提供拓展,例如:@Autowired...


beanFactory.getBeansOfType(BeanPostProcessor.class).values()
        .forEach(beanFactory::addBeanPostProcessor);

【Spring原理分析-BeanFactory与ApplicationContext】_System_14


此时可以看到,装配bean1时需要bean2,容器就去沟通bean2完成注入。但是,实际使用Spring的时候,其实bean都是在我们使用前已经创建好的,我们还需处理。

  • ⑤ preInstantiateSingletons初始化


beanFactory.preInstantiateSingletons();
System.out.println("==== before we get these beans ====");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());

【Spring原理分析-BeanFactory与ApplicationContext】_spring_15


  • ⑥ 总结

Ⅰ 不会主动调用 BeanFactory 后处理器;

Ⅱ 不会主动添加 Bean 后处理器;

Ⅲ 不会主动初始化单例;

Ⅳ 不会解析beanFactory 还不会解析 ${ } 与 #{ }(如:@Value注解内使用)。

补充:AnnotationConfigUtils类

  • ① 基础准备

Ⅰ Config类添加:


@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{}

Ⅲ Bean1内注入:

a、同一接口不同实现,@Autowired按照字段名注入,如下:


@Autowired
private Inter bean3;

【Spring原理分析-BeanFactory与ApplicationContext】_System_16


b、同一接口不同实现,@Resource(name = "bean4")指定注入,如下:

【Spring原理分析-BeanFactory与ApplicationContext】_System_17


c、同时开启,按照@Autowired注入,如下:

【Spring原理分析-BeanFactory与ApplicationContext】_xml_18


d、通过比较器修改注入,如下:

Ⅰ 修改前


beanFactory.getBeansOfType(BeanPostProcessor.class).values()
        .forEach(beanPostProcessor -> {
            System.out.println("[!!!LOOK HERE!!!] Added BeanPostProcessor is ---> " + beanPostProcessor);
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });

【Spring原理分析-BeanFactory与ApplicationContext】_xml_19


Ⅱ 修改后

添加了.stream().sorted(beanFactory.getDependencyComparator())


beanFactory.getBeansOfType(BeanPostProcessor.class).values()
        .stream().sorted(beanFactory.getDependencyComparator())
        .forEach(beanPostProcessor -> {
            System.out.println("[!!!LOOK HERE!!!] Added BeanPostProcessor is ---> " + beanPostProcessor);
            beanFactory.addBeanPostProcessor(beanPostProcessor);
        });

【Spring原理分析-BeanFactory与ApplicationContext】_xml_20


2、ApplicationContext实现

  • ① ClassPathXmlApplicationContext类

Ⅰ 编写内部类


public class Demo02 {
    static class Bean1{}

    static class Bean2{
        private Bean1 bean1;

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

        public Bean1 getBean1() {
            return bean1;
        }
    }
}

Ⅱ 编写b01.xml配置文件


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
       http://www.springframework.org/schema/beans/spring-beans.xsd">
        <!--配置bean-->
        <bean name="bean1" class="com.stone.demo02.Demo02.Bean1"/>
        <bean name="bean2" class="com.stone.demo02.Demo02.Bean2">
            <property name="bean1" ref="bean1"/>
        </bean>
</beans>

Ⅲ 编写测试方法


public static void testClassPathXmlApplicationContext(){
    ClassPathXmlApplicationContext context = 
            new ClassPathXmlApplicationContext("b01.xml");
    for (String definitionName : context.getBeanDefinitionNames()) {
        System.out.println(definitionName);
    }
    System.out.println(context.getBean(Bean2.class).getBean1());
}

【Spring原理分析-BeanFactory与ApplicationContext】_spring_21


  • ② FileSystemXmlApplicationContext类


public static void testFileSystemXmlApplicationContext(){
    FileSystemXmlApplicationContext context
            // 绝对路径 D:\JavaStudy\Level1\spring_origin_demo\src\main\resources\b01.xml
            // 相对路径 src/main/resources/b01.xml
            = new FileSystemXmlApplicationContext("src/main/resources/b01.xml");
    for (String definitionName : context.getBeanDefinitionNames()) {
        System.out.println(definitionName);
    }
    System.out.println(context.getBean(Bean2.class).getBean1());
}

【Spring原理分析-BeanFactory与ApplicationContext】_System_22


补充:XmlBeanDefinitionReader类


DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
System.out.println("[!!!LOOK HERE!!!] Before reader works :");
for (String definitionName : beanFactory.getBeanDefinitionNames()) {
    System.out.println(definitionName);
}
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
//        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
reader.loadBeanDefinitions(new FileSystemResource("src/main/resources/b01.xml"));
System.out.println("[!!!LOOK HERE!!!] After reader worked :");
for (String definitionName : beanFactory.getBeanDefinitionNames()) {
    System.out.println(definitionName);
}

【Spring原理分析-BeanFactory与ApplicationContext】_xml_23


  • ③ AnnotationConfigApplicationContext类

Ⅰ 编写Config类


@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;
    }
}

Ⅱ 编写测试方法


public static void testAnnotationConfigApplicationContext(){
    AnnotationConfigApplicationContext context
            = new AnnotationConfigApplicationContext(Config.class);
    for (String definitionName : context.getBeanDefinitionNames()) {
        System.out.println(definitionName);
    }
    System.out.println(context.getBean(Bean2.class).getBean1());
}

【Spring原理分析-BeanFactory与ApplicationContext】_xml_24


补充:<context:annotation-config/>

可以看到AnnotationConfigApplicationContext类自动添加了后置处理器,其作用类似于配置<context:annotation-config/>。


<!--添加注解驱动-->
<context:annotation-config/>

【Spring原理分析-BeanFactory与ApplicationContext】_xml_25


【Spring原理分析-BeanFactory与ApplicationContext】_System_26


  • ④ AnnotationConfigServletWebServerApplicationContext类

Ⅰ 编写WebConfig类


@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 controller(){
        // org.springframework.web.servlet.mvc.Controller
        return (request, response) -> {
            response.getWriter().println("Hello, context!");
            return null;
        };
    }
}

Ⅱ 编写测试方法


public static void testAnnotationConfigServletWebServerApplicationContext(){
    AnnotationConfigServletWebServerApplicationContext context
            = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    for (String definitionName : context.getBeanDefinitionNames()) {
        System.out.println(definitionName);
    }
}

【Spring原理分析-BeanFactory与ApplicationContext】_System_27


三、结尾

以上即为Spring原理分析-容器&Bean(一)的全部内容