版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/my_momo_csdn/article/details/90986148
文章目录
- Spring扩展接口
- 一、扩展接口分类
- 二、详解
- 2.1 Aware系列解析
- 2.1.1 BeanNameAware
- 2.1.2 ApplicationContextAware
- 2.1.3 BeanFactoryAware
- 2.1.4 EnvironmentAware
- 2.1.5 ApplicationEventPublisherAware
- 2.2 BeanPostProcessor系列解析
- 2.2.1 BeanPostProcessor
- 2.2.2 InstantiationAwareBeanPostProcessor
- 2.2.3 MergedBeanDefinitionPostProcessor
- 2.2.4 BeanFactoryPostProcessor
- 2.3 初始化和销毁
- 2.4 其他
- 三、图示
- 四、总结
- 五、参考
Spring扩展接口
一、扩展接口分类
- Spring中的扩展接口非常多,给开发者留下了足够多的扩展点。在Spring中最核心的是IOC容器,而IOC容器中核心的是Bean,Bean就是Java对象,因此扩展点围绕的就是对这个Java对象(Bean)的生命周期的一些关键点做一些扩展。生命周期包括实例化,初始化,销毁等,针对每个阶段Spring几乎都有对应的扩展点,了解这些可以更好的帮助我们理解整个Spring容器的运行和对Bean的扩展和管理。按照扩展点的分类,我梳理了Spring中有下面这些扩展点。
1.1 Aware系列
- BeanNameAware
- ApplicationContextAware
- BeanFactoryAware
1.2 BeanPostProcessor系列
- BeanPostProcessor
- BeanFactoryPostProcessor
- InstantiationAwareBeanPostProcessor
- MergedBeanDefinitionPostProcessor
1.3 初始化和销毁
- InitialingBean和@PostConstruct,initMethod
- DisposableBean和@PreDestroy,destroyMethod
1.4 其他
- FactoryBean
二、详解
2.1 Aware系列解析
2.1.1 BeanNameAware
- Aware系列的接口作用很相似,都是给一个bean赋予一种能力,或者说给bean附一个值进去,比如BeanNameAware接口就是将beanName传给bean,后面的ApplicationContextAware接口,就是将ApplicationContext传给bean,BeanFactoryAware接口就是将BeanFactory传给bean,几乎是类似的,如果我们的bean在业务功能上需要这些对象,就可以通过相对应的Aware接口来实现字段的注入。
public class Man implements DisposableBean, InitializingBean, ApplicationContextAware, BeanNameAware, BeanFactoryAware, EnvironmentAware, ApplicationEventPublisherAware {
private String name;
private int age;
private String beanName;
public Man(String name, int age) {
System.out.println("Man 带参构造方法执行...");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Man{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
@Override
public void destroy() throws Exception {
System.out.println("Man 继承自DisposableBean接口的destroy 方法执行...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Man 继承自InitializingBean接口的afterPropertiesSet 方法执行...");
}
public void init() {
System.out.println("Man 类通过@Bean的init-method指定的init方法执行...");
}
public void destroySelf() {
System.out.println("Man 类通过@Bean的destroyMethod指定的destroySelf方法执行...");
}
@PostConstruct
public void postConstruct() {
System.out.println("Man 类通过@PostConstruct注解指定的PostConstruct方法执行........");
}
@PreDestroy
public void preDestroy() {
System.out.println("Man 类通过@PreDestroy注解指定的PreDestroy方法执行......");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("Man 继承自ApplicationContextAware接口的setApplicationContext方法执行......" + applicationContext.getId());
}
@Override
public void setBeanName(String name) {
this.beanName = name;
System.out.println("Man 继承自BeanNameAware接口的setBeanName方法执行......" + name);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("Man 继承自BeanFactoryAware接口的setBeanFactory方法执行......" + beanFactory.containsBean(beanName));
}
@Override
public void setEnvironment(Environment environment) {
System.out.println("Man 继承自EnvironmentAware接口的setEnvironment方法执行......" + environment.toString());
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("Man 继承自ApplicationEventPublisherAware接口的setApplicationEventPublisher方法执行......"
+ applicationEventPublisher.toString());
}
}
配置类:
@Configuration
@ComponentScan("com.intellif.ch1")
@PropertySource(value = "classpath:/application.properties")
public class MainConfig1 {
@Bean(value = "man", initMethod = "init", destroyMethod = "destroySelf")
public Man man() {
return new Man("Parker", 33);
}
}
测试:
public class Test1 {
@Test
public void test01() {
ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig1.class);
((AnnotationConfigApplicationContext) app).close();
}
}
打印:
MyInstantiationAwareBeanPostProcessor后置处理器的postProcessBeforeInstantiation方法执行...man
Man 带参构造方法执行...
MyMergedBeanDefinitionPostProcessor后置处理器的postProcessMergedBeanDefinition方法执行...man
MyInstantiationAwareBeanPostProcessor后置处理器的postProcessAfterInstantiation方法执行...man
MyInstantiationAwareBeanPostProcessor后置处理器的的PropertyDescriptor方法执行...man
Man 继承自BeanNameAware接口的setBeanName方法执行......man
Man 继承自BeanFactoryAware接口的setBeanFactory方法执行......true
Man 继承自EnvironmentAware接口的setEnvironment方法执行......StandardEnvironment {activeProfiles=[], defaultProfiles=[default], propertySources=[MapPropertySource {name='systemProperties'}, SystemEnvironmentPropertySource {name='systemEnvironment'}, ResourcePropertySource {name='class path resource [application.properties]'}]}
Man 继承自ApplicationEventPublisherAware接口的setApplicationEventPublisher方法执行......org.springframework.context.annotation.AnnotationConfigApplicationContext@2471cca7: startup date [Tue May 07 13:03:12 CST 2019]; root of context hierarchy
Man 继承自ApplicationContextAware接口的setApplicationContext方法执行......org.springframework.context.annotation.AnnotationConfigApplicationContext@2471cca7
MyBeanPostProcessor后置处理器的postProcessBeforeInitialization方法执行,the bean name is : man
Man 类通过@PostConstruct注解指定的PostConstruct方法执行........
Man 继承自InitializingBean接口的afterPropertiesSet 方法执行...
Man 类通过@Bean的init-method指定的init方法执行...
MyBeanPostProcessor后置处理器的postProcessAfterInitialization方法执行,the bean name is : man
Man 类通过@PreDestroy注解指定的PreDestroy方法执行......
Man 继承自DisposableBean接口的destroy 方法执行...
Man 类通过@Bean的destroyMethod指定的destroySelf方法执行...
- 我们看到6-10行,就是Aware接口的调用打印。Aware接口方法会在BeanPostProcessor的前置Before方法调用之前调用,具体可以参照后面的图片日志。
2.1.2 ApplicationContextAware
- 同上,不再赘述
2.1.3 BeanFactoryAware
- 同上,不再赘述
2.1.4 EnvironmentAware
- 同上,不再赘述
2.1.5 ApplicationEventPublisherAware
- 同上,不再赘述
2.2 BeanPostProcessor系列解析
2.2.1 BeanPostProcessor
- 方法会在bean的初始化前后被调用
2.2.2 InstantiationAwareBeanPostProcessor
- 方法会在bean的实例化前后被调用(注意实例化和初始化的区别,先实例化,再初始化)
2.2.3 MergedBeanDefinitionPostProcessor
- 方法会在bean的实例化之后调用,但是在InstantiationAwareBeanPostProcessor的后置After方法之前调用
2.2.4 BeanFactoryPostProcessor
- 这个方法放在"其他"里面分析
2.3 初始化和销毁
2.3.1 初始化
- @PostConstruct:JSR规范注解,JDK的注解,不是Spring的注解,注解的方法会在初始化阶段调用,也在这里一并讲解
- InitialingBean:Spring提供的扩展接口,会在初始化阶段调用,在属性设置完毕后做一些自定义操作
- initMethod:@Bean注解的属性方法,会在初始化阶段调用,在属性设置完毕后做一些自定义操作
2.3.2 销毁(关闭容器前执行)
- @PreDestroy:JSR规范注解,JDK的注解,不是Spring的注解,注解的方法会在销毁阶段调用,也在这里一并讲解
- DisposableBean:Spring提供的扩展接口,会在Bean销毁阶段调用
- destroyMethod:@Bean注解的属性方法,会在销毁阶段调用
2.3.3 调用时机
- 上面的6个方法,具体调用时机,参照后面的日志打印,或者时序图,比较清晰。
2.4 其他
2.4.1 FactoryBean
- FactoryBean在Spring中是非常有用的一个接口,传统的Spring容器加载一个Bean的整个过程,都是由Spring控制的,换句话说,开发者除了设置Bean相关属性之外,没有太多的自主权的。FactoryBean改变了这一点,开发者可以个性化地定制自己想要实例化出来的Bean,就是基于FactoryBean接口实现的。
@Component
public class MyFactoryBean implements FactoryBean<Man> {
@Override
public Man getObject() throws Exception {
if (new Random().nextBoolean()) {
return new Man("Kobe", 24);
}
return new Man("James", 23);
}
@Override
public Class<?> getObjectType() {
return Man.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
public class Man {
private String name;
private int age;
public Man(String name, int age) {
System.out.println("Man 带参构造方法执行...");
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "Man{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
//get and set methods
}
@Configuration
@ComponentScan("com.intellif.ch1")
@PropertySource(value = "classpath:/application.properties")
public class MainConfig1 {
}
public class Test1 {
@Test
public void test01() {
ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig1.class);
System.out.println(app.getBean("myFactoryBean").toString());
((AnnotationConfigApplicationContext) app).close();
}
}
这里会随机打印:Man{name='James', age=23}或者Man{name='Kobe', age=24},当然这里只是简单演示,我们可以
在构造bean的时候写更多的复杂逻辑来满足我们的需求,比如根据配置生成不同的bean。
2.4.2 BeanFactoryPostProcessor
- Spring允许在Bean创建之前,读取Bean的元属性,并根据自己的需求对元属性进行改变,比如将Bean的scope从singleton改变为prototype,PropertyPlaceholderConfigurer就是最典型的应用,其作用是替换xml文件中的占位符,替换为properties文件中相应的key对应的value值。
- 经验证BeanFactoryPostProcessor的postProcessBeanFactory方法执行时机比InstantiationAwareBeanPostProcessor的前置方法还要早,也就是说这个方法的执行时机早于前面的时序图的全部流程,是在最前面的,且只会执行一次,那么它的作用是什么呢,先看下示例代码如下:
@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("MyBeanFactoryPostProcessor的postProcessBeanFactory方法执行");
BeanDefinition beanDefinition = beanFactory.getBeanDefinition("bear");
beanDefinition.setLazyInit(true);
}
}
- 这里的ConfigurableListableBeanFactory方法参数,这个变量非常丰富,如下如图所示,因为这个阶段很早,我们就可以对bean的定义信息做修改,下面我来修改bean的加载时机(这里面其实可以修改很多东西,这里只做示例),
修改的代码在上面,我自定义一个Bear类,我在这里讲其设置为懒加载,我们知道在默认情况下,我没有给Bean添加Lazy注解的话是立即加载的,也就是在容器初始化就会创建bean,再看我下面的测试代码:
public class Test1 {
@Test
public void test01() {
ApplicationContext app = new AnnotationConfigApplicationContext(MainConfig1.class);
//1.打印IOC容器中所有的 实例对象名称
String[] names = app.getBeanDefinitionNames();
System.out.println("下面打印IOC容器中已经存在的Bean.. ");
for (String name : names) {
System.out.println(name);
}
System.out.println("下面打印IOC容器中已经存在的Bean完毕.. ");
System.out.println(app.getBean("bear").toString());
((AnnotationConfigApplicationContext) app).close();
}
}
- 按照我们的预期,在postProcessBeanFactory方法没有设置为懒加载之前,Bear的构造方法应该在遍历bean的名字之前执行,日志如下,是符合我们的预期的:
MyBeanFactoryPostProcessor的postProcessBeanFactory方法执行
Bear 带参构造方法执行...
下面打印IOC容器中已经存在的Bean..
mainConfig1
myBeanFactoryPostProcessor
bear
下面打印IOC容器中已经存在的Bean完毕..
Bear{name='myBear'}
- 我们设置为懒加载之后,日志如下,我们看到,我们在没有getBean(“bear”)之前,bean的构造方法没有被执行,说明是懒加载的,等遍历bean的name完毕之后执行app.getBean(“bear”)才执行了构造方法,因此我们验证了在BeanFactoryPostProcessor中修改bean的加载方式是有效的,当然这里面还可以修改其他的比如scop作用域等。
MyBeanFactoryPostProcessor的postProcessBeanFactory方法执行,
下面打印IOC容器中已经存在的Bean..
mainConfig1
myBeanFactoryPostProcessor
bear
下面打印IOC容器中已经存在的Bean完毕..
Bear 带参构造方法执行...
Bear{name='myBear'}
三、图示
-
下面是上述接口的调用时序
-
下面是上面代码的日志记录,和上面的时序是一样的
四、总结
- Bean的生命周期在刚开始看还是比较复杂的,前后接口子接口什么的非常多,我们按照上面的流程图,将Bean的生命周期先大致分为几个阶段,然后关注每个阶段有哪些扩展点。
- 实例化:InstantiationAwareBeanPostProcessor 在该阶段前后拦截,初始化之后还有
MergedBeanDefinitionPostProcessor接口,这个接口是实现@Autowire和@Value的关键,可以查看参考文档:04-spring AutowiredAnnotationBeanPostProcessor接口 - 初始化:BeanPostProcess 在该阶段前后拦截,初始化阶段过程中介绍了3种拦截方法
- 销毁阶段:主要是容器关闭的时候调用,也介绍了3种拦截方法
- 能力接口:就是Aware系列接口,会在初始化之前调用,也就是BeanPostProcess的Before方法之前
- 另外文中提到的@PostConstructor和PreDestroy并不是Spring中的内容,也一并带出了。