参考
B站颜群老师Spring教程,B站雷丰阳老师Spring教程,《Spring实战》
https://zhuanlan.zhihu.com/p/137507309
https://liayun.blog.csdn.net/article/details/115053350
容器
快速导入一个组件
Spring 3.0之前,创建bean 可以通过XML 配置文件与扫描特定包下面的类
来将类注入到Spring IOC容器内。而在Spring 3.0之后提供了JavaConfig
的方式,也就是将IOC容器里面bean的元信息以Java代码的方式进行描述,
然后我们可以通过@Configuration与@Bean这两个注解配合使用来将原来
配置在XML文件里面的bean通过Java代码的方式进行描述
- 包扫描+给组件标注注解(@Controller、@Servcie、@Repository、
@Component),但这种方式比较有局限性,局限于我们自己写的类
- @Bean注解,通常用于导入第三方包中的组件
- @Import注解,快速向Spring容器中导入一个组件
@Import注解概述
@Import注解提供了@Bean 注解的功能,同时还有XML配置文件里面标签组织
多个分散的XML文件的功能,当然在这里是组织多个分散的@Configuration
,因为一个配置类就约等于一个XML配置文件
1 2 3 4 5
|
public @interface Import { Class<?>[] value(); }
|
注意:@Import注解只允许放到类上面,不允许放到方法上
@Import注解的使用方式
@Import注解的三种用法主要包括:
- 直接填写class数组的方式
- ImportSelector接口的方式,即批量导入,这是重点
- ImportBeanDefinitionRegistrar接口方式,即手工注册bean到容器中
首先来看第一种方式,创建一个Color类
在MainConfig2配置类上添加一个@Import注解,并将Color类填写到该注解中
1 2 3 4 5 6 7 8
|
@Conditional({WindowsCondition.class}) @Configuration @Import(Color.class) // @Import快速地导入组件,id默认是组件的全类名 public class MainConfig2 { ... }
|
@Import注解还支持同时导入多个类,比如又创建一个Red类
1
| @Import({Color.class, Red.class})
|
ImportSelector
接下来学一下第二种方式,ImportSelector接口是Spring中导入外部配置
的核心接口,在Spring Boot的自动化配置和@EnableXXX(功能性注解)
都有它的存在
1 2 3 4 5
| public interface ImportSelector {
String[] selectImports(AnnotationMetadata var1); }
|
其主要作用是收集需要导入的配置类,selectImports() 方法的返回值就
是我们向Spring 容器中导入的类的全类名。如果该接口的实现类同时实现
EnvironmentAware,BeanFactoryAware,BeanClassLoaderAware 或
者ResourceLoaderAware,那么在调用其selectImports()方法之前先
调用上述接口中对应的方法,如果需要在所有的@Configuration处理完
再导入时,那么可以实现DeferredImportSelector接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| public class MyImportSelector implements ImportSelector { @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) {
return new String[]{"com.atguigu.bean.Bule", "com.atguigu.bean.Yellow"}; } }
|
然后在MainConfig2配置类的@Import注解中,导入MyImportSelector类
1 2 3 4 5 6 7 8
| @Conditional({WindowsCondition.class}) // 满足当前条件,这个类中配置的所有bean注册才能生效 @Configuration @Import({Color.class, Red.class, MyImportSelector.class}) public class MainConfig2 { ... }
|
ImportBeanDefinitionRegistrar
在该接口中,有一个registerBeanDefinitions()方法,通过该方法,我
们可以向Spring容器中注册bean实例
1 2 3 4 5 6 7 8 9 10 11
| public interface ImportBeanDefinitionRegistrar {
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { } }
|
首先创建创建一个RainBow类,作为测试ImportBeanDefinitionRegistrar
接口的bean来使用
1 2 3
| package com.atguigu.bean; public class RainBow { }
|
创建ImportBeanDefinitionRegistrar接口的实现类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
@Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean definition = registry.containsBeanDefinition( "com.atguigu.bean.Red"); boolean definition2 = registry.containsBeanDefinition( "com.atguigu.bean.Bule"); if (definition && definition2) { RootBeanDefinition beanDefinition = new RootBeanDefinition( RainBow.class); registry.registerBeanDefinition("rainBow", beanDefinition); } } }
|
以上registerBeanDefinitions()方法的实现逻辑很简单,就是判断Spring
容器中是否同时存在以Red命名的bean和以Bule命名的bean,如果真的同时
存在,那么向Spring容器中注入一个以rainBow命名的bean。
ImportBeanDefinitionRegistrar需要配合@Configuration和@Import
这俩注解,其中,@Configuration注解定义Java格式的Spring配置文件
,@Import注解导入实现了ImportBeanDefinitionRegistrar接口的类
1 2 3 4 5 6 7 8 9 10
| @Conditional({WindowsCondition.class}) // 满足当前条件,这个类中配置的所有bean注册才能生效 @Configuration @Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) // @Import快速地导入组件,id默认是组件的全类名 public class MainConfig2 { ... }
|
FactoryBean注册组件
可以使用FactoryBean向Spring容器中注册bean,一般情况下,Spring是
通过反射机制利用bean的class属性指定实现类来实例化bean的。在某些情
况下,实例化bean过程比较复杂,如果按照传统的方式,那么则需要在标
签中提供大量的配置信息,配置方式的灵活性是受限的,这时采用编码的
方式可以得到一个更加简单的方案。Spring为此提供了FactoryBean的工
厂类接口,用户可以通过实现该接口定制实例化bean的逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public interface FactoryBean<T> { String OBJECT_TYPE_ATTRIBUTE = "factoryBeanObjectType";
@Nullable T getObject() throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton() { return true; } }
|
需要注意的是:当配置文件中标签的class属性配置的实现类是FactoryBean
时,通过getBean()方法返回的不是FactoryBean本身,而是FactoryBean
#getObject()方法所返回的对象,相当于FactoryBean#getObject()代
理了getBean()方法
FactoryBean案例
创建一个ColorFactoryBean类,它得实现FactoryBean接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| public class ColorFactoryBean implements FactoryBean<Color> { @Override public Color getObject() throws Exception { System.out.println("ColorFactoryBean...getObject..."); return new Color(); } @Override public Class<?> getObjectType() { return Color.class; } @Override public boolean isSingleton() { return false; } }
|
在MainConfig2配置类中加入ColorFactoryBean的声明
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| @Conditional({WindowsCondition.class}) // 满足当前条件,这个类中配置的所有bean注册才能生效 @Configuration @Import({Color.class, Red.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class}) // @Import快速地导入组件,id默认是组件的全类名 public class MainConfig2 { ... @Bean public ColorFactoryBean colorFactoryBean() { return new ColorFactoryBean(); } }
|
这里使用@Bean注解向Spring容器中注册的是ColorFactoryBean对象,但
是实际上从Spring容器中获取到的bean对象却是调用ColorFactoryBean
类中的getObject()方法获取到的Color对象
1 2 3 4 5 6 7 8 9 10 11 12
| @Test public void testImport() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } Object bean2 = applicationContext.getBean("colorFactoryBean"); System.out.println("bean的类型:" + bean2.getClass()); }
|
获取到FactoryBean对象本身
只需要在获取工厂Bean本身时,在id前面加上&符号即可,例如&colorFactoryBean
1 2 3 4 5 6 7 8 9 10
| public void testImport() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class); String[] definitionNames = applicationContext.getBeanDefinitionNames(); for (String name : definitionNames) { System.out.println(name); } Object bean4 = applicationContext.getBean("&colorFactoryBean"); System.out.println(bean4.getClass()); }
|
@Bean注解指定初始化和销毁的方法
接下来是有关bean的生命周期的学习
bean的生命周期
通常意义上讲的bean的生命周期,指的是bean从创建到初始化,经过一系
列的流程,最终销毁的过程。在Spring中,bean 的生命周期是由Spring
容器来管理的。在Spring中,我们可以自己来指定bean 的初始化和销毁
的方法。我们指定了bean的初始化和销毁方法之后,当容器在bean进行
到当前生命周期的阶段时,会自动调用我们自定义的初始化和销毁方法
定义初始化和销毁方法
第一种定义初始化和销毁方法的方式:通过@Bean注解指定初始化和销毁方
法。如果是使用XML配置文件的方式配置bean的话,那么可以在标签中指定
bean的初始化和销毁方法
1 2 3 4 5
| <bean id="person" class="com.meimeixia.bean.Person" init-method="init" destroy-method="destroy"> <property name="age" value="18"></property> <property name="name" value="liayun"></property> </bean>
|
在我们自己写的Person类中,需要存在init()方法和destroy()方法。而
且Spring中还规定,这里的init()方法和destroy()方法必须是无参方
法,但可以抛出异常,首先创建一个Person类
1 2 3 4 5 6 7 8 9 10 11
| public class Car { public Car() { System.out.println("car constructor..."); } public void init() { System.out.println("car ... init..."); } public void destroy() { System.out.println("car ... destroy..."); } }
|
然后将Car类对象通过注解的方式注册到Spring容器中,具体的做法就
是新建一个MainConfigOfLifeCycle类作为Spring的配置类,将Car
类对象通过MainConfigOfLifeCycle类注册到Spring容器中
1 2 3 4 5 6 7
| @Configuration public class MainConfigOfLifeCycle { @Bean public Car car() { return new Car(); } }
|
接着新建一个IOCTest_LifeCycle类来测试容器中的Car对象
1 2 3 4 5 6 7 8 9
| public class IOCTest_LifeCycle { @Test public void test01() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器创建完成"); } }
|
对于单实例bean对象来说,在Spring 容器创建完成后,就会对单实例
bean进行实例化,此时没有执行init和destroy方法,如果是使用XML
文件配置的话,那么我们可以使用如下配置来实现
1 2 3
| <bean id="car" class="com.meimeixia.bean.Car" init-method="init" destroy-method="destroy"> </bean>
|
接下来使用@Bean注解实现
1 2 3 4 5 6 7 8 9 10 11
| public @interface Bean { @AliasFor("name") String[] value() default {}; @AliasFor("value") String[] name() default {}; @Deprecated Autowire autowire() default Autowire.NO; boolean autowireCandidate() default true; String initMethod() default ""; String destroyMethod() default "(inferred)"; }
|
使用@Bean注解的initMethod属性和destroyMethod属性来指定bean的
初始化方法和销毁方法
1 2 3 4 5 6 7
| @Configuration public class MainConfigOfLifeCycle { @Bean(initMethod="init", destroyMethod="destroy") public Car car() { return new Car(); } }
|
在Spring容器中,先是调用了Car类的构造方法来创建Car对象,接下来便
是调用了Car对象的init()方法来进行初始化。但是不会打印销毁信息,
bean的销毁方法是在容器关闭的时候被调用的
1 2 3 4 5 6 7 8 9 10 11
| public class IOCTest_LifeCycle { @Test public void test01() { AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class); System.out.println("容器创建完成"); applicationContext.close(); } }
|
初始化和销毁方法的使用场景
一个典型的使用场景就是对于数据源的管理。在配置数据源时,在初始化
的时候,会对很多的数据源的属性进行赋值操作,在销毁的时候,我们
需要对数据源的连接等信息进行关闭和清理。这个时候,就可以在自定
义的初始化和销毁方法中来做这些事情了
初始化和销毁方法调用的时机
- bean对象的初始化方法调用的时机:对象创建完成,如果对象中存在
一些属性,并且这些属性也都赋好值之后,那么就会调用bean的初始化
方法。对于单实例bean来说,在Spring容器创建完成后,Spring 容器
会自动调用bean 的初始化方法,对于多实例bean 来说,在每次获取
bean对象的时候,调用bean的初始化方法
- bean对象的销毁方法调用的时机:对于单实例bean来说,在容器关闭
的时候,会调用bean的销毁方法,对于多实例bean来说,Spring容器不
会管理这个bean,也就不会自动调用这个bean的销毁方法了
多实例Bean
多实例bean的初始化和销毁方法调用的时机与单实例不同
1 2 3 4 5 6 7 8
| @Configuration public class MainConfigOfLifeCycle { @Scope("prototype") @Bean(initMethod="init", destroyMethod="destroy") public Car car() { return new Car(); } }
|
当我们在获取多实例bean对象的时候,会创建对象并进行初始化,多实
例的bean在容器关闭的时候是不进行销毁的,也就是说你每次获取时,
IOC容器帮你创建出对象交还给你,至于要什么时候销毁这是你自己的
事,Spring容器压根就不会再管理这些多实例的bean了
管理bean的生命周期
Spring中提供了一个InitializingBean接口,该接口为bean提供了属性
初始化后的处理方法,它只包括afterPropertiesSet方法,凡是继承该
接口的类,在bean的属性初始化后都会执行该方法
1 2 3 4
| public interface InitializingBean { void afterPropertiesSet() throws Exception; }
|
何时调用InitializingBean接口
首先定位到AbstractAutowireCapableBeanFactory这个类里面的
invokeInitMethods()方法中,来查看Spring加载bean的方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36
| protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd) throws Throwable { boolean isInitializingBean = bean instanceof InitializingBean; if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (this.logger.isTraceEnabled()) { this.logger.trace( "Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } if (System.getSecurityManager() != null) { try { AccessController.doPrivileged(() -> { ((InitializingBean)bean).afterPropertiesSet(); return null; }, this.getAccessControlContext()); } catch (PrivilegedActionException var6) { throw var6.getException(); } } else { ((InitializingBean)bean).afterPropertiesSet(); } } if (mbd != null && bean.getClass() != NullBean.class) { String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) { this.invokeCustomInitMethod(beanName, bean, mbd); } } }
|
分析上述代码后,我们可以初步得出如下信息
- Spring为bean提供了两种初始化的方式,实现InitializingBean
接口(也就是要实现该接口中的afterPropertiesSet方法),或者在
配置文件或@Bean注解中通过init-method来指定,两种方式可以同时
使用
- 实现InitializingBean接口是直接调用afterPropertiesSet()方
法,与通过反射调用init-method指定的方法相比,效率相对来说要高
点。但是init-method方式消除了对Spring的依赖
- 如果调用afterPropertiesSet方法时出错,那么就不会调用
init-method指定的方法了
也就是说Spring 为bean 提供了两种初始化的方式,第一种方式是实现
InitializingBean 接口(实现该接口中afterPropertiesSet方法)
,第二种方式是在配置文件或@Bean注解中通过init-method来指定,
这两种方式可以同时使用,同时使用先调用afterPropertiesSet方
法,后执行init-method 指定的方法
DisposableBean接口
实现DisposableBean 接口的bean在销毁前,Spring将会调用该接口
的destroy()方法
1 2 3
| public interface DisposableBean { void destroy() throws Exception; }
|
在bean生命周期结束前调用destroy()方法做一些收尾工作,亦可以使用
destroy-method。前者与Spring耦合高,使用类型强转.方法名(),效
率高,后者耦合低,使用反射,效率相对来说较低
DisposableBean接口注意事项
多实例bean的生命周期不归Spring容器来管理,这里的DisposableBean
接口中的方法是由Spring容器来调用的,所以如果一个多实例bean 实现
了DisposableBean接口是没有啥意义的,因为相应的方法根本不会被调
用,在XML配置文件中指定了destroy方法,也是没有任何意义的。在多
实例bean情况下,Spring是不会自动调用bean的销毁方法的
单实例bean
创建一个Cat的类来实现InitializingBean和DisposableBean这俩接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| @Component public class Cat implements InitializingBean, DisposableBean { public Cat() { System.out.println("cat constructor..."); }
@Override public void destroy() throws Exception { System.out.println("cat destroy..."); }
@Override public void afterPropertiesSet() throws Exception { System.out.println("cat afterPropertiesSet..."); } }
|
在MainConfigOfLifeCycle配置类中通过包扫描的方式将以上类注入
到Spring容器中
1 2 3 4 5 6 7 8 9
| @ComponentScan("com.meimeixia.bean") @Configuration public class MainConfigOfLifeCycle { @Scope("prototype") @Bean(initMethod="init", destroyMethod="destroy") public Car car() { return new Car(); } }
|
单实例bean情况下,IOC容器创建完成后,会自动调用bean的初始化方
法,而在容器销毁前,会自动调用bean的销毁方法
多实例bean
在多实例bean情况下,Spring不会自动调用bean的销毁方法
1 2 3 4 5
| @Scope("prototype") @Component public class Cat implements InitializingBean, DisposableBean { ... }
|
@PostConstruct注解和@PreDestroy注解
在JDK中还提供了两个注解能够在bean 创建完成并且属性赋值完成之后
执行一些初始化工作和在容器销毁bean之前通知我们进行一些清理工作
@PostConstruct注解
@PostConstruct注解好多人以为是Spring提供的,其实它是Java自己的
注解,是JSR-250规范里面定义的一个注解
1 2 3 4 5
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface PostConstruct { }
|
该注解被用来修饰一个非静态的void()方法。被@PostConstruct注解修饰
的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。
被@PostConstruct注解修饰的方法通常在构造函数之后,init()方法之
前执行,执行顺序如下
1
| Constructor(构造方法)→@Autowired(依赖注入)→@PostConstruct(注释的方法)
|
@PreDestroy注解
@PreDestroy注解同样是Java提供的,它也是JSR-250规范里面定义的一
个注解
1 2 3 4 5
| @Documented @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD}) public @interface PreDestroy { }
|
被@PreDestroy 注解修饰的方法会在服务器卸载Servlet 的时候运行,并且
只会被服务器调用一次,类似于Servlet的destroy()方法。被@PreDestroy
注解修饰的方法会在destroy()方法之后,Servlet被彻底卸载之前执行
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Component public class Dog { public Dog() { System.out.println("dog constructor..."); } @PostConstruct public void init() { System.out.println("dog...@PostConstruct..."); } @PreDestroy public void destory() { System.out.println("dog...@PreDestroy..."); } }
|
BeanPostProcessor后置处理器
BeanPostProcessor是一个接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
|
这两个方法分别是在Spring容器中的bean初始化前后执行,所以Spring
容器中的每一个bean对象初始化前后,都会执行BeanPostProcessor接
口的实现类中的这两个方法。当容器中存在多个BeanPostProcessor的
实现类时,会按照它们在容器中注册的顺序执行。对于自定义的实现类
,还可以让其实现Ordered接口自定义排序
后置处理器实例
创建一个MyBeanPostProcessor类,实现BeanPostProcessor接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| @Component public class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean); return bean; } }
|
也可以让我们自己写的MyBeanPostProcessor类来实现Ordered接
口自定义排序
1 2 3 4 5 6 7 8 9
| @Component public class MyBeanPostProcessor implements BeanPostProcessor, Ordered { ... @Override public int getOrder() { return 3; } }
|
后置处理器作用
后置处理器可用于bean 对象初始化前后进行逻辑增强。Spring 提供了
该接口很多实现类
- AutowiredAnnotationBeanPostProcessor用于@Autowired注解
的实现
- AnnotationAwareAspectJAutoProxyCreator用于Spring AOP
的动态代理等等
我们都知道spring AOP的实现原理是动态代理,最终放入容器的是代理
类的对象,而不是bean本身的对象,那么Spring是什么时候做到这一步
的呢?就是在AnnotationAwareAspectJAutoProxyCreator后置处理
器的postProcessAfterInitialization方法中,即bean对象初始化
完成之后,后置处理器会判断该bean是否注册了切面,若是,则生成
代理对象注入到容器中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15
| public abstract class AbstractAutoProxyCreator extends ProxyProcessorSupport implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware { ... public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) { if (bean != null) { Object cacheKey = this.getCacheKey(bean.getClass(), beanName); if (this.earlyProxyReferences.remove(cacheKey) != bean) { return this.wrapIfNecessary(bean, beanName, cacheKey); } } return bean; } }
|
BeanPostProcessor的执行流程
接下来看一下BeanPostProcessor的底层原理
bean的初始化和销毁
bean的初始化和销毁方法我们可以通过如下四种方式进行指定
- 通过@Bean指定init-method和destroy-method
1 2 3 4
| @Bean(initMethod="init", destroyMethod="destroy") public Car car() { return new Car(); }
|
- 通过让bean实现InitializingBean和DisposableBean这俩接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Component public class Cat implements InitializingBean, DisposableBean { public Cat() { System.out.println("cat constructor..."); } @Override public void destroy() throws Exception { System.out.println("cat destroy..."); } @Override public void afterPropertiesSet() throws Exception { System.out.println("cat afterPropertiesSet..."); } }
|
- 使用JSR-250规范里面定义的@PostConstruct和@PreDestroy
- @PostConstruct:在bean创建完成并且属性赋值完成之后,来执行
初始化方法
- @PreDestroy:在容器销毁bean之前通知我们进行清理工作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| @Component public class Dog { public Dog() { System.out.println("dog constructor..."); } @PostConstruct public void init() { System.out.println("dog...@PostConstruct..."); } @PreDestroy public void destory() { System.out.println("dog...@PreDestroy..."); } }
|
- 通过让bean实现BeanPostProcessor接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| @Component public class MyBeanPostProcessor implements BeanPostProcessor, Ordered { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessBeforeInitialization..." + beanName + "=>" + bean); return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("postProcessAfterInitialization..." + beanName + "=>" + bean); return bean; } @Override public int getOrder() { return 3; } }
|
通过以上这四种方式,我们就可以对bean的整个生命周期进行控制:
- bean的实例化:调用bean的构造方法,我们可以在bean的无参构造
方法中执行相应的逻辑
- bean的初始化:在初始化时,可以通过BeanPostProcesso 的两
个方法进行拦截,执行自定义的逻辑,通过@PostConstruct 注解、
InitializingBean和init-method来指定bean初始化前后执行的
方法,在该方法中咱们可以执行自定义的逻辑
- bean的销毁:可以通过@PreDestroy注解、DisposableBean和
destroy-method来指定bean在销毁前执行的方法,在该方法中咱
们可以执行自定义的逻辑
BeanPostProcessor源码解析
AbstractAutowireCapableBeanFactory类的doCreateBean()方法中
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args) throws BeanCreationException { ... Object exposedObject = bean; try { this.populateBean(beanName, mbd, instanceWrapper); exposedObject = this.initializeBean(beanName, exposedObject, mbd); } catch (Throwable var18) { if (var18 instanceof BeanCreationException && beanName.equals( ((BeanCreationException)var18).getBeanName())) { throw (BeanCreationException)var18; } throw new BeanCreationException(mbd.getResourceDescription(), beanName, "Initialization of bean failed", var18); } ... }
|
调用initializeBean()方法之前,还调用了一个populateBean()方
法,populateBean() 方法同样是该类中的方法,它里面的代码比较
多,但是逻辑非常简单,populateBean()方法做的工作就是为bean
的属性赋值。也就是说,在Spring中会先调用populateBean()方法
为bean的属性赋好值,然后再调用initializeBean()方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { ... Object wrappedBean = bean; if (mbd == null || !mbd.isSynthetic()) { wrappedBean = this.applyBeanPostProcessorsBeforeInitialization( bean, beanName); } try {
this.invokeInitMethods(beanName, wrappedBean, mbd); } catch (Throwable var6) { throw new BeanCreationException(mbd != null ? mbd.getResourceDescription() : null, beanName, "Invocation of init method failed", var6); } if (mbd == null || !mbd.isSynthetic()) { wrappedBean = this.applyBeanPostProcessorsAfterInitialization( wrappedBean, beanName); } return wrappedBean; }
|
先来看看applyBeanPostProcessorsBeforeInitialization()
方法中具体执行了哪些逻辑
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; Object current;
for(Iterator var4 = this.getBeanPostProcessors().iterator(); var4.hasNext(); result = current) { BeanPostProcessor processor = (BeanPostProcessor)var4.next(); current = processor.postProcessBeforeInitialization(result, beanName); if (current == null) { return result; } } return result; }
|
经过上面的一系列的跟踪源码分析,我们可以将关键代码的调用过程使用
如下伪代码表述出来
1 2 3 4 5 6 7
| populateBean(beanName, mbd, instanceWrapper); initializeBean(beanName, exposedObject, mbd) { applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); invokeInitMethods(beanName, wrappedBean, mbd); applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); }
|
也就是说,在Spring中,调用initializeBean()方法之前,调用了
populateBean()方法为bean的属性赋值,为bean的属性赋好值之后
,再调用initializeBean()方法进行初始化。
在initializeBean()中,调用自定义初始化方法invokeInitMethods()
之前,调用了applyBeanPostProcessorsBeforeInitialization()方
法,applyBeanPostProcessorsAfterInitialization()方法在调用
自定义的初始化方法后调用,至此整个bean的初始化过程就这样结束了
BeanPostProcessor底层使用
依然来看一下BeanPostProcessor的源码,接下来就来分析下
BeanPostProcessor接口在Spring中的实现
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }
|
ApplicationContextAwareProcessor类
ApplicationContextAwareProcessor是BeanPostProcessor接
口的一个实现类,这个类的作用是可以向组件中注入IOC容器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
| class ApplicationContextAwareProcessor implements BeanPostProcessor { private final ConfigurableApplicationContext applicationContext; private final StringValueResolver embeddedValueResolver; public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) { this.applicationContext = applicationContext; this.embeddedValueResolver = new EmbeddedValueResolver( applicationContext.getBeanFactory()); } @Nullable public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if (!(bean instanceof EnvironmentAware) && !(bean instanceof EmbeddedValueResolverAware) && !(bean instanceof ResourceLoaderAware) && !(bean instanceof ApplicationEventPublisherAware) && !(bean instanceof MessageSourceAware) && !(bean instanceof ApplicationContextAware)) { return bean; } else { AccessControlContext acc = null; if (System.getSecurityManager() != null) { acc = this.applicationContext.getBeanFactory(). getAccessControlContext(); }
if (acc != null) { AccessController.doPrivileged(() -> { this.invokeAwareInterfaces(bean); return null; }, acc); } else { this.invokeAwareInterfaces(bean); }
return bean; } }
private void invokeAwareInterfaces(Object bean) { if (bean instanceof EnvironmentAware) { ((EnvironmentAware)bean).setEnvironment( this.applicationContext.getEnvironment()); }
if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware)bean).setEmbeddedValueResolver( this.embeddedValueResolver); }
if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware)bean).setResourceLoader( this.applicationContext); }
if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware)bean). setApplicationEventPublisher(this.applicationContext); }
if (bean instanceof MessageSourceAware) { ((MessageSourceAware)bean).setMessageSource(this. applicationContext); }
if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware)bean).setApplicationContext( this.applicationContext); } } }
|
要想使用ApplicationContextAwareProcessor类向组件中注
入IOC 容器,我们就不得不提Spring 中的另一个接口了,即
ApplicationContextAware。如果需要向组件中注入IOC容器
,那么可以让组件实现ApplicationContextAware接口。
创建一个Dog类,使其实现ApplicationContextAware接口
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
@Component public class Dog implements ApplicationContextAware { private ApplicationContext applicationContext;
public Dog() { System.out.println("dog constructor..."); } @PostConstruct public void init() { System.out.println("dog...@PostConstruct..."); } @PreDestroy public void destory() { System.out.println("dog...@PreDestroy..."); }
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException { this.applicationContext = applicationContext; } }
|
BeanValidationPostProcessor类
该类主要是用来为bean进行校验操作的,当我们创建bean,并为bean
赋值后,我们可以通过BeanValidationPostProcessor类为bean进
行校验操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| public class BeanValidationPostProcessor implements BeanPostProcessor, InitializingBean { @Nullable private Validator validator; private boolean afterInitialization = false; ...
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (!this.afterInitialization) { this.doValidate(bean); }
return bean; }
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (this.afterInitialization) { this.doValidate(bean); }
return bean; } }
|
InitDestroyAnnotationBeanPostProcessor类
该类主要用来处理@PostConstruct注解和@PreDestroy注解,之
前创建的Dog类中就使用了@PostConstruct注解和@PreDestroy
注解。
在Dog类中使用了@PostConstruct注解和@PreDestroy注解来标注
方法,Spring怎么就知道什么时候执行@PostConstruct注解标注
的方法,什么时候执行@PreDestroy注解标注的方法呢?这就要归
功于InitDestroyAnnotationBeanPostProcessor类了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| public class InitDestroyAnnotationBeanPostProcessor implements DestructionAwareBeanPostProcessor, MergedBeanDefinitionPostProcessor, PriorityOrdered, Serializable {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
InitDestroyAnnotationBeanPostProcessor.LifecycleMetadata metadata = this.findLifecycleMetadata(bean.getClass()); try { metadata.invokeInitMethods(bean, beanName); return bean; } catch (InvocationTargetException var5) { throw new BeanCreationException(beanName, "Invocation of init method failed", var5.getTargetException()); } catch (Throwable var6) { throw new BeanCreationException(beanName, "Failed to invoke init method", var6); } } }
|
AutowiredAnnotationBeanPostProcessor类
该类主要是用于处理标注了@Autowired注解的变量或方法