网站建设计划表,郑州做网站公司天强科技,青岛企业网站建设公司,数字广东公司是国企吗前言这篇文章会重点分析一下SmartInitializingSingleton扩展点的功能 特性、实现方式 、工作原理。SmartInitializingSingleton扩展点内只有一个扩展方法#xff0c;且执行时机在Spring Bean的生命周期里比较靠后#xff0c;很重要#xff0c;但是也很简单。功能特性1、Smar…前言这篇文章会重点分析一下SmartInitializingSingleton扩展点的功能 特性、实现方式 、工作原理。SmartInitializingSingleton扩展点内只有一个扩展方法且执行时机在Spring Bean的生命周期里比较靠后很重要但是也很简单。功能特性1、SmartInitializingSingleton主要用于在Spring容器启动完成时进行扩展操作即afterSingletonsInstantiated()2、实现SmartInitializingSingleton接口的bean的作用域必须是单例afterSingletonsInstantiated()才会触发3、afterSingletonsInstantiated()触发执行时非懒加载的单例bean已经完成实现化、属性注入以及相关的初始化操作3、afterSingletonsInstantiated()的执行时机是在DefaultListableBeanFactory#preInstantiateSingletons()关于Spring bean有七种作用域默认singleton(单例)、prototype、request、session、globalSession、application、websocket1、singleton(单例)Spring容器只会创建一个bean对象2、prototype每次获取bean都会重新创建一个bean对象3、request对于每一个http请求在同一个请求内Spring容器只会创建一个bean对象若请求结束bean也随之销毁4、session在同一个http会话里Spring容器只会创建一个bean对象若传话结束也随之销毁5、globalSessionglobalSession作用域的效果与session作用域类似但是只适用于基于portlet的web应用程序中6、application在servlet程序中该作用域的bean将会作为ServletContext对象的属性被全局访问与singleton的区别就是singleton作用域的bean在Spring容器中只一application作用域的bean在ServletContex中唯一7、websocket为每个websocket对象创建一个实例。仅在Web相关的ApplicationContext中生效。实现方式 这里用一个示例验证SmartInitializingSingleton的功能特性并且通过debug分析其工作过程1、定义Dog类以setter注入方式进行属性注入同时Dog类实现SmartInitializingSingleton接口重写afterSingletonsInstantiated()并在方法内部打印日志如果在实际业务开发过程中用到了这个扩展点相关的扩展操作逻辑就是在这个方法内实现Slf4j
public class Dog implements InitializingBean, DisposableBean, SmartInitializingSingleton {private String name wang cai;private Food food;public Dog() {log.info(----Dog的无参构造方法被执行);}Autowiredpublic void setFood(Food food) {this.food food;log.info(----dog的food属性被注入);}Overridepublic void afterPropertiesSet() throws Exception {log.info(----com.fanfu.entity.Dog.afterPropertiesSet触发执行);}public void myInitMethod() {log.info(----com.fanfu.entity.Dog.myInitMethod触发执行);}Overridepublic void destroy() throws Exception {log.info(----com.fanfu.entity.Dog.destroy触发执行);}Overridepublic void afterSingletonsInstantiated() {log.info(----com.fanfu.entity.Dog.afterSingletonsInstantiated触发执行);}
}2、定义Food类作为Dog类的一个属性Slf4j
public class Food {private String name 大骨头;public Food() {log.info(----Food的无参数构造方法被执行);}
}3、使用Configuration配置类的方式注册Dog、Food到Spring容器里默认是单例对象Configuration
public class SpringConfig {Bean(initMethod myInitMethod)public Dog dog(){Dog dog new Dog();return dog;}Beanpublic Food food(){Food food new Food();return food;}
}4、单元测试用于验证结果 Testpublic void test5(){log.info(----单元测试执行开始);AnnotationConfigApplicationContext context new AnnotationConfigApplicationContext(com.fanfu);log.info(----单元测试执行完毕);}工作原理 如果我分享的关于Springboot扩展点系统的文章从头都一点一点自己debug看过的话一定对AbstractApplicationContext#refresh()不陌生与Spring容器启动相关的核心逻辑都在这个方法中。1、在AbstractApplicationContext#refresh()中会发现调用了finishBeanFactoryInitialization()从上面的注释可以看出这个方法昌要实例化所有非懒加载的单例bean2、进入到finishBeanFactoryInitialization()方法内做了一些beanFactory的准备工作后调用preInstantiateSingletons()开始非懒加载的单例bean实例化3、继续往下实际上是调用 了DefaultListableBeanFactory#preInstantiateSingletons()单独看这个方法逻辑相对简单分为两部分第一部分bean的实例化、属性注入、相关初始化操作第二部分找出所有实现了SmartInitializingSingleton接口的实现类遍历并执行afterSingletonsInstantiated()public void preInstantiateSingletons() throws BeansException {//----------start------------------实例化bean----------------------------------------if (logger.isTraceEnabled()) {logger.trace(Pre-instantiating singletons in this);}ListString beanNames new ArrayList(this.beanDefinitionNames);// Trigger initialization of all non-lazy singleton beans...for (String beanName : beanNames) {RootBeanDefinition bd getMergedLocalBeanDefinition(beanName);if (!bd.isAbstract() bd.isSingleton() !bd.isLazyInit()) {if (isFactoryBean(beanName)) {Object bean getBean(FACTORY_BEAN_PREFIX beanName);if (bean instanceof FactoryBean) {FactoryBean? factory (FactoryBean?) bean;boolean isEagerInit;if (System.getSecurityManager() ! null factory instanceof SmartFactoryBean) {isEagerInit AccessController.doPrivileged((PrivilegedActionBoolean) ((SmartFactoryBean?) factory)::isEagerInit,getAccessControlContext());}else {isEagerInit (factory instanceof SmartFactoryBean ((SmartFactoryBean?) factory).isEagerInit());}if (isEagerInit) {getBean(beanName);}}}else {getBean(beanName);}}}//----------end------------------实例化bean----------------------------------------//----------start------------------SmartInitializingSingleton#afterSingletonsInstantiated----------------------------------------for (String beanName : beanNames) {Object singletonInstance getSingleton(beanName);//判断单例bean是否实现了SmartInitializingSingleton接口if (singletonInstance instanceof SmartInitializingSingleton) {SmartInitializingSingleton smartSingleton (SmartInitializingSingleton) singletonInstance;if (System.getSecurityManager() ! null) {AccessController.doPrivileged((PrivilegedActionObject) () - {smartSingleton.afterSingletonsInstantiated();return null;}, getAccessControlContext());}else {//执行afterSingletonsInstantiated()smartSingleton.afterSingletonsInstantiated();}}}//----------start------------------SmartInitializingSingleton#afterSingletonsInstantiated----------------------------------------
}总结如果要在业务开发中使用SmartInitializingSingleton扩展点需要特别注意实现这个接口的bean应该是非懒加载的单例bean执行时机是在bean完成实例化、属性注入、相关初始化操作后否则无法触发执行。