// 启动类
public class MainTest {
@Test
public void TestMain() {
// 创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
// applicationContext.getBean(“dog”);
applicationContext.close();
}
}
// 待注入的Bean
public class Dog {
public Dog(){
System.out.println(“dog create”);
}
public void init(){
System.out.println(“dog init”);
}
public void destroy(){
System.out.println(“dog destroy”);
}
}
// 配置类
@Configuration
public class AppConfig {
// @Scope(“prototype”)
// 通过@Bean注解指定初始化和销毁方法
@Bean(initMethod = “init”,destroyMethod = “destroy”)
public Dog dog(){
return new Dog();
}
}
这是单实例场景下的案例,单实例是在容器启动的时候实例化对象,容器关闭的时候进行销毁,可以看到,通过@Bean(initMethod = "init",destroyMethod = "destroy")
,可以指定初始化和销毁方法。
如果是多实例,将配置类中的@Scope("prototype")
放开,多实例是在获取对象的时候实例化对象,这时,直接运行启动类啥都不会打印,因为没有获取对象,也就没有初始化和销毁,因此需要将启动类中的applicationContext.getBean("dog");
放开,获取对象,此时运行启动类,进行了创建Bean和初始化Bean,而销毁则当对象长时间不用且没有其他对象引用时,由Java垃圾回收器回收。
【2】实现接口
将Bean对象实现InitializingBean, DisposableBean
接口,重写destroy和afterPropertiesSet方法进行销毁和初始化,注意要@Component
注解将Bean注入容器中,并在配置类中使用@ComponentScan
注解进行扫描,以cat对象为例子:
// 启动类
@Test
public void TestMain() {
// 创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
applicationContext.close();
}
// 待注入的Bean
@Component
public class Cat implements InitializingBean, DisposableBean {
public Cat(){
System.out.println(“cat create”);
}
// 销毁Bean
public void destroy() throws Exception {
System.out.println(“cat destroy”);
}
// 初始化Bean
public void afterPropertiesSet() throws Exception {
System.out.println(“cat afterPropertiesSet”);
}
}
// 配置类
@ComponentScan(“bean”)
@Configuration
public class AppConfig {
}
实现InitializingBean, DisposableBean
接口,重写destroy和afterPropertiesSet方法进行销毁和初始化,可以看到进行初始化和销毁:
【3】使用JSR250注解规范
使用JSR250注解规范,通过@PostConstruct
注解和@PreDestroy
注解进行对象的创建赋值调用和销毁对象,以pig对象为例:
// 启动类
@Test
public void TestMain() {
// 创建IOC容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
applicationContext.close();
}
// 待注入的Bean
@Component
public class Pig {
public Pig(){
System.out.println(“pig create”);
}
// @PostConstruct:对象创建并赋值之后调用
@PostConstruct
public void init(){
System.out.println(“pig postConstruct”);
}
// @PreDestroy:容器移除对象之前
@PreDestroy
public void destroy(){
System.out.println(“pig destroy”);
}
}
// 配置类
@ComponentScan(“bean”)
@Configuration
public class AppConfig {
}
使用@PostConstruct
注解作用来初始化方法上面,@PreDestroy
注解作用在销毁方法上面,运行启动类,可以看到进行初始化和销毁:
【4】后置处理器
后置处理器是在Bean初始化前后进行一些处理工作,实现BeanPostProcessor
类,重写方法,postProcessBeforeInitialization
在初始化之前工作,postProcessAfterInitialization
在初始化之后工作,在pig对象实例中添加:
@Component // 将后置处理器加入到容器中
public class MyBeanPostProcessor implements BeanPostProcessor {
// postProcessBeforeInitialization:在初始化之前工作
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“postProcessBeforeInitialization” + beanName + “===” + bean);
return bean;
}
// postProcessAfterInitialization:在初始化之后工作
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println(“postProcessAfterInitialization” + beanName + “===” + bean);
return bean;
}
}
在pig对象初始化前后执行相应的代码,运行结果如下:
三、源码追踪
在spring源码中,BeanPostProcessor后置处理器是一个非常重要的类,我们来看看spring底层是如何实现Bean初始化的
【1】刷新容器
IOC容器构造器调用refresh
方法刷新容器
public AnnotationConfigApplicationContext(String… basePackages) {
this();
this.scan(basePackages);
// 刷新容器
this.refresh();
}
【2】获取实例
调用refresh
中的finishBeanFactoryInitialization
方法初始化所有单实例对象
public void refresh() throws BeansException, IllegalStateException {
synchronized(this.startupShutdownMonitor) {
StartupStep contextRefresh = this.applicationStartup.start(“spring.context.refresh”);
this.prepareRefresh();
ConfigurableListableBeanFactory beanFactory = this.obtainFreshBeanFactory();
this.prepareBeanFactory(beanFactory);
try {
this.postProcessBeanFactory(beanFactory);
StartupStep beanPostProcess = this.applicationStartup.start(“spring.context.beans.post-process”);
this.invokeBeanFactoryPostProcessors(beanFactory);
this.registerBeanPostProcessors(beanFactory);
beanPostProcess.end();
this.initMessageSource();
this.initApplicationEventMulticaster();
this.onRefresh();
this.registerListeners();
// 初始化所有单实例对象
this.finishBeanFactoryInitialization(beanFactory);
this.finishRefresh();
} catch (BeansException var10) {
if (this.logger.isWarnEnabled()) {
this.logger.warn("Exception encountered during context initialization - cancelling refresh attempt: " + var10);
}
this.destroyBeans();
this.cancelRefresh(var10);
throw var10;
} finally {
this.resetCommonCaches();
contextRefresh.end();
}
}
}
-
到
preInstantiateSingletons
类中调用getBean
方法 -
调用
doGetBean
-
调用
getSingleton
获取单实例 -
如果获取不到则调用
createBean
创建实例
this.getBean(beanName);
public Object getBean(String name) throws BeansException {
return this.doGetBean(name, (Class)null, (Object[])null, false);
}
if (mbd.isSingleton()) {
// 获取单实例
sharedInstance = this.getSingleton(beanName, () -> {
try {
// 如果获取不到则调用createBean创建实例
return this.createBean(beanName, mbd, args);
} catch (BeansException var5) {
this.destroySingleton(beanName);
throw var5;
}
});
bean = this.getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
// 创建实例
beanInstance = this.doCreateBean(beanName, mbdToUse, args);
【3】创建实例
如何创建的呢,我们继续看源码,追踪到doCreateBean
类中的initializeBean
方法,在这个方法之前有个populateBean
方法
-
populateBean:为Bean属性赋值
-
initializeBean:相当于后置处理器的调用
try {
// 为Bean属性赋值
this.populateBean(beanName, mbd, instanceWrapper);
// 相当于后置处理器的调用
exposedObject = this.initializeBean(beanName, exposedObject, mbd);
} catch (Throwable var18) {
if (var18 instanceof BeanCreationException && beanName.equals(((BeanCreationException)var18).getBeanName())) {
throw (BeanCreationException)var18;
}
throw new BeanCreationException(mbd.getResourceDescription(), beanName, “Initialization of bean failed”, var18);
}
调用initializeBean
方法中的invokeInitMethods
方法执行初始化方法,在上面提到的实现接口、使用注解、自定义初始化都是在这个方法中执行的,注意看这个方法的前后:
-
applyBeanPostProcessorsBeforeInitialization
-
applyBeanPostProcessorsAfterInitialization
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(() -> {
this.invokeAwareMethods(beanName, bean);
return null;
}, this.getAccessControlContext());
} else {
this.invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
最后
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。
深知大多数Java工程师,想要提升技能,往往是自己摸索成长,自己不成体系的自学效果低效漫长且无助。
因此收集整理了一份《2024年Java开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
[外链图片转存中…(img-4fwX9FyL-1715618149707)]
[外链图片转存中…(img-tn5b0Ymq-1715618149707)]
[外链图片转存中…(img-KbU0tDCN-1715618149707)]
既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Java开发知识点,不论你是刚入门Java开发的新手,还是希望在技术上不断提升的资深开发者,这些资料都将为你打开新的学习之门!
如果你觉得这些内容对你有帮助,需要这份全套学习资料的朋友可以戳我获取!!
由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!