知识储备:Spring中Bean的生命周期(基于注解版)
一:前言在Spring项目中,通常配置Spring都是使用XML的形式进行配置,配置bean是通过<bean></bean>标签将bean加入IOC容器中,但在Spring注解版中,可以通过Java代码进行配置,即创建一个java类在其类头上标注@Configuration注解即表示当前类为一个配置类,作用相当于之前的.xml配置文件,那如何
一:前言
在Spring项目中,通常配置Spring都是使用XML的形式进行配置,配置bean是通过<bean></bean>标签将bean加入IOC容器中,但在Spring注解版中,可以通过Java代码进行配置,即创建一个java类在其类头上标注@Configuration注解即表示当前类为一个配置类,作用相当于之前的.xml配置文件,那如何将bean加入到IOC容器中呢,下面通过一小段代码了解一下。
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.ComponentScan.Filter;
import org.springframework.context.annotation.ComponentScans;
import org.springframework.stereotype.Controller;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.FilterType;
import com.peng.demo.bean.ColorFactoryBean;
import com.peng.demo.bean.Person;
import com.peng.demo.service.BookService;
/**
* @ComponentScan value指定要扫描的包
* @ComponentScan excludeFilters排除某些组件
* @ComponentScan includeFilters只需要包含某些组件
* @ComponentScan useDefaultFilters禁用默认规则
* FilterType.ANNOTATION按照注解
* FilterType.ASSIGNABLE_TYPE按照给定的类型
* FilterType.ASPECTJ按照ASPECTJ表达式的方式
* FilterType.REGEX正则表达式
* FilterType.CUSTOM自定义规则
*
*/
@Configuration
@ComponentScans(
@ComponentScan(value="com.peng",
/*excludeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
},*/
//useDefaultFilters 属性的默认值为 true,即使用默认的 Filter 进行包扫描,而默认的 Filter 对标有 @Service,@Controller和@Repository 的注解的类进行扫描
useDefaultFilters=false,
includeFilters= {
@Filter(type=FilterType.ANNOTATION,classes= {Controller.class})
/*@Filter(type=FilterType.ASSIGNABLE_TYPE,classes= {BookService.class}),
@Filter(type=FilterType.CUSTOM,classes= {MyTypeFilter.class})*/
}
)
)
public class MainConfig {
// @Bean(name="person1")//配置bean名称
@Bean
@Scope("singleton")
public Person person() {
return new Person("张三", 22);
}
}
注:@Configuration标注MainConfig为一个配置类,@ComponentScan标注基本包扫描相当于以前的<context:component-scan base-package=""></context:component-scan>,@ComponentScans内可以配置多个@ComponentScan。excludeFilters排除某些组件,includeFilters只需要包含某些组件,useDefaultFilters禁用默认规则。@Bean相当于之前的<bean></bean>标签,默认bean的id为方法名,@Scope("singleton")可以指定bean为单例或多实例。这里就不做过多的赘述了,读者可以根据xml配置,在配置类中一一尝试。
测试可见,person已经加入IOC容器中
public class TestMain {
public static void main(String[] args) {
ApplicationContext context=new AnnotationConfigApplicationContext(MainConfig.class);
Person person = context.getBean(Person.class);
System.out.println(person);
String[] beanNamesForType = context.getBeanNamesForType(Person.class);
for (String name : beanNamesForType) {
System.out.println(name);
}
}
}
二:bean的生命周期
bean的生命周期主要包括bean的创建,初始化,销毁
1.通过注解指定bean的初始化及销毁方法,在xml配置文件中可以通过init-method和destroy-method来配置bean的初始化及销毁方法:<bean id="" class="" init-method="" destroy-method=""></bean>,那么在注解中怎么使用呢?
@Bean注解提供initMethod和destroyMethod来指定bean的初始化和销毁方法。
创建一个类
public class Car {
public Car() {
System.out.println("Car创建啦!!!!!!!!!!!!!!!!!!!!");
}
public void init(){
System.out.println("Car init!!!!!!!!!!!!!!!!!");
}
public void destory(){
System.out.println("Car destory!!!!!!!!!!");
}
}
创建配置类
@Configuration
public class MainConfigOfLifeCycle {
@Bean(initMethod="init",destroyMethod="destory")
public Car car(){
return new Car();
}
}
编写测试代码
@Test
public void test1() {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfigOfLifeCycle.class);
String[] beanNamesForType = context.getBeanDefinitionNames();
for (String name : beanNamesForType) {
System.out.println(name);
}
context.close();
}
可以看见已经调用初始化及销毁方法
2.通过让bean实现InitializingBean接口定义初始化,实现DisposableBean定义销毁
创建类
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.stereotype.Component;
@Component
public class Cat implements InitializingBean,DisposableBean{
/**
* 初始化方法
*/
public void afterPropertiesSet() throws Exception {
System.out.println("Cat Init!!!!!!!!!!!!!!!");
}
/**
* 销毁方法
*/
public void destroy() throws Exception {
System.out.println("Cat destroy!!!!!!!!!!!!!!!");
}
}
注:这里使用@Component注解,所以需要在配置类上加@ComponentScan("com.peng.demo.bean")注解进行包扫描
测试发现Cat的初始化及销毁方法也调用了
3.使用JSR250的@PostConstruct注解标注在方法上,当bean创建完成并且赋值完成来初始化,@PreDestroy 当bean从容器移除之前,通知进行销毁
创建一个类
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import org.springframework.stereotype.Component;
@Component
public class Dog {
public Dog() {
System.out.println("Dog 创建!!!!!!!!!!!!!!!!!");
}
/**
*
* @Description 对象创建并赋值之后调用
*/
@PostConstruct
public void postConstruct(){
System.out.println("Dog PostConstruct!!!!!!!!!!!!");
}
/**
*
* @Description 当bean从IOC容器移除前调用
*/
@PreDestroy
public void destory(){
System.out.println("Dog PreDestroy!!!!!!!!!!!!");
}
}
测试发现Dog的初始化及销毁方法也调用了
4.通过BeanPostProcessor后置处理器,在bean初始化前后进行处理工作, postProcessBeforeInitialization()在初始化之前调用,postProcessAfterInitialization()在初始化之后调用
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessBeforeInitialization---"+beanName+"=>"+bean);
return bean;
}
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("postProcessAfterInitialization---"+beanName+"=>"+bean);
return bean;
}
}
运行测试发现在每个bean的初始化的前后都会调用相应的方法
三:后置处理器(BeanPostProcessor)源码分析
当我们自己定义一个类实现BeanPostProcessor接口后,将其加入到IOC容器中,后置处理器中的postProcessBeforeInitialization()和postProcessAfterInitialization()方法就会在bean的初始化方法的前后调用,通过debug就可以看到。在MyBeanPostProcessor的postProcessBeforeInitialization()方法上加一个断点,以debug运行测试方法就会发现
通过方法调用栈可以发现,首先进入refresh();方法,这里在刷新IOC容器
接着进入refresh()方法会看到调用了finishBeanFactoryInitialization()方法
接着跟进,底层在创建bean并返回
接着,底层就调用了initializeBean()方法,在调用initializeBean()之前会调用populateBean()这是在为bean的属性赋值,在initializeBean(0方法中,出现了最重要的三步
第一步,调用applyBeanPostProcessorsBeforeInitialization(),循环调用所有的后置处理器的postProcessBeforeInitialization()方法,一旦方法返回null就跳出循环
第二步,调用bean的初始化方法invokeInitMethods()。
第三步,调用applyBeanPostProcessorsAfterInitialization(),循环调用后置处理器的postProcessAfterInitialization()方法。
注:上述三步均是在populateBean()调用之后执行,也就是后置处理器及bean的初始化方法均是在bean赋值之后执行。
四:总结
至此整个bean的生命周期就完了,我们可以在bean的构造方法编写构造器的逻辑,然后到bean的初始化方法,在bean的初始化前后还有后置处理器的前后拦截方法,最后又bean的销毁方法,这就是spring为我们提供的bean控制的所有方法。
更多推荐
所有评论(0)