1.BeanFactory实现
测试类起手
public class TestBeanFactory {
public static void main(String[] args){
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//bean的定义(lass,scope单例多例,初始化、消费方法)
//建造者模式
AbstractBeanDefinition beanDefinition =
BeanDefinitionBuilder.genericBeanDefinition(Config.class).setScope("singleton").getBeanDefinition();
beanFactory.registerBeanDefinition("config",beanDefinition);
for (String name : beanFactory.getBeanDefinitionNames()) {
//此时只有config,没有bean1和bean2,说明@Configuration@Bean注解没有解析
//beanFactory不具备解析注解的功能
System.out.println(name);
}
}
@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()");}
}
}
此时的输出,只有config,不包含其他的bean,因为beanFactory不具备解析注解的功能,@Configuration@Bean注解没有被解析
1.1 BeanFactoryPostProcessor
稍作修改
//给beanFactory添加一些常用的后处理器,也就是对beanFactory进行扩展
//后处理器: 先把bean实例化,再去处理该Bean所依赖的关系
//spring的源码里有大量的后置处理器,aop原理就是借助后置处理器的执行时机来进行动态代理的
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
for (String name : beanFactory.getBeanDefinitionNames()) {
//此时再看,又多了几个bean
System.out.println(name);
}
输出如图:
此时还没有bean1和bean2,原因是还没执行后处理器
//生成beanFactory后处理器对象并执行
beanFactory.getBeansOfType(BeanFactoryPostProcessor.class).values().stream().forEach(beanFactoryPostProcessor -> {
beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);
});
for (String name : beanFactory.getBeanDefinitionNames()) {
//此时再看,bean1和bean2有了
System.out.println(name);
}
输出如图:
注意这里只是BeanDifination 而不是Bean本身,从bean1和bean2的构造器没被调用就知道了。
bean工厂的原始功能并没有那么丰富,扩展功能是通过后处理器实现的。
1.2 BeanPostProcessor
那么此时bean1中注入的bean2可以调用吗?试一下
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
输出结果:
21:38:08.903 [main] DEBUG com.example.demo.a02.TestBeanFactory$Bean1 - 构造Bean1()
null
说明此时@Autowired没被解析,依赖注入功能是没有的,刚才只执行了beanFactory的后处理器
要做依赖注入的话,还有bean的后处理器,刚才图里也有
@Autowired注解
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
@Resource注解
org.springframework.context.annotation.internalCommonAnnotationProcessor
复习一下@Autowired和@Resource这俩注解的区别:
(1)两个注解@Autowired和@Resource功能上等价;
(2)但匹配顺序不同, @Autowired获取bean会先byType方式再byName方式, 而@Resource与前者相反;
(3)另, 作用域不同, @Autowired可作用于构造器, 字段, setter方法上, 而@Resource只可作用于字段和setter方法上
//bean后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource
beanFactory.getBeansOfType(BeanPostProcessor.class)
.values().stream().forEach(beanFactory::addBeanPostProcessor);
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
此时完成了依赖注入,输出如下
21:54:40.052 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘bean1’
21:54:40.053 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘config’
21:54:40.065 [main] DEBUG com.example.demo.a02.TestBeanFactory$Bean1 - 构造Bean1()
21:54:40.072 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean ‘bean2’
21:54:40.073 [main] DEBUG com.example.demo.a02.TestBeanFactory$Bean2 - 构造Bean2()
最后看看这两个添加后处理器操作的区别:
//后处理器添加到BeanFactory
AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory);
//建立BeanFactory后处理器和BeanFactory的联系
beanFactory.getBeansOfType(BeanPostProcessor.class)
.values().stream().forEach(beanFactory::addBeanPostProcessor);
另外@Configuration加不加Config类中的@Bean注解都会被解析,@Configuration是用于Spring类扫描的时候用的,加了这个注解的类被扫描到了就会被放进Bean工厂
假设这样一种情况, 在方法1, 3中都调用了方法2去new Bean2, 那么Bean2是否会实例化多次?
答案是如果加了@Configuration就不会, 而是会走cglib动态代理去拦截@Bean方法的调用,使其每次会从Spring容器中获取Bean实例
那BeanFactory是用到时才创建,还是一开始就创建好呢?
这里加上分隔线
//bean后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource
beanFactory.getBeansOfType(BeanPostProcessor.class)
.values().stream().forEach(beanFactory::addBeanPostProcessor);
//用到的时候才去创建bean
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
可见是用到的时候才会创建bean
但对于单例对象,一般希望在getBean之前就把单例对象提前实例化,可以使用preInstantiateSingletons
//bean后处理器,针对bean的生命周期的各个阶段提供扩展,例如@Autowired @Resource
beanFactory.getBeansOfType(BeanPostProcessor.class)
.values().stream().forEach(beanFactory::addBeanPostProcessor);
//对于单例对象,一般希望在getBean之前就把单例对象提前实例化
beanFactory.preInstantiateSingletons();
//用到的时候才去创建bean
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>>>>");
System.out.println(beanFactory.getBean(Bean1.class).getBean2());
此时创建bean就在分隔线(实际使用)之前了
1.3 后处理器排序(@Autowired @Resource谁先被解析?)
新增了接口和implements该接口的bean3 bean4,然后这时注入Inter接口类型
因为@Autowired获取bean会先byType方式再byName方式,此时会有报错,容器里有两个Inter类型,可以用@qualifier,也可以明确变量名
@Autowired
private Inter bean3;
如果换成@Resource注解,顺序就是相反的,先byName,这里获取到的就是bean4
@Resource(name = "bean4")
private Inter bean3;
那如果同时使用@Autowired和@Resource,会注入谁呢?答案是bean3
@Autowired
@Resource(name = "bean4")
private Inter bean3;
和addBeanPostProcessor这里添加后处理器的顺序有关,Autowired后处理器先被添加进去,sout输出看一下
beanFactory.getBeansOfType(BeanPostProcessor.class)
.values().stream().forEach(beanPostProcessor -> {
System.out.println("===="+beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
确实如此,没排序之前,是根据getBeansOfType取出来的顺序设置的,不会考虑Order的大小,所以Autowired排到了Common前边
====org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@247d8ae
====org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@48974e45
那怎么控制后处理器的顺序呢?
其实在AnnotationConfigUtils.registerAnnotationConfigProcessors(beanFactory)中,已经set了比较器,所以这里可以直接beanFactory.getDependencyComparator()
我们可以通过比较器来修改顺序
beanFactory.getBeansOfType(BeanPostProcessor.class).values().stream()
//比较器
.sorted(beanFactory.getDependencyComparator())
.forEach(beanPostProcessor -> {
System.out.println("===="+beanPostProcessor);
beanFactory.addBeanPostProcessor(beanPostProcessor);
});
====org.springframework.context.annotation.CommonAnnotationBeanPostProcessor@2fd1433e
====org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor@29d89d5d
这样sorted就能改变顺序是因为,后处理器有order属性
AutowiredAnnotationBeanPostProcessor.order = Ordered.LOWEST_PRECEDENCE - 2 也就是2147483647-2=2147483645
CommonAnnotationBeanPostProcessor.order=Ordered.LOWEST_PRECEDENCE - 3也就是2147483647-3=2147483644
order的顺序是由小到大,那CommonAnnotationBeanPostProcessor就在前面了,这时@Resource先生效
总结:
1.beanFactory不会做的事
(1)不会主动调用BeanFactory后处理器
(2)不会主动添加Bean后处理器
(3)不会主动初始化单例对象
(4)不会解析BeanFactory 还不会解析 ${} 与 #{}
2.bean后处理器会有排序的逻辑
=>所以有了applicationContext的refresh
2.ApplicationContext实现
加载bean的定义信息,首先看xml配置bean的方式
<?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 id="bean1" class="com.example.demo.a02.A02Application.Bean1"/>
<bean id="bean2" class="com.example.demo.a02.A02Application.Bean2">
<property name="bean1" ref="bean1"/>
</bean>
</beans>
2.1 ClassPathXmlApplicationContext:较为经典的容器,基于classpath 下xml格式的配置文件来创建
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("b01.xml");
2.2 FileSystemXmlApplicationContext:基于磁盘路径下 xml格式的配置文件来创建, 绝对路径/相对路径
FileSystemXmlApplicationContext context =
new FileSystemXmlApplicationContext("src/main/resources/b01.xml");
2.3 XmlBeanDefinitionReader:使用XmlBeanDefinitionReader读取xml
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
//把xml的标签转成beanDefinition
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(beanFactory);
reader.loadBeanDefinitions(new ClassPathResource("b01.xml"));
2.4 AnnotationConfigApplicationContext:较为经典的容器,基于java配置类来创建,相对前几种,多了一些后处理器:
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(Config.class);
@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;
}
}
或者xml里加一句也能加上后处理器
<context:annotation-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
a02Application.Config bean1 bean2
2.5 AnnotationConfigServletWebApplicationContext:较为经典的容器,基于java配置类来创建,实现简单的web环境
使用了内嵌tomcat容器,dispatcherServlet,和注册的DispatcherServletRegistrationBean,没有用springboot的注解
private static void testAnnotationConfigServletWebServerApplicationContext(){
AnnotationConfigServletWebServerApplicationContext context =
new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
}
@Configuration
static class WebConfig{
@Bean
public ServletWebServerFactory servletWebServerFactory(){
return new TomcatServletWebServerFactory();
}
@Bean
public DispatcherServlet dispatcherServlet(){
return new DispatcherServlet();
}
//把DispatcherServlet注册到tomcat服务器中
@Bean
public DispatcherServletRegistrationBean registrationBean(DispatcherServlet dispatcherServlet){
return new DispatcherServletRegistrationBean(dispatcherServlet,"/");
}
@Bean("/hello")
public Controller controller1(){
return (request, response) -> {
response.getWriter().print("hello");
return null;
};
}
}
然后浏览器访问http://localhost:8080/hello,日志如下图