给容器中注入组件的方式
- 包扫描+组件标注注解(@Controller/@Service/@Repository/@Component)
- @Bean[导入的第三方包里面的组件]
- @Import【快速的给容器中导入一个组件】
- @Import(要导入容器中的组件);容器就会注入这个类,id是class的全限类名
- 实现ImportSelector接口:返回需要导入的组名的全限类名
- 实现ImportBeanDefinitionRegistrar接口:手动注册Bean到容器中
- 使用Spring提供的FactoryBean(工厂Bean)
- 默认获取到的是工厂Bean调用getObject创建的对象
- 想要获取工厂Bean本身,需要在getBean的时候,id最前面加&标志符
Bean的生命周期
Bean的生命周期: bean创建—初始化—销毁 的过程
容器管理Bean的生命周期
我们可以自定义初始化和销毁方法,容器在Bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法
Bean经历的基本过程:
- 构造(对象创建):
单实例:在容器启动的时候创建对象
多实例:在每次获取的时候创建对象
BeanPostProcessor.postProcessBeforeInitialization
- 初始化:
对象创建完成,并赋值后,调用初始化方法
BeanPostProcessor.postProcessAfterInitialization
- 销毁:
单实例:在容器关闭的时候调用销毁方法
多实例:容器不会管理这个Bean,容器不会调用销毁方法
自定义Bean初始化销毁方法
- 指定Bean 的初始化和销毁方法==>指定init-method和destroy-method
@Bean(initMethod = "init",destroyMethod = "destroy")
- 通过让Bean实现
InitializingBean
接口的afterPropertiesSet
方法定义初始化逻辑;实现DisposableBean
接口的destroy
方法定义销毁逻辑 - 可以使用JSR250:
- @PostConstruct:在Bean创建完成并且属性赋值完成后,执行初始化方法
- @PreDestroy:在容器销毁之前调用
- BeanPostProcessor:Bean的后置处理器;在Bean的初始化前后进行一些处理工作
postProcessBeforeInitialization
在初始化之前调用postProcessAfterInitialization
在初始化之后调用
demo测试
- 创建一个MyBeanPostProcessor类实现BeanPostProcessor接口
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"初始化之前=>"+bean.getClass());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(beanName+"初始化之后=>"+bean.getClass());
return bean;
}
}
- 创建一个类Cat,注入到Spring中
@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...init...");
}
}
- 创建一个配置类MyConfig
@Configuration
@ComponentScan("com.yang.lifecycle")
public class MyConfig {
}
- 最后是测试类Test
public class MyTest {
@Test
public void yangTest(){
AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(MyConfig.class);
ac.close();
}
}
- 运行结果
myConfig初始化之前=>class com.yang.lifecycle.config.MyConfig$$EnhancerBySpringCGLIB$$51ed062e
myConfig初始化之后=>class com.yang.lifecycle.config.MyConfig$$EnhancerBySpringCGLIB$$51ed062e
cat...constructor
cat初始化之前=>class com.yang.lifecycle.bean.Cat
cat...init...
cat初始化之后=>class com.yang.lifecycle.bean.Cat
cat...destroy...
Spring源码探究
老规矩我们需要打一个断点来查看,这里主要是要看源码中是在什么时候执行后置处理器的回调
- 第一步
createBean#doCreateBean(beanName, mbdToUse, args)
(前面的一些先忽略)
protected Object doCreateBean(String beanName, RootBeanDefinition mbd, @Nullable Object[] args)
throws BeanCreationException {
// Instantiate the bean. 实例化Bean对象,注意这里只是对象,不是Bean
......
// Allow post-processors to modify the merged bean definition.
......
// Eagerly cache singletons to be able to resolve circular references
// even when triggered by lifecycle interfaces like BeanFactoryAware.
......
// Initialize the bean instance.初始化Bean实例
Object exposedObject = bean;
try {
//Bean对象属性赋值
populateBean(beanName, mbd, instanceWrapper);
//初始化Bean;这里可以看出,初始化Bean是在属性赋值之后进行的
exposedObject = initializeBean(beanName, exposedObject, mbd);
}
......
return exposedObject;
}
- 第二步
doCreateBean#initializeBean(beanName, exposedObject, mbd)
,从这段代码可以看出BeanPostProcessor的调用顺序
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
......忽略
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
//1、调用初始化前方法BeanPostProcessor#postProcessBeforeInitialization(result, beanName)
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
//2、调用Bean初始化方法
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
//3、调用初始化前方法BeanPostProcessor#postProcessAfterInitialization(result, beanName)
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}