Bean的声明周期是指Bean创建➡️初始化➡️销毁的过程
XML配置注册Bean时,bean标签除了id class属性还有init-method和destroy-method,这两个方法就是配置bean的初始化方法和销毁方法
以Person实体类为例,增加初始化方法和销毁方法,自定义Bean初始化和销毁
public void init(){
System.out.println("Person Bean 初始化方法调用");
}
public void destroy(){
System.out.println("Person Bean 销毁方法调用");
}
在config包中定一个BeanLifeCycleConfig配置类,声明了initMethod和destroyMethod,注意不要加(),代码如下
@Configuration
public class BeanLifeCycleConfig {
@Bean(value = "stark", initMethod = "init", destroyMethod = "destroy")
public Person stark(){
System.out.println("stark被实例化");
Person person = new Person();
person.setName("stark");
person.setAge(40);
return person;
}
}
在test包中新增一个BeanLifeCycleTest
public class BeanLifeCycleTest {
@Test
public void getBeanByImport(){
ApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
System.out.println("IoC容器初始化完成");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
// 关闭容器
((AnnotationConfigApplicationContext)context).close();
}
}
执行测试
close()方法底层最终调用的是map的clear()方法,也就是清空map容器
容器入口类AnnotationConfigApplicationContext
容器创建Bean最终是调用的BeanUtils的instantiateClass()方法,该方法中使用了反射中的newInstance方法来实例化Bean
在配置类中@Bean注解中配置多实例
@Configuration
public class BeanLifeCycleConfig {
@Scope("prototype")
@Bean(value = "stark", initMethod = "init", destroyMethod = "destroy")
public Person stark(){
System.out.println("stark被实例化");
Person person = new Person();
person.setName("stark");
person.setAge(40);
return person;
}
}
执行测试,初始化和销毁方法都没有调用
多实例时只有调用getBean()方法时才会创建Bean,修改测试方法,增加获取Bean的代码
@Test
public void getBeanByImport(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
System.out.println("IoC容器初始化完成");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Person bean = context.getBean(Person.class);
// 关闭容器
context.close();
}
控制台打印如下,只调用了初始化方法
对于多实例的bean,容器只负责初始化, 但不会管理bean, 容器关闭时不会调用销毁方法
public class Item implements InitializingBean, DisposableBean {
private Integer id;
private String itemName;
public Item(Integer id, String itemName) {
System.out.println("Item 有参构造方法被调用");
this.id = id;
this.itemName = itemName;
}
public Integer getId() {
System.out.println("getId()方法被调用");
return id;
}
public void setId(Integer id) {
System.out.println("setId()方法被调用");
this.id = id;
}
public String getItemName() {
System.out.println("getItemName()方法被调用");
return itemName;
}
public void setItemName(String itemName) {
System.out.println("setItemName()方法被调用");
this.itemName = itemName;
}
public Item(){
System.out.println("Item 空参构造方法被调用");
}
// Bean销毁时调用
@Override
public void destroy() throws Exception {
System.out.println("Item Bean 销毁方法被调用");
}
// Bean属性赋值和初始化完成后调用
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("Item Bean 初始化方法被调用,属性被赋值后调用");
}
}
复制代码
修改BeanLifeCycleConfig配置类,增加@Import注解,把Item注册到IoC容器中
@Configuration
@Import(value = Item.class)
public class BeanLifeCycleConfig {
}
复制代码
注释BeanLifeCycleTest测试类方法中获取Person Bean的代码
public class BeanLifeCycleTest {
@Test
public void getBeanByImport(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
System.out.println("IoC容器初始化完成");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
// Person bean = context.getBean(Person.class);
// 关闭容器
context.close();
}
}
复制代码
执行测试,查看控制台打印结果
可以使用JSR250规则定义的(java规范)两个注解来实现
public class Address {
private Integer id;
private String addressDetail;
public Address() {
System.out.println("Address空参构造方法被调用");
}
public Address(Integer id, String addressDetail) {
System.out.println("Address有参数构造方法被调用");
this.id = id;
this.addressDetail = addressDetail;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getAddressDetail() {
return addressDetail;
}
public void setAddressDetail(String addressDetail) {
this.addressDetail = addressDetail;
}
@PostConstruct
public void init(){
System.out.println("Address Bean 的 @PostContruct注解形式的Bean初始化方法");
}
@PreDestroy
public void destroy(){
System.out.println("Address Bean 的 @PreDestry注解形式的Bean销毁方法");
}
}
复制代码
修改BeanLifeCycleConfig方法@Import注解,改@Import(Address.class),即往容器中注入Address Bean,BeanLifeCycleTest类不需要修改,直接执行测试方法,控制它打印如下
Bean的后置处理器,在bean初始化之前调用进行拦截,在bean初始化前后进行一些处理工作,使用BeanPostProcessor如何控制Bean的生命周期,实现BeanPostProcessor的两个接口即可
自定义类CustBeanPostProcessor,实现BeanPostProcessor
public class CustBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "postProcessBeforeInitialization前置处理器调用");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "postProcessAfterInitialization后置处理器调用");
return bean;
}
}
复制代码
修改BeanLifeCycleConfig,将自定义的CustBeanPostProcessor注册到容器中,在注册一些其他的Bean,Person是使用第一种生命周期定义方式,Item是第二种,Address是第三种,
@Configuration
//@Import(value = Item.class)
//@Import(value = Address.class)
@Import({CustBeanPostProcessor.class, Item.class, Address.class})
public class BeanLifeCycleConfig {
@Bean(initMethod = "init",destroyMethod = "destroy")
public Person person(){
System.out.println("Person Bean被实例化");
Person person = new Person();
person.setName("Stark");
person.setAge(40);
return person;
}
}
复制代码
执行测试类,确定postProcessBeforeInitialization(),postProcessAfterInitialization()是否支持这三种初始化方法前后调用
CustBeanPostProcessor的初始化前后拦截是针对容器中的所有业务Bean,不包括它本身
多实例情况下如何?修改BeanLifeCycleConfig,给Person添加多实例注解@Scope
@Configuration
//@Import(value = Item.class)
//@Import(value = Address.class)
@Import({CustBeanPostProcessor.class, Item.class, Address.class})
public class BeanLifeCycleConfig {
@Scope("prototype")
@Bean(initMethod = "init",destroyMethod = "destroy")
public Person person(){
System.out.println("Person Bean被实例化");
Person person = new Person();
person.setName("Stark");
person.setAge(40);
return person;
}
}
在打印方法中添加bean,将Bean实例也打印在控制台
public class CustBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "postProcessBeforeInitialization前置处理器调用" + bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName + "postProcessAfterInitialization后置处理器调用" + bean);
return bean;
}
}
在BeanLifeCycleTest中两次获取Person Bean
public class BeanLifeCycleTest {
@Test
public void getBeanByImport(){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanLifeCycleConfig.class);
System.out.println("IoC容器初始化完成");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Person bean = context.getBean(Person.class);
Person bean1 = context.getBean(Person.class);
// 关闭容器
context.close();
}
}
查看控制台打印
自定义CustBeanPostProcessor对初始化方法的前后拦截针对多实例Bean同样适用