3.生命周期
3.1. @Bean
指定初始化和销毁方法
首先,定义一个Car类:
package com.hutu.bean;
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 ...");
}
}
配置类:MainConfigOfLifeCycle
package com.hutu.config;
import com.hutu.bean.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* bean的生命周期:bean的创建->初始化->销毁的过程
* 容器管理bean的生命周期:
* 可以自定义初始化方法和销毁的方法:容器在bean进行到当前的生命周期的时候,来调用我们自定义的初始化方法和销毁方法
*
* 构造(对象创建):
* -- 单实例:在容器启动的时候创建对象
* -- 多实例:在每次获取的时候来创建对象
* 初始化方法:
* -- 对象创建完成,并赋值好,调用初始化方法
* 销毁方法:
* -- 单实例的bean:在容器关闭的时候进行销毁
* -- 多实例的bean:容器不会管理这个bean,容器不会调用销毁的方法
* <p>
* 1)指定初始化方法和销毁方法;
* 可以通过@Bean(initMethod = "init",destroyMethod = "destroy")来指定初始化方法和销毁方法
* 相当于xml配置文件bean标签里面的 init-method="" 和 destroy-method="" 属性
*/
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
测试
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
}
此时,还没有关闭IOC容器的时候,运行结果为
car constructor...
car ... init ...
容器创建完成
而当调用了容器的close方法关闭容器的时候:
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
context.close();
}
测试的运行结果为:
car constructor...
car ... init ...
容器创建完成
car ... destroy ...
而当bean的作用域为多例的时候:
@Configuration
public class MainConfigOfLifeCycle {
@Scope("prototype")
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
再次测试
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
context.close();
}
测试结果
容器创建完成
当bean的作用域为多例的时候,只有在获取的时候,才会创建对象,而且在IOC容器关闭的时候,是不进行销毁的 :
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
Object car = context.getBean("car");
context.close();
}
测试结果
容器创建完成
car constructor...
car ... init ...
3.2. InitializingBean
和DisposableBean
InitializingBean接口:在bean的初始化方法调用之后进行调用
package org.springframework.beans.factory;
public interface InitializingBean {
/**
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
* <p>This method allows the bean instance to perform validation of its overall
* configuration and final initialization when all bean properties have been set.
* @throws Exception in the event of misconfiguration (such as failure to set an
* essential property) or if initialization fails for any other reason
*/
void afterPropertiesSet() throws Exception;
}
DisposableBean 接口
package org.springframework.beans.factory;
public interface DisposableBean {
/**
* Invoked by the containing {@code BeanFactory} on destruction of a bean.
* @throws Exception in case of shutdown errors. Exceptions will get logged
* but not rethrown to allow other beans to release their resources as well.
*/
void destroy() throws Exception;
}
cat类:实现这两个接口
package com.hutu.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
public class Car implements InitializingBean, DisposableBean {
public Car() {
System.out.println("car constructor...");
}
public void init() {
System.out.println("car ... init ...");
}
@Override
public void destroy() {
System.out.println("car ... destroy ...");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Cat...afterPropertiesSet...");
}
}
用包扫描的方式来进行装配
@Configuration
@ComponentScan("com.hutu.bean")
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
测试
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
context.close();
}
测试结果
car constructor...
Cat...afterPropertiesSet...
car ... init ...
容器创建完成
car ... destroy ...
3.3. @PostConstruct
&@PreDestroy
可以使用JSR250规范里面定义的两个注解:
-
@PostConstruct :在bean创建完成并且属性赋值完成,来执行初始化方法
-
@PreDestroy :在容器销毁bean之前通知我们来进行清理工作
@PostConstruct
:在bean创建完成并且属性赋值完成,来执行初始化方法
@PreDestroy
:在容器销毁bean之前通知我们来进行清理工作
定义一个Dog类
package com.hutu.bean;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Dog {
public Dog() {
System.out.println("Dog...Contructor...");
}
//在对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("Dog...@PostConstruct...");
}
//在对象创建并赋值之后调用
@PreDestroy
public void destroy() {
System.out.println("Dog...@PreDestroy...");
}
}
再来运行这个测试方法:
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
context.close();
}
测试结果
Dog...Contructor...
Dog...@PostConstruct...
car constructor...
Cat...afterPropertiesSet...
car ... init ...
容器创建完成
car ... destroy ...
Dog...@PreDestroy...
3.4. BeanPostProcessor
-后置处理器
BeanPostProcessor接口:bean的后置处理器,在bean初始化前后做一些处理工作,这个接口有两个方法:
-
postProcessBeforeInitialization:在初始化之前工作
-
postProcessAfterInitialization:在初始化之后工作
BeanPostProcessor接口
package org.springframework.beans.factory.config;
import org.springframework.beans.BeansException;
import org.springframework.lang.Nullable;
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;
}
}
同样,还是使用包扫描的方式来进行装配:
@Configuration
@ComponentScan("com.hutu.bean")
@ComponentScan("com.hutu.config")
public class MainConfigOfLifeCycle {
@Bean(initMethod = "init", destroyMethod = "destroy")
public Car car() {
return new Car();
}
}
写一个类并且实现这个后置处理器接口 BeanPostProcessor :
package com.hutu.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@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;
}
}
测试
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
context.close();
}
测试结果
通过自定义的匹配规则--->com.hutu.test.MainTest
通过自定义的匹配规则--->com.hutu.test.MainTest01
通过自定义的匹配规则--->com.hutu.bean.Blue
通过自定义的匹配规则--->com.hutu.bean.Car
通过自定义的匹配规则--->com.hutu.bean.Color
通过自定义的匹配规则--->com.hutu.bean.Dog
通过自定义的匹配规则--->com.hutu.bean.Person
通过自定义的匹配规则--->com.hutu.bean.RainBow
通过自定义的匹配规则--->com.hutu.bean.Red
通过自定义的匹配规则--->com.hutu.bean.Yellow
通过自定义的匹配规则--->com.hutu.config.ColorFactoryBean
通过自定义的匹配规则--->com.hutu.config.LinuxCondition
通过自定义的匹配规则--->com.hutu.config.MainConfig2
通过自定义的匹配规则--->com.hutu.config.MainConfigOfLifeCycle
通过自定义的匹配规则--->com.hutu.config.MyBeanPostProcessor
通过自定义的匹配规则--->com.hutu.config.MyImportBeanDefinitionRegistrar
通过自定义的匹配规则--->com.hutu.config.MyImportSelector
通过自定义的匹配规则--->com.hutu.config.MyTypeFilter
通过自定义的匹配规则--->com.hutu.config.WindowsCondition
通过自定义的匹配规则--->com.hutu.controller.BookController
通过自定义的匹配规则--->com.hutu.dao.BookDao
通过自定义的匹配规则--->com.hutu.service.BookService
postProcessBeforeInitialization...mainConfigOfLifeCycle=>com.hutu.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$58dbf743@50a638b5
postProcessAfterInitialization...mainConfigOfLifeCycle=>com.hutu.config.MainConfigOfLifeCycle$$EnhancerBySpringCGLIB$$58dbf743@50a638b5
Dog...Contructor...
postProcessBeforeInitialization...dog=>com.hutu.bean.Dog@1725dc0f
Dog...@PostConstruct...
postProcessAfterInitialization...dog=>com.hutu.bean.Dog@1725dc0f
postProcessBeforeInitialization...mainConfig=>com.hutu.config.MainConfig$$EnhancerBySpringCGLIB$$d6ed4678@3911c2a7
postProcessAfterInitialization...mainConfig=>com.hutu.config.MainConfig$$EnhancerBySpringCGLIB$$d6ed4678@3911c2a7
postProcessBeforeInitialization...mainConfig2=>com.hutu.config.MainConfig2$$EnhancerBySpringCGLIB$$5b037c42@4ac3c60d
postProcessAfterInitialization...mainConfig2=>com.hutu.config.MainConfig2$$EnhancerBySpringCGLIB$$5b037c42@4ac3c60d
postProcessBeforeInitialization...person=>Person(name=null, age=null)
postProcessAfterInitialization...person=>Person(name=null, age=null)
postProcessBeforeInitialization...myTypeFilter=>com.hutu.config.MyTypeFilter@76508ed1
postProcessAfterInitialization...myTypeFilter=>com.hutu.config.MyTypeFilter@76508ed1
postProcessBeforeInitialization...bookController=>com.hutu.controller.BookController@41e36e46
postProcessAfterInitialization...bookController=>com.hutu.controller.BookController@41e36e46
postProcessBeforeInitialization...bookService=>com.hutu.service.BookService@15c43bd9
postProcessAfterInitialization...bookService=>com.hutu.service.BookService@15c43bd9
postProcessBeforeInitialization...person666=>Person(name=小糊涂仙, age=20)
postProcessAfterInitialization...person666=>Person(name=小糊涂仙, age=20)
postProcessBeforeInitialization...com.hutu.bean.Color=>com.hutu.bean.Color@188715b5
postProcessAfterInitialization...com.hutu.bean.Color=>com.hutu.bean.Color@188715b5
postProcessBeforeInitialization...com.hutu.bean.Red=>com.hutu.bean.Red@1ea9f6af
postProcessAfterInitialization...com.hutu.bean.Red=>com.hutu.bean.Red@1ea9f6af
postProcessBeforeInitialization...com.hutu.bean.Blue=>com.hutu.bean.Blue@6a192cfe
postProcessAfterInitialization...com.hutu.bean.Blue=>com.hutu.bean.Blue@6a192cfe
postProcessBeforeInitialization...com.hutu.bean.Yellow=>com.hutu.bean.Yellow@5119fb47
postProcessAfterInitialization...com.hutu.bean.Yellow=>com.hutu.bean.Yellow@5119fb47
postProcessBeforeInitialization...bill=>Person(name=Bill Gates, age=28)
postProcessAfterInitialization...bill=>Person(name=Bill Gates, age=28)
postProcessBeforeInitialization...linux=>Person(name=linus, age=19)
postProcessAfterInitialization...linux=>Person(name=linus, age=19)
postProcessBeforeInitialization...colorFactoryBean=>com.hutu.config.ColorFactoryBean@1dde4cb2
postProcessAfterInitialization...colorFactoryBean=>com.hutu.config.ColorFactoryBean@1dde4cb2
postProcessBeforeInitialization...rainBow=>com.hutu.bean.RainBow@393671df
postProcessAfterInitialization...rainBow=>com.hutu.bean.RainBow@393671df
car constructor...
postProcessBeforeInitialization...car=>com.hutu.bean.Car@55b7a4e0
Cat...afterPropertiesSet...
car ... init ...
postProcessAfterInitialization...car=>com.hutu.bean.Car@55b7a4e0
容器创建完成
car ... destroy ...
Dog...@PreDestroy...
3.5. BeanPostProcessor
原理
在这个后置处理器的两个方法上面打上断点
以debug的方式来运行这个测试方法
前置处理器调用的方法:
调用getBeanPostProcessors()方法找到容器里面的所有的BeanPostProcessor,挨个遍历,调用BeanPostProcessor的postProcessBeforeInitialization方法,一旦调用postProcessBeforeInitialization方法的返回值为null的时候,就直接跳出遍历 ,后面的BeanPostProcessor 的postProcessBeforeInitialization也就不会执行了:
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessBeforeInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
后置处理器调用的方法:
调用getBeanPostProcessors()方法找到容器里面的所有的BeanPostProcessor,挨个遍历,调用BeanPostProcessor的postProcessAfterInitialization方法,一旦调用postProcessAfterInitialization方法的返回值为null的时候,就直接跳出遍历 ,后面的BeanPostProcessor 的postProcessAfterInitialization也就不会执行了:
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
throws BeansException {
Object result = existingBean;
for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
result = beanProcessor.postProcessAfterInitialization(result, beanName);
if (result == null) {
return result;
}
}
return result;
}
//前置处理器执行 wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); //初始化方法执行 invokeInitMethods(beanName, wrappedBean, mbd); //后置处理器执行 wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
在看源码的时候,可以发现: 在执行exposedObject = initializeBean(beanName, exposedObject, mbd);方法之前先调用了populateBean(beanName, mbd, instanceWrapper);这个方法:
populateBean(beanName, mbd, instanceWrapper);–给bean进行属性赋值 exposedObject = initializeBean(beanName, exposedObject, mbd);–初始化方法,在这个初始化方法内部包括了前置处理器、初始化方法、后置处理器的调用
3.6. BeanPostProcessor
在Spring底层的使用
Spring底层对 BeanPostProcessor 的使用:
-
bean赋值,注入其他组件,
@Autowired
,生命周期注解等功能,@Async
等等都是使用BeanPostProcessor
来完成的
BeanPostProcessor 这个接口有很多的实现类
如果我们想要获取IOC容器,可以这样做:
package com.hutu.bean;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
@Component
public class Dog implements ApplicationContextAware {
private ApplicationContext applicationContext;
public Dog() {
System.out.println("Dog...Contructor...");
}
//在对象创建并赋值之后调用
@PostConstruct
public void init() {
System.out.println("Dog...@PostConstruct...");
}
//在对象创建并赋值之后调用
@PreDestroy
public void destroy() {
System.out.println("Dog...@PreDestroy...");
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
可以debug来调试
还可以debug运行这个测试方法
@Test
public void test01() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
System.out.println("容器创建完成");
context.close();
}
实际上BeanPostProcessor接口还有很多的实现类,比如说BeanValidationPostProcessor,这个是用来做数据校验的:
像InitDestroyAnnotationBeanPostProcessor这个实现类就是实现了@PostConstruct和@PreDestroy这两个注解的功能:
在这个地方打个断点