侧边栏壁纸
博主头像
落叶人生博主等级

走进秋风,寻找秋天的落叶

  • 累计撰写 130562 篇文章
  • 累计创建 28 个标签
  • 累计收到 9 条评论
标签搜索

目 录CONTENT

文章目录

Spring SmartInitializingSingleton

2023-12-17 星期日 / 0 评论 / 0 点赞 / 23 阅读 / 5296 字

使用场景我们在这样的场景下使用,当ApplicationContext 加载完所有的Bean之后,我们来做一些我们想要的操作。下面是使用方法:public class MyRegister imple

使用场景

我们在这样的场景下使用,当ApplicationContext 加载完所有的Bean之后,我们来做一些我们想要的操作。下面是使用方法:

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 {}

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

  1. 这个接口的功能类似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),对应性能也会更好一点。

  1. 文档里说到 pre-instantiation phase 这个比较疑惑,实际上这里的pre-instantiation对应SmartInitializingSingleton的执行过程·
public abstract class AbstractApplicationContext extends DefaultResourceLoaderimplements 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;	}

广告 广告

评论区