容器实现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();
// 注册BeanDefinition
beanFactory.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 还不会解析 ${ } 与 #{ }
*/
}
@Configuration
static class Config {
@Bean
public Bean1 getBean1() {
return new Bean1();
}
@Bean
public Bean2 getBean2() {
return new Bean2();
}
}
static class Bean1 {
public Bean1() {
log.debug("构造 Bean1()");
}
@Autowired
private 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);
});
}
@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;
}
@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;
}
}
@Configuration
static class Config {
@Bean
public Bean1 bean1() {
return new Bean1();
}
@Bean
public Bean2 bean2() {
return new Bean2();
}
}
@Configuration
static class WebConfig {
@Bean
public ServletWebServerFactory servletWebServerFactory() {
// 初始化一个内嵌的tomcat
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet() {
// 转发请求至对应的servlet
return new DispatcherServlet();
}
@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet) {
// 将请求转发器关联到tomcat容器
return new DispatcherServletRegistrationBean(dispatcherServlet, "/");
}
@Bean("/hello")
public Controller controller1() {
// spring约定如果Bean的名字/开头则是一个servlet
return (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);
}
}