02.容器实现BeanFactory和ApplicationContext实现
容器实现BeanFactory和ApplicationContext实现
- BeanFactory实现的特点
- ApplicationContext的常见实现和用法
- 内嵌容器、注册DispatcherServlet
1. BeanFactory的实现
- BeanFactory不会主动添加BeanFactoryPostProcessor;BeanFactory后处理器主要功能:补充了一些Bean的定义,例如扫描@Configuration注解
- BeanFactory不会主动添加BeanPostProcessor;Bean后处理器主要功能:针对bean的生命周期的各个阶段提供扩展,例如@Autowired、@Resource、@Value
- BeanFactory添加了后处理器的的定义后,不会主动创建这些后处理的对象(不会主动使用),需要调用对应的方法将BeanFactory和后处理器们关联起来
- 不会主动初始化单例,默认懒汉单例,用到了才会创建;beanFactory.preInstantiateSingletons()方法修改为饿汉单例
补充:
创建BeanDefinition
AbstractBeanDefinition definition = BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
注册BeanDefinition
beanFactory.registerBeanDefinition("config", definition);
给BeanFactory添加一些常用的后处理器
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
添加的后处理器
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
用来解析@Configuration注解
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
用来解析@Autowire注解
org.springframework.context.annotation.internalCommonAnnotationProcessor
用来解析@Resource注解
org.springframework.context.event.internalEventListenerProcessor
org.springframework.context.event.internalEventListenerFactory
将BeanFactoryPostProcessor初始化到beanFactory
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
将BeanPostProcessor初始化到beanFactory
beanFactory.addBeanPostProcessor(beanPostProcessor);
将spring初始化Bean方式改为饿汉单例
beanFactory.preInstantiateSingletons();
public class A021 {private static final Logger log = LoggerFactory.getLogger(A021.class);public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();// BeanFactory里存放的是Bean的定义,而不是现成的对象;Bean的定义的要素:class、scope、初始化方法、销毁方法AbstractBeanDefinition definition =BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();// 注册BeanDefinitionbeanFactory.registerBeanDefinition("config", definition);for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {/* config*/}// 给BeanFactory添加一些常用的后处理器AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {/* 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后处理器BeanFactoryPostProcessor主要功能:补充了一些Bean的定义beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);});for (String beanDefinitionName : beanFactory.getBeanDefinitionNames()) {/* 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* getBean1* getBean2*/}// Bean 后处理器, 针对 bean 的生命周期的各个阶段提供扩展, 例如 @Autowired @Resource ...System.err.println(beanFactory.getBean(Bean1.class).getBean2());beanFactory.getBeansOfType(BeanPostProcessor.class).values().forEach(beanFactory::addBeanPostProcessor);System.err.println(beanFactory.getBean(Bean1.class).getBean2());beanFactory.preInstantiateSingletons(); // 准备好所有单例;默认懒汉单例,用到了才会创建,调用该方法修改为饿汉单例System.out.println(beanFactory.getBean(Bean1.class).getBean2());/*学到了什么:a. beanFactory 不会做的事1. 不会主动调用 BeanFactory 后处理器2. 不会主动添加 Bean 后处理器3. 不会主动初始化单例4. 不会解析beanFactory 还不会解析 ${ } 与 #{ }*/}@Configurationstatic class Config {@Beanpublic Bean1 getBean1() {return new Bean1();}@Beanpublic Bean2 getBean2() {return new Bean2();}}static class Bean1 {public Bean1() {log.debug("构造 Bean1()");}@Autowiredprivate Bean2 bean2;public Bean2 getBean2() {return bean2;}}static class Bean2 {public Bean2() {log.debug("构造 Bean2()");}}}
2. BeanFactory-后处理器排序
首先我们验证一个问题:
-
@Autowire注解根据类型注入,@Resource注解根据Bean的名称注入;
当有两个同类型的Bean时,@Autowire会寻找跟变量名相同的注解进行注入(找不到则抛出异常)
-
如果一个成员变量上同时存在@Autowire、@Resource,并且有两个同类型的Bean,那么最终注入的是哪个?
例如有两个Bean类型的Bean,名称bean1、bean2,成员变量名称bean1,@Resource注解指定注入bean2
-
结果是@Aurowire生效,@Resource失效,失效原因是被覆盖
以上问题的原因是:
- 每一个后处理器都有一个order,这些后处理器会根据order进行排序,order小的在前,先被执行;
- @Autowire由
AutowiredAnnotationBeanPostProcessor
处理,该处理器的优先级是Ordered.LOWEST_PRECEDENCE - 2
;@Resource由CommonAnnotationBeanPostProcessor
处理,该处理器的优先级是Ordered.LOWEST_PRECEDENCE - 3
- 因此@Resource对应的后处理器order更小,先被执行,然后后执行的@Autowire覆盖掉
我们也可以手动调整顺序,但是没有必要;以下是相关源码
-
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
这里包含了添加Comparator方式的代码
-
beanFactory.setDependencyComparator(AnnotationAwareOrderComparator.INSTANCE);
传入一个比较器,该比较器实现了Comparator接口,在该比较器中重写了compare方法,内部实际上比较各个后处理器的order
-
每个后处理器都实现了Ordered接口,Ordered中有个getOrder()方法,返回各个后处理器的order大小
public class AutowiredAnnotationBeanPostProcessor implements SmartInstantiationAwareBeanPostProcessor,
MergedBeanDefinitionPostProcessor,PriorityOrdered
, BeanFactoryAware -
获取到beanPostProcessors,得到list,调整顺序后再挨个添加到beanFactory中,就可以得到跟上文相反的结果
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).forEach(beanPostProcessor -> {System.out.println(">>>>" + beanPostProcessor);beanFactory.addBeanPostProcessor(beanPostProcessor);});
public class A022 {private static final Logger log = LoggerFactory.getLogger(A022.class);public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();AbstractBeanDefinition definition =BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();beanFactory.registerBeanDefinition("config", definition);AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().forEach(beanFactoryPostProcessor -> {beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);});beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream().sorted(beanFactory.getDependencyComparator()).forEach(beanPostProcessor -> {System.out.println(">>>>" + beanPostProcessor);beanFactory.addBeanPostProcessor(beanPostProcessor);});}@Configurationstatic class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2() {return new Bean2();}@Beanpublic Bean3 bean3() {return new Bean3();}@Beanpublic 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()");}@Autowiredprivate Bean2 bean2;public Bean2 getBean2() {return bean2;}@Autowired@Resource(name = "bean4")private Inter bean3;public Inter getInter() {return bean3;}}static class Bean2 {private static final Logger log = LoggerFactory.getLogger(Bean2.class);public Bean2() {log.debug("构造 Bean2()");}}}
3. 四种经典的ApplicationContext实现
ClassPathXmlApplicationContext
支持读取类路径下的 XML格式bean配置文件的Web容器
FileSystemXmlApplicationContext
支持读取文件系统下的XML格式bean配置文件的Web容器
AnnotationConfigApplicaitonContext
支持读取@Config、@Resource、@Autowire、@Value等注解的Web容器
AnnotaionConfigServletWebServerApplicaitonContext
在AnnotationConfigApplicaitonContext的基础上,增加了对web应用的支持,可以接收和响应请求
public class A023 {public static void main(String[] args) {
// testClassPathXmlApplicationContext();
// testFileSystemXmlApplicationContext();
// testAnnotationConfigApplicationContext();
// testAnnotationConfigServletWebServerApplicationContext();}private static void testClassPathXmlApplicationContext() {ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("a023.xml");for (String name : context.getBeanDefinitionNames()) {System.err.println(name);}}private static void testFileSystemXmlApplicationContext() {
// FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("E:\\\\allproject\\\\spring\\\\src\\\\main\\\\resources\\\\a023.xml");FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("src/main/resources/a023.xml");for (String name : context.getBeanDefinitionNames()) {System.err.println(name);}}private static void testAnnotationConfigApplicationContext() {AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(Config.class);for (String name : context.getBeanDefinitionNames()) {System.err.println(name);}}private static void testAnnotationConfigServletWebServerApplicationContext() {AnnotationConfigServletWebServerApplicationContext context = new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);for (String name : context.getBeanDefinitionNames()) {System.err.println(name);}}static class Bean1 {}static class Bean2 {private A023.Bean1 bean1;public void setBean1(A023.Bean1 bean1) {this.bean1 = bean1;}public A023.Bean1 getBean1() {return bean1;}}@Configurationstatic class Config {@Beanpublic Bean1 bean1() {return new Bean1();}@Beanpublic Bean2 bean2() {return new Bean2();}}@Configurationstatic class WebConfig {@Beanpublic ServletWebServerFactory servletWebServerFactory() {// 初始化一个内嵌的tomcatreturn new TomcatServletWebServerFactory();}@Beanpublic DispatcherServlet dispatcherServlet() {// 转发请求至对应的servletreturn new DispatcherServlet();}@Beanpublic DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {// 将请求转发器关联到tomcat容器return new DispatcherServletRegistrationBean(dispatcherServlet, "/");}@Bean("/hello")public Controller controller1() {// spring约定如果Bean的名字/开头则是一个servletreturn (request, response) -> {response.getWriter().write("hello");return null;};}}
}
<?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"><!-- 控制反转, 让 bean1 被 Spring 容器管理 --><bean id="bean1" class="com.shunyum.a02.A023.Bean1"/><!-- 控制反转, 让 bean1 被 Spring 容器管理 --><bean id="bean2" class="com.shunyum.a02.A023.Bean2"><property name="bean1" ref="bean1"/></bean>
</beans>
4. ApplicationContext内部做的事
application内部组合了beanFactory,实际上bean的定义是由内部beanFactory实现;
下面的例子就是ClasspathXml ApplicationContext中的beanFactory做了哪些事;
同理,AnnotationConfigApplicationContext中的beanFactory做了哪些事可以参考第一节BeanFactory的实现
public static void main(String[] args) {DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();System.out.println("读取之前...");for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}System.out.println("读取之后...");XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
// reader.loadBeanDefinitions("a023.xml");reader.loadBeanDefinitions(new FileSystemResource("src/main/resources/a023.xml"));for (String name : beanFactory.getBeanDefinitionNames()) {System.out.println(name);}}