ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

04 Spring中BeanFactory与ApplicationContext接口及实现类特点

2022-06-02 02:35:31  阅读:188  来源: 互联网

标签:ApplicationContext 04 BeanFactory springframework bean context import org class


1 接口

1-1 基本接口说明

Springboot启动源码

package com.village.dog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

@SpringBootApplication
public class Application {
    private static final Logger logging = LoggerFactory.getLogger(Application.class);
    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);
    }
}

图1:Diagram for BeanFactory

BeanFactory接口:用于访问Spring容器的根接口

简介:实现BeanFactory接口的Object容纳多个bean definition,
每个bean definition通过唯一的字符串名称进行区别。

ApplicationContext接口:为应用提供配置的核心接口

接口支持功能 所对应的父接口
用于访问应用组件的工厂方法 org.springframework.beans.factory.ListableBeanFactory
加载文件资源的能力 org.springframework.core.io.ResourceLoader
向已注册的监听对象发布事件的能力 ApplicationEventPublisher
解析消息,支持国际化 MessageSource

说明:类图中可看到ApplicationContext接口继承BeanFactory接口,此外还继承了其他很多接口。

Java中接口可通过extends关键字继承一个或多个接口
官方文档对上述接口的说明:
BeanFactory:

1-2 BeanFactory实现类

图2:Diagram for DefaultLisableBeanFactory

DefaultLisableBeanFactory:spring中的默认接口实现类

  • 继承父类:DefaultSingletonBeanRegister:用于共享bean实例的通用注册类,其允许能够通过bean name获得单例对象。
// 说明:DefaultSingletonBeanRegister中定义了存放所有单例对象的concurrentHashMap
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
	/** Cache of singleton objects: bean name to bean instance. */
	private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);

需求:打印 ”存放单例对象的map“中特定的单例对象

package com.village.dog;
import org.springframework.stereotype.Component;
// springboot默认是单例对象
@Component
public class Component1 {
}
package com.village.dog;
import org.springframework.stereotype.Component;
@Component
public class Component2 {
}
package com.village.dog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.DefaultSingletonBeanRegistry;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

import java.lang.reflect.Field;
import java.util.Map;

@SpringBootApplication
public class Application {
    private static final Logger logging = LoggerFactory.getLogger(Application.class);
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException {
        ConfigurableApplicationContext context = SpringApplication.run(Application.class,args);

        /*
            需求:通过反射的方式获取存储单例对象的concurrentMap,打印处Map中我们自己注入的
                  两个单例对象Component1和Component2.
        */
        Field singletonObjects = DefaultSingletonBeanRegistry.class.getDeclaredField("singletonObjects");
        singletonObjects.setAccessible(true);
        // 获取现有的BeanFactory实现类
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        // 获取该实现类的singletonObjects属性,也就是存放单例对象的map
        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())
        );
    }
}

运行结果

component1=com.village.dog.Component1@601cbd8c
component2=com.village.dog.Component2@7180e701

1-3 ApplicationContext接口特点

图2中ApplicationContext的父接口如下

ListableBeanFactory和HierarchicalBeanFactory:BeanFactory的扩展
MessageSource: 用于解析消息的策略接口,支持消息参数化和国际化(国际化能力)
EnvironmentCapable:环境信息,包括yaml,xml等类型文件中的配置信息
ApplicationEventPublisher:事件对象发布能力
ResourcePatternResolver:基于通配符匹配资源

说明:可以发现Application除了获取Bean实例对象这一基本的功能外,还支持国际化,环境信息获取、
基于通配符匹配资源和发布事件对象
这四种能力。

四种扩展功能测试代码

package com.village.dog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.event.EventListener;
import org.springframework.stereotype.Component;
// springboot默认是单例对象
@Component
public class Component1 {
    private static final Logger log = LoggerFactory.getLogger(Component1.class);

    /*
       通过事件分发器,可以实现业务上解耦:
       比如用户注册,后续操作可能有短信验证码,邮件验证码
       这个时候模块的功能的协同可以通过事件发布框架进行接口
     */
    @EventListener
    public void testMonitor(UserRegisterEvent event){
        log.info("收到发送的消息{}",event);
    }
}
package com.village.dog;
import org.springframework.context.ApplicationEvent;
public class UserRegisterEvent extends ApplicationEvent {
    public UserRegisterEvent(Object source){
        super(source);
    }
}
package com.village.dog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.util.Locale;

@SpringBootApplication
public class Application_Extension {
    private static final Logger logging = LoggerFactory.getLogger(Application_Extension.class);
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IOException {
        ConfigurableApplicationContext context = SpringApplication.run(Application_Extension.class,args);
        /*
           1) ApplicationContext国际化功能:
           ========该继承于父接口MessageSource=====
           getMessage方法:同一key获取不同语言的value,从而实现国际化
           实际开发中,语言可以从浏览器的请求头获取
           注意:配置文件内容的编码方式需要设置的方式一致,IDEA中可以在setting中设置properties文件的编码方式为UTF8
         */
        System.out.println("1 国际化功能测试");
        System.out.println(context.getMessage("hi",null, Locale.CHINA));
        System.out.println(context.getMessage("hi",null,Locale.ENGLISH));
        System.out.println(context.getMessage("hi",null, Locale.JAPANESE));
        System.out.println();
        /*
           2) ApplicationContext:获取资源文件
           ========继承于于父接口MessageSource=====
         */
        System.out.println("2 获取资源测试");
        Resource[] resources = context.getResources("classpath:application.properties");
        for(Resource resource:resources){
            System.out.println(resource);
        }
        /*采用通配符获取jar包中名称为spring.factories的文件路径
          spring.factories的作用:https://zhuanlan.zhihu.com/p/444331676
         */
        Resource[] re = context.getResources("classpath*:META-INF/spring.factories");
        for(Resource resource:re){
            System.out.println(resource);
        }
        System.out.println();

        /*
            3) applicationContext的环境信息获取能力
            =============继承于父接口EnvironmentCapable====
         */
        // 配置信息获取:通过application获取windows系统环境变量Java_Home以及application.properties中的server.port属性
        System.out.println("3 环境信息获取测试");
        System.out.println(context.getEnvironment().getProperty("Java_Home"));
        System.out.println(context.getEnvironment().getProperty("server.port"));
        System.out.println();

        /*
           4) applicationContext的事件发布能力
           ==============继承于父接口ApplicationEventPublisher===
         */
        System.out.println("4 事件对象发布测试");
        context.publishEvent(new UserRegisterEvent(context));
    }
}

运行结果

1 国际化功能测试
你好
Hello
こんにちは

2 获取资源测试
class path resource [application.properties]
URL [jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot/2.5.5/spring-boot-2.5.5.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot-autoconfigure/2.5.5/spring-boot-autoconfigure-2.5.5.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/spring-beans/5.3.10/spring-beans-5.3.10.jar!/META-INF/spring.factories]
URL [jar:file:/C:/Users/Administrator/.m2/repository/org/springframework/boot/spring-boot-test/2.5.5/spring-boot-test-2.5.5.jar!/META-INF/spring.factories]

3 环境信息获取测试
C:\Program Files\Java\jdk1.8.0_131
9006

4 事件对象发布测试
[2022-05-17 16:03:06] [INFO ] -- 收到发送的消息com.village.dog.UserRegisterEvent[source=org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@67080771

2 实现类

2-1 BeanFactory实现类特点

特点1:底层类,相较于Application不支持以下功能
    不会主动调用BeanFactory的后处理器
    不会主动添加Bean后处理器(解析@Autowired @Resource注入依赖)
    不会主动初始化单例
    不会解析${}和#{}(EL表达式)
特点2:Bean的后置处理器支持排序功能

BeanFactory实现类特点展示代码

package com.village.dog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;


public class TestBeanFactory {
    private static void printBeanDefinitionsNames(DefaultListableBeanFactory beanFactory){
        for(String name:beanFactory.getBeanDefinitionNames()){
            System.out.println(name);
        }
        System.out.println();
    }

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        /*
           容器创建实例对象前必须存储对象的beanDefinition
           beanDefinition包含class、scope、初始化、销毁信息
         */
        AbstractBeanDefinition beanDefinition =
        BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config",beanDefinition);

        /*
           打印容器类中BeanDefinition的名称,从打印结果可以发现
           容器类并没有对Bean的内容进行进一步解析。
         */
        System.out.println("step1:当前容器所包含的BeanDefinition");
        printBeanDefinitionsNames(beanFactory);

        // 为容器添加处理器
        System.out.println("step2:容器添加处理器后,所包含的BeanDefinition");
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        printBeanDefinitionsNames(beanFactory);

        System.out.println("step3:执行BeanFactoryPostProcessor逻辑后,添加的BeanDefinition,创建的实例对象和");
        // 执行BeanFactoryPostProcessor的逻辑
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor ->{
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        printBeanDefinitionsNames(beanFactory);

        // 为null,说明此时@Autowired的,如果在执行BeanPostProcessor前获取bean,那么后续即便
        // 调用BeanPostProcessor也无法注入依赖
        //System.out.println(beanFactory.getBean(Bean1.class).getBean2());
        // 执行BeanPostProcessor的逻辑,将依赖注入到容器的bean中,针对bean的生命周期的各个阶段提供扩展
        // 例如@Autowired或@Resource
        System.out.println("step4:执行BeanPostProcessor,创建的实例对象");
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
        // DefaultListableBeanFactory默认是延迟创建单例,可以通过preInstantiateSingletons提前创建
        beanFactory.preInstantiateSingletons();
        System.out.println("=============================");
        System.out.println(beanFactory.getBean(Bean1.class).getBean2());

        /*
           总结:BeanFactory的特点:
                 1.不会主动调用BeanFactory的后处理器
                 2.不会主动添加Bean后处理器
                 3.不会主动初始化单例
                 4.不会解析EL表达式
         */
   }

    @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(Bean2.class);
        public Bean2(){
            log.debug("构造Bean2()");
        }
    }
}

程序输出结果

step1:当前容器所包含的BeanDefinition
config

step2:容器添加处理器后,所包含的BeanDefinition
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

step3:执行BeanFactoryPostProcessor逻辑后,添加的BeanDefinition,创建的实例对象和
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
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

step4:执行BeanPostProcessor,创建的实例对象
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'config'
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'bean1'
[2022-05-19 20:43:30] [DEBUG] -- 构造Bean1()
[2022-05-19 20:43:30] [DEBUG] -- Creating shared instance of singleton bean 'bean2'
[2022-05-19 20:43:30] [DEBUG] -- 构造Bean2()
=============================
com.village.dog.TestBeanFactory$Bean2@61862a7f


实例程序说明

DefaultListableBeanFactory()是BeanFactory接口实现,这个类也就是
产生Bean的工厂,该工厂能够创建bean的实例对象供外部程序使用。为创建
Bean的实例对象,该工厂需要解析每个bean的class对象,从而为每个bean生成
beanDefinition存放在工厂中(BeanDefinition是对bean实例的描述,包括属性值、构造参数值等)。

显然"如何从Bean得到BeanDefinition"对于BeanFactory非常重要,只要我们保证能够正确解析Bean Class获取BeanDefinition实例对象,那么就能够保证我们能够正确的创建想要的bean。

实际开发中,我们可以通过注解的方式将我们定义的Bean放入的容器中,具体的工作实际上是由Spring中的BeanFactoryPostProcessor去解析Bean生成BeanDefinition,通过BeanPostProcessor为bean实例对象注入依赖。

  • BeanFactoryPostProcessor: Factory hook that allows for custom modification of an application context's bean definitions, adapting the bean property values of the context's underlying bean factory.(工厂钩子程序用于自定义的应用上下文BeanDefinition修改,
    调整上下文的底层bean工厂的bean属性值,只针对beanDefinition)

  • BeanPostProcessor:Factory hook that allows for custom modification of new bean instances
    for example, checking for marker interfaces or wrapping beans with proxies.(bean的解析,有的处理器处理@Autowired注解,有的处理器处理@Resource注解)

设计思想:在程序的固定固定位置通过hook程序的定义修改实现灵活的功能,是开闭原则的一种体现

Bean后处理器的排序
package com.village.dog;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
import org.springframework.context.annotation.AnnotationConfigUtils;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import javax.annotation.Resource;


public class TestBeanFactory {

    public static void main(String[] args) {
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        AbstractBeanDefinition beanDefinition =
        BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
        beanFactory.registerBeanDefinition("config",beanDefinition);
        // 为容器添加处理器
        AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
        // 执行BeanFactoryPostProcessor的逻辑
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class);
        beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor ->{
            beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
        });
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);
//        beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanPostProcessor->{
//            System.out.println("BeanFactory中的BeanPostProcessor:"+beanPostProcessor);
//            beanFactory.addBeanPostProcessor(beanPostProcessor);     // 先添加的processor先执行
//        });

        // 重新定义BeanPostProcessor的顺序
        beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).
                forEach(beanPostProcessor->{
            System.out.println("BeanFactory中的BeanPostProcessor:"+beanPostProcessor);
            beanFactory.addBeanPostProcessor(beanPostProcessor);     // 先添加的processor先执行
        });

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

   }

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

    }

    /*
       Bean1中Inter bean3,Inter接口有两个实现类
       Bean3,Bean4,
       情况1:
       @Autowired
       Inter bean3
       会根据bean3名称匹配到Bean3

       情况2:
        @Resource(name="bean4")
        Inter bean3;
        会根据name匹配到bean4

        上述如果两个注解一起用,都可以匹配,但最终匹配的是Bean3,原因是
        @Autowired对应的BeanPostProcessor在执行顺序上优于
        @Resource对应的BeanPostProcessor
        我们可以通过定义排序规则,让@Resource对应的BeanPostProcessor的执行顺序优于
        @Autowired对应的BeanPostProcessor
    */
    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;}
        @Autowired
        @Resource(name="bean4")
        Inter bean3;
        public Inter getBean3(){return bean3;}
    }

    static class Bean2{
        private static final Logger log = LoggerFactory.getLogger(Bean2.class);
        public Bean2(){
            log.debug("构造Bean2()");
        }
    }

    interface Inter{
        void get();
    }

    static class Bean3 implements Inter{
        @Override
        public void get() {}
    }

    static class Bean4 implements Inter{
        @Override
        public void get() {

        }
    }

}

2-2 ApplicationContext接口的实现类

背景:Spring中ApplicationContext接口有以下四个较为常见的实现类

容器类名 作用
ClassPathXmlApplication 加载classpath路径下的xml进行配置
FileSystemXmlApplicationContext 加载磁盘路径下的xml文件进行配置
AnnotationConfigApplicationContext 基于Java配置类创建
AnnotationConfigServletWebServerApplicationContext 基于Java配置类创建,适用于web环境

四种实现类测试代码

package com.village.dog;

import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.boot.autoconfigure.web.servlet.DispatcherServletRegistrationBean;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.mvc.Controller;

public class TestApplicationContext {
    public static void main(String[] args) {
        System.out.println("测试ClassPathXmlApplicationContext");
        testClassPathXmlApplicationContext();

        /*
        DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
        // ==================ClassPathXmlApplication的内部机制流程=================
        printBeanDefinitionNames(beanFactory);
        XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
        reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
        printBeanDefinitionNames(beanFactory);
        */
        System.out.println("测试AnnotationConfigApplicationContext");
        testAnnotationConfigApplicationContext();

        System.out.println("测试AnnotationConfigServletWebServerApplicationContext");
        testAnnotationConfigServletWebServerApplicationContext();

    }


    /*
            ClassPathXmlApplication:加载classpath路径下的xml进行配置
            FileSystemXmlApplicationContext:加载磁盘路径下的xml文件进行配置
     */
    private static void testClassPathXmlApplicationContext(){
        // FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("xxx.xml");
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("b01.xml");
        printBeanDefinitionNames(context);
        System.out.println(context.getBean(Bean2.class).getBean1());
        System.out.println();

    }




    private static void testAnnotationConfigApplicationContext(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);
        /*
           从输出可以看出:相较于ClassPathXmlApplication容器,该容器中除了配置类中配置的
           Bean1和Bean2,还有Config以及用于解析不同注解的5个工具类,作为bean的后处理器(如下所示):
           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

           如果ClassPathXmlApplication加载的xml文件中包含<context:annotation-config/>,则也能引入上述5个后置处理器

         */
        printBeanDefinitionNames(context);
        System.out.println(context.getBean(Bean2.class).getBean1());
        System.out.println();
    }

    /*
      AnnotationConfigServletWebServerApplicationContext:
                            该容器也是基于Java配置类创建,主要用于web环境
     */
    private static void testAnnotationConfigServletWebServerApplicationContext(){

        // 内嵌Tomcat容器配合DispatchServlet实现简单的web应用
        // 最小系统: web容器,servlet对象,容器注册类,控制类处理请求
        AnnotationConfigServletWebServerApplicationContext  context = new AnnotationConfigServletWebServerApplicationContext (WebConfig.class);
        printBeanDefinitionNames(context);
        System.out.println();
    }

    @Configuration
    static class WebConfig{
        @Bean
        public ServletWebServerFactory servletWebServerFactory(){  // 创建内嵌Tomcat容器
            return new TomcatServletWebServerFactory();
        }

        @Bean
        public DispatcherServlet dispatcherServlet(){              // 创建Servlet对象
            return new DispatcherServlet();
        }

        // 将dispatchServlet注册到Tomcat容器中
        @Bean
        public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){
            return new DispatcherServletRegistrationBean(dispatcherServlet,"/");
        }

        // 这里将/后面的bean名称作为访问路径
        @Bean("/hello")
        public Controller controller1(){
            return (request,response)->{
                    response.getWriter().print("Response Message: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;
        }

    }

    private static void printBeanDefinitionNames(ListableBeanFactory beanFactory){
        System.out.println("==============beanDefinitions==================");
        for(String name:beanFactory.getBeanDefinitionNames()){
            System.out.println(name);
        }
        System.out.println("================================");
    }
}


日志输出

测试ClassPathXmlApplicationContext
[2022-06-01 20:26:57] [DEBUG] -- Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@5afa04c
[2022-06-01 20:26:57] [DEBUG] -- Loaded 2 bean definitions from class path resource [b01.xml]
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'bean1'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'bean2'
==============beanDefinitions==================
bean1
bean2
================================
com.village.dog.TestApplicationContext$Bean1@475e586c

测试AnnotationConfigApplicationContext
[2022-06-01 20:26:57] [DEBUG] -- Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5c1a8622
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'testApplicationContext.Config'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'bean1'
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'bean2'
[2022-06-01 20:26:57] [DEBUG] -- Autowiring by type from bean name 'bean2' via factory method to bean named 'bean1'
==============beanDefinitions==================
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
testApplicationContext.Config
bean1
bean2
================================
com.village.dog.TestApplicationContext$Bean1@21b2e768

测试AnnotationConfigServletWebServerApplicationContext
[2022-06-01 20:26:57] [DEBUG] -- Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@11c9af63
[2022-06-01 20:26:57] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalConfigurationAnnotationProcessor'
[2022-06-01 20:26:58] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerProcessor'
[2022-06-01 20:26:58] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.event.internalEventListenerFactory'
[2022-06-01 20:26:58] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalAutowiredAnnotationProcessor'
[2022-06-01 20:26:58] [DEBUG] -- Creating shared instance of singleton bean 'org.springframework.context.annotation.internalCommonAnnotationProcessor'
[2022-06-01 20:26:58] [DEBUG] -- Unable to locate ThemeSource with name 'themeSource': using default [org.springframework.ui.context.support.ResourceBundleThemeSource@be35cd9]
[2022-06-01 20:26:58] [DEBUG] -- Creating shared instance of singleton bean 'servletWebServerFactory'
[2022-06-01 20:26:58] [DEBUG] -- Creating shared instance of singleton bean 'testApplicationContext.WebConfig'
[2022-06-01 20:27:00] [DEBUG] -- Code archive: C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot\2.5.5\spring-boot-2.5.5.jar
[2022-06-01 20:27:00] [DEBUG] -- Code archive: C:\Users\Administrator\.m2\repository\org\springframework\boot\spring-boot\2.5.5\spring-boot-2.5.5.jar
[2022-06-01 20:27:00] [DEBUG] -- None of the document roots [src/main/webapp, public, static] point to a directory and will be ignored.
[2022-06-01 20:27:00] [INFO ] -- Tomcat initialized with port(s): 8080 (http)
六月 01, 2022 8:27:00 下午 org.apache.coyote.AbstractProtocol init
信息: Initializing ProtocolHandler ["http-nio-8080"]
六月 01, 2022 8:27:00 下午 org.apache.catalina.core.StandardService startInternal
信息: Starting service [Tomcat]
六月 01, 2022 8:27:00 下午 org.apache.catalina.core.StandardEngine startInternal
信息: Starting Servlet engine: [Apache Tomcat/9.0.53]
六月 01, 2022 8:27:00 下午 org.apache.catalina.core.ApplicationContext log
信息: Initializing Spring embedded WebApplicationContext
[2022-06-01 20:27:00] [DEBUG] -- Published root WebApplicationContext as ServletContext attribute with name [org.springframework.web.context.WebApplicationContext.ROOT]
[2022-06-01 20:27:00] [INFO ] -- Root WebApplicationContext: initialization completed in 2448 ms
[2022-06-01 20:27:00] [DEBUG] -- Creating shared instance of singleton bean 'registrationBean'
[2022-06-01 20:27:00] [DEBUG] -- Creating shared instance of singleton bean 'dispatcherServlet'
[2022-06-01 20:27:00] [DEBUG] -- Autowiring by type from bean name 'registrationBean' via factory method to bean named 'dispatcherServlet'
[2022-06-01 20:27:00] [DEBUG] -- Mapping filters: 
[2022-06-01 20:27:00] [DEBUG] -- Mapping servlets: dispatcherServlet urls=[/]
[2022-06-01 20:27:00] [DEBUG] -- Creating shared instance of singleton bean '/hello'
[2022-06-01 20:27:00] [DEBUG] -- Starting beans in phase 2147483646
六月 01, 2022 8:27:00 下午 org.apache.coyote.AbstractProtocol start
信息: Starting ProtocolHandler ["http-nio-8080"]
[2022-06-01 20:27:00] [INFO ] -- Tomcat started on port(s): 8080 (http) with context path ''
[2022-06-01 20:27:00] [DEBUG] -- Successfully started bean 'webServerStartStop'
[2022-06-01 20:27:00] [DEBUG] -- Starting beans in phase 2147483647
[2022-06-01 20:27:00] [DEBUG] -- Successfully started bean 'webServerGracefulShutdown'
==============beanDefinitions==================
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
testApplicationContext.WebConfig
servletWebServerFactory
dispatcherServlet
registrationBean
/hello
================================

总结:四种ApplicationContext接口的实现类包含两种配置容器的方式,一种是基于xml文件,另外一种是通过添加配置注解的配置类。通常我们适用配置类的方式配置容器更多一点。通过打印容器中beanDefinition。可以发现采用配置类的容器类对于@Autowired等注解的解析是通过容器中所添加的后置bean处理器实现的。
此外,web环境下的容器类至少包含 web容器、servlet对象、web容器注册对象。

小结

问题1:BeanFactory与ApplicationContext的作用和关系

1)BeanFactory是spring容器的核心接口,也是ApplicationContext的父接口。
2)ApplicationContext组合BeanFactory的功能,更加确切地ApplicationContext接口的实现类内部
有一个成员变量是BeanFactory接口的实现类,然后通过内部BeanFactory的实现类调用BeanFactory接口方法。
说明:org.springframework.context.support.GenericApplicationContexts是ApplicationContext接口的实现类,其包含成员变量DefaultListableBeanFactory,该变量实现BeanFactory接口。因此Application接口本质上组合了BeanFactory接口。
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	private final DefaultListableBeanFactory beanFactory;
		...
	}

问题2:ApplicationContext在BeanFactory扩展哪些功能?

ApplicationContext除了继承BeanFactory,还继承了其他接口,从而
支持以下四种功能:

1)国际化功能
2)根据统配符加载Resouce的功能
3)获取配置信息(环境变量)的功能
4)发送事件对象的功能

问题3:ApplicationContext的事件解耦功能如何得到支持?

事件解耦本质上是观察者模式的体现,通过消息,实现功能的解耦。
ApplicationContext的父接口ApplicationContext提供了该功能。

Spring 事件驱动模型实现业务解耦
观察者模式与订阅发布模式的区别

问题4:BeanFactory实现类的特点?

属于底层类,相较于Application不支持以下功能

  • 不会主动调用BeanFactory的后处理器
  • 不会主动添加Bean后处理器(解析@Autowired @Resource注入依赖)
  • 不会主动初始化单例
  • 不会解析${}和#{}(EL表达式)
    问题5:ApplicationContext的常见实现和使用方法
    四种ApplicationContext接口的实现类包含两种配置容器的方式,一种是基于xml文件,另外一种是通过添加配置注解的配置类。

参考资料

spring5讲解视频

循环依赖介绍

标签:ApplicationContext,04,BeanFactory,springframework,bean,context,import,org,class
来源: https://www.cnblogs.com/kfcuj/p/16336304.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有