学无先后,达者为师

网站首页 编程语言 正文

SpringBoot中的SmartInitializingSingleton接口的使用

作者:神笔码靓 更新时间: 2022-07-13 编程语言

一、说明

SmartInitializingSingleton 接口的 afterSingletonsInstantiated()方法类似bean实例化执行后的回调函数。
afterSingletonsInstantiated 会在spring 容器基本启动完成后执行。此时所有的单列bean都已初始化完成。实现了SmartInitializingSingleton 接口的类
可以在afterSingletonsInstantiated 中做一些回调操作。

二、XXL-JOB 中SmartInitializingSingleton 的使用

xxl-job 是一个轻量级的分布式任务调度框架,通过一个中心式的调度平台,调度多个执行器执行任务,而且监控界面就集成在调度中心,界面又简洁。

xxl-job中, XxlJobSpringExecutor,XxlJobSimpleExecutor 继承自 XxlJobExecutor 同时也实现了 SmartInitializingSingleton 接口。
XxlJobSpringExecutor 在 afterSingletonsInstantiated() 方法中,完成了提取 @XxlJob 注解标注的方法,用于后续任务的执行。调用父类方法中的start() 方法,初始化netty服务器。

public class XxlJobSpringExecutor extends XxlJobExecutor implements ApplicationContextAware, SmartInitializingSingleton, DisposableBean {
    private static final Logger logger = LoggerFactory.getLogger(XxlJobSpringExecutor.class);


    // start
    @Override
    public void afterSingletonsInstantiated() {

        // init JobHandler Repository
        /*initJobHandlerRepository(applicationContext);*/

        // init JobHandler Repository (for method)
        initJobHandlerMethodRepository(applicationContext);

        // refresh GlueFactory
        GlueFactory.refreshInstance(1);

        // super start
        try {
            super.start();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
	/// 其他代码 省略
}

父类中的start() 方法:initEmbedServer 用于初始化netty服务。


    // ---------------------- start + stop ----------------------
    public void start() throws Exception {

        // init logpath
        XxlJobFileAppender.initLogPath(logPath);

        // init invoker, admin-client
        initAdminBizList(adminAddresses, accessToken);


        // init JobLogFileCleanThread
        JobLogFileCleanThread.getInstance().start(logRetentionDays);

        // init TriggerCallbackThread
        TriggerCallbackThread.getInstance().start();

        // init executor-server 初始化netty 服务
        initEmbedServer(address, ip, port, appname, accessToken);
    }

获取容器中被@XxlJob 注解标注的方法的实现方法:


    private void initJobHandlerMethodRepository(ApplicationContext applicationContext) {
        if (applicationContext == null) {
            return;
        }
        // init job handler from method
        String[] beanDefinitionNames = applicationContext.getBeanNamesForType(Object.class, false, true);
        for (String beanDefinitionName : beanDefinitionNames) {
            Object bean = applicationContext.getBean(beanDefinitionName);

            Map<Method, XxlJob> annotatedMethods = null;   // referred to :org.springframework.context.event.EventListenerMethodProcessor.processBean
            try {
                annotatedMethods = MethodIntrospector.selectMethods(bean.getClass(),
                        new MethodIntrospector.MetadataLookup<XxlJob>() {
                            @Override
                            public XxlJob inspect(Method method) {
                                return AnnotatedElementUtils.findMergedAnnotation(method, XxlJob.class);
                            }
                        });
            } catch (Throwable ex) {
                logger.error("xxl-job method-jobhandler resolve error for bean[" + beanDefinitionName + "].", ex);
            }
            if (annotatedMethods==null || annotatedMethods.isEmpty()) {
                continue;
            }

            for (Map.Entry<Method, XxlJob> methodXxlJobEntry : annotatedMethods.entrySet()) {
                Method executeMethod = methodXxlJobEntry.getKey();
                XxlJob xxlJob = methodXxlJobEntry.getValue();
                // regist
                registJobHandler(xxlJob, bean, executeMethod);
            }
        }
    }

使用时和其他框架差不多,在@Configuraton 修饰的配置类中返回一个示例化的bean即可。


@Configuration
public class XxlJobConfig {
    @Bean
    public XxlJobSpringExecutor xxlJobExecutor() {
        logger.info(">>>>>>>>>>> xxl-job config init.");
        XxlJobSpringExecutor xxlJobSpringExecutor = new XxlJobSpringExecutor();
        xxlJobSpringExecutor.setAdminAddresses(adminAddresses);
        xxlJobSpringExecutor.setAppname(appname);
        xxlJobSpringExecutor.setAddress(address);
        xxlJobSpringExecutor.setIp(ip);
        xxlJobSpringExecutor.setPort(port);
        xxlJobSpringExecutor.setAccessToken(accessToken);
        xxlJobSpringExecutor.setLogPath(logPath);
        xxlJobSpringExecutor.setLogRetentionDays(logRetentionDays);

        return xxlJobSpringExecutor;
    }
}

三、spring 容器中 SmartInitializingSingleton 的使用

EventListenerMethodProcessor也实现了 SmartInitializingSingleton 接口,主要用于完成@EventListener注解方式的事件监听。
在afterSingletonsInstantiated() 方法中处理逻辑与xxl-job 中的类似,都是用于筛选实例中被指定注解修饰的方法。

public class EventListenerMethodProcessor
		implements SmartInitializingSingleton, ApplicationContextAware, BeanFactoryPostProcessor {

	
	@Override
	public void afterSingletonsInstantiated() {
		ConfigurableListableBeanFactory beanFactory = this.beanFactory;
		Assert.state(this.beanFactory != null, "No ConfigurableListableBeanFactory set");
		String[] beanNames = beanFactory.getBeanNamesForType(Object.class);
		for (String beanName : beanNames) {
			if (!ScopedProxyUtils.isScopedTarget(beanName)) {
				Class<?> type = null;
				try {
					type = AutoProxyUtils.determineTargetClass(beanFactory, beanName);
				}
				catch (Throwable ex) {
					// An unresolvable bean type, probably from a lazy bean - let's ignore it.
					if (logger.isDebugEnabled()) {
						logger.debug("Could not resolve target class for bean with name '" + beanName + "'", ex);
					}
				}
				if (type != null) {
					if (ScopedObject.class.isAssignableFrom(type)) {
						try {
							Class<?> targetClass = AutoProxyUtils.determineTargetClass(
									beanFactory, ScopedProxyUtils.getTargetBeanName(beanName));
							if (targetClass != null) {
								type = targetClass;
							}
						}
						catch (Throwable ex) {
							// An invalid scoped proxy arrangement - let's ignore it.
							if (logger.isDebugEnabled()) {
								logger.debug("Could not resolve target bean for scoped proxy '" + beanName + "'", ex);
							}
						}
					}
					try {
						processBean(beanName, type);
					}
					catch (Throwable ex) {
						throw new BeanInitializationException("Failed to process @EventListener " +
								"annotation on bean with name '" + beanName + "'", ex);
					}
				}
			}
		}
	}

}

写在最后

以上两个使用的方式都是在spring容器 单列被加载完成后,处理一些自定义的逻辑。EventListenerMethodProcessor主要用于筛选出被@EventListener
注解的方法,在后续的使用中 通过 发布-订阅模式,实现事件的监听。

XxlJobSpringExecutor 主要用于筛选出被@XxlJob 注解标注的方法,用于后续任务的启动和停止。

原文链接:https://blog.csdn.net/daxues_/article/details/125750267

栏目分类
最近更新