Spring SmartInitializingSingleton

使用场景

我们在这样的场景下使用,当ApplicationContext

public class MyRegister implements SmartInitializingSingleton 
{ 
Logger logger = LoggerFactory.getLogger(MyRegister.class); 
private final DefaultListableBeanFactory beanFactory; 
public MyRegister(DefaultListableBeanFactory beanFactory) 
{ this.beanFactory = beanFactory; 
} 
@Override public void afterSingletonsInstantiated() 
{ 
Map<String, Tiger> redisCacheProviderMap = beanFactory.getBeansOfType(Tiger.class); 
logger.info("tiger pre init"); 
} 
}

接口说明

/** *<p> Callback interface triggered at the end of the singleton pre-instantiation phase * during 
{
@link BeanFactory}
 bootstrap. * * <p>This callback variant is somewhat similar to * 
{
@link org.springframework.context.event.ContextRefreshedEvent}
 but doesn't * require an implementation of 
{
@link org.springframework.context.ApplicationListener
}, * with no need to filter context references across a context hierarchy etc. * It also implies a more minimal dependency on just the 
{
@code beans
}
 package * and is being honored by standalone 
 {
 @link ListableBeanFactory} implementations, * not just in an 
{
@link org.springframework.context.ApplicationContext} environment. */ 
public interface SmartInitializingSingleton {}

主要摘取上面一段说明来解答疑惑:

这个接口的功能类似ContextRefreshedEvent(由ConfiguableApplicationContext.refresh()触发),ContextRefreshedEvent的具体阶段来看下面具体文档。

Published when the ApplicationContext is initialized or refreshed (for example, by using the refresh() method on the ConfigurableApplicationContext interface). Here, “initialized” means that all beans are loaded, post-processor beans are detected and activated, singletons are pre-instantiated, and the ApplicationContext object is ready for use. As long as the context has not been closed, a refresh can be triggered multiple times, provided that the chosen ApplicationContext actually supports such “hot” refreshes. For example, XmlWebApplicationContext supports hot refreshes, but GenericApplicationContext does not.

对比接收事件的优点:就是不需要实现ApplicationListener,引用也更加简单(不需要获取ApplicationContext),对应性能也会更好一点。

文档里说到 pre-instantiation phase 这个比较疑惑,实际上这里的pre-instantiation对应SmartInitializingSingleton的执行过程·

public abstract class AbstractApplicationContext extends DefaultResourceLoader implements ConfigurableApplicationContext, DisposableBean 
{ 
public void refresh() throws BeansException, IllegalStateException 
{ 
synchronized (this.startupShutdownMonitor) 
{ 
// 省略其他步骤......... 
// Instantiate all remaining (non-lazy-init) singletons. finishBeanFactoryInitialization(beanFactory); 
// Last step: publish corresponding event. finishRefresh(); 
} 
} finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) 
{ 
//省略其他步骤....... 
// Instantiate all remaining (non-lazy-init) singletons. beanFactory.preInstantiateSingletons(); 
}

所以结论就是SmartInitializingSingleton的方法就是在finishRefresh() 触发ContextRefreshedEvent事件前执行的。所以上面的pre-instantiation phase说的就是beanFactory.preInstantiateSingletons()这方法执行。

实现

beanFactory.preInstantiateSingletons();

// Trigger post-initialization callback for all applicable beans... for (String beanName : beanNames) 
{ 
Object singletonInstance = getSingleton(beanName); 
if (singletonInstance instanceof SmartInitializingSingleton) 
{
 final SmartInitializingSingleton smartSingleton = (SmartInitializingSingleton) singletonInstance; 
 if (System.getSecurityManager() != null) 
 { 
 AccessController.doPrivileged(new PrivilegedAction<Object>() 
 { 
 @Override public Object run() 
 { 
 smartSingleton.afterSingletonsInstantiated(); 
 return null; 
 } 
 }, getAccessControlContext()); 
 } 
 else 
 { 
 smartSingleton.afterSingletonsInstantiated();
  }
  }
  }

DefaultListableBeanFactory 这个类的实例是怎么构造注入的?构造函数注入。

另外的方法:Bean获取ApplicationContext是需要实现Aware接口的,类似这样:

//spring 
@EventListner 处理器 
public class EventListenerMethodProcessor implements SmartInitializingSingleton, ApplicationContextAware 
{ 
private ConfigurableApplicationContext applicationContext; 
@Override public void setApplicationContext(ApplicationContext applicationContext) throws BeansException 
{ 
Assert.isTrue(applicationContext instanceof ConfigurableApplicationContext, "ApplicationContext does not implement ConfigurableApplicationContext"); 
this.applicationContext = (ConfigurableApplicationContext) applicationContext; 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值