1. Description
The afterSingletonsInstantiated() method of the SmartInitializingSingleton interface is similar to the callback function after the bean instantiation is executed.
afterSingletonsInstantiated will be executed after the spring container is basically started. At this point all single-column bean s have been initialized. A class that implements the SmartInitializingSingleton interface
You can do some callback operations in afterSingletonsInstantiated.
2. Use of SmartInitializingSingleton in XXL-JOB
xxl-job is a lightweight distributed task scheduling framework. Through a central scheduling platform, multiple executors are scheduled to execute tasks, and the monitoring interface is integrated in the scheduling center, and the interface is simple.
In xxl-job, XxlJobSpringExecutor and XxlJobSimpleExecutor inherit from XxlJobExecutor and also implement the SmartInitializingSingleton interface.
In the afterSingletonsInstantiated() method, XxlJobSpringExecutor completes the method of extracting the @XxlJob annotation for the execution of subsequent tasks. Call the start() method in the parent class method to initialize the netty server.
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); } } ///Other code omitted }
The start() method in the parent class: initEmbedServer is used to initialize the netty service.
// ---------------------- 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 initializes the netty service initEmbedServer(address, ip, port, appname, accessToken); }
Get the implementation method of the method annotated with the @XxlJob annotation in the container:
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); } } }
Similar to other frameworks, just return an instantiated bean in the configuration class decorated with @Configuraton.
@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; } }
3. Use of SmartInitializingSingleton in spring container
EventListenerMethodProcessor also implements the SmartInitializingSingleton interface, which is mainly used to complete event monitoring by @EventListener annotation.
The processing logic in the afterSingletonsInstantiated() method is similar to that in xxl-job, and it is used to filter the methods modified by the specified annotations in the instance.
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); } } } } } }
write at the end
The above two methods are used to process some custom logic after the single column of the spring container is loaded. EventListenerMethodProcessor is mainly used to filter out @EventListener
The annotated method implements event monitoring through the publish-subscribe mode in subsequent use.
XxlJobSpringExecutor is mainly used to filter out the methods annotated with @XxlJob annotation for starting and stopping subsequent tasks.