springboot源码解析-管中窥豹系列之EnableXXX(十)

Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去。

我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot源码管中窥豹系列。

 简介

二、EnableXXX

我们上一节讲了自动装配,用到了@SpringBootApplication里面的@EnableAutoConfiguration

springboot还封装了其它的EnableXXX注解

比如我们想开启定时任务,要加上注解:@EnableScheduling

比如我们想用异步编程,要加上注解:@EnableAsync

自动装配用的是:@Import(AutoConfigurationImportSelector.class)

是不是都是这个套路呢?我们研究一下

三、源码分析

我们先看看@EnableScheduling

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Import(SchedulingConfiguration.class) @Documented public @interface EnableScheduling { }

同样的用到@Import,我们看看SchedulingConfiguration

@Configuration @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public class SchedulingConfiguration { @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME) @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() { return new ScheduledAnnotationBeanPostProcessor(); } }

定义了一个BeanPostProcessor :ScheduledAnnotationBeanPostProcessor

BeanPostProcessor,我们先简单的说下,相当于一个aop组件,在bean加载的时候调用

public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; } }

我们看看ScheduledAnnotationBeanPostProcessor怎么实现的方法?

public Object postProcessAfterInitialization(Object bean, String beanName) { if (bean instanceof AopInfrastructureBean) { // Ignore AOP infrastructure such as scoped proxies. return bean; } Class<?> targetClass = AopProxyUtils.ultimateTargetClass(bean); if (!this.nonAnnotatedClasses.contains(targetClass)) { Map<Method, Set<Scheduled>> annotatedMethods = MethodIntrospector.selectMethods(targetClass, (MethodIntrospector.MetadataLookup<Set<Scheduled>>) method -> { Set<Scheduled> scheduledMethods = AnnotatedElementUtils.getMergedRepeatableAnnotations( method, Scheduled.class, Schedules.class); return (!scheduledMethods.isEmpty() ? scheduledMethods : null); }); if (annotatedMethods.isEmpty()) { this.nonAnnotatedClasses.add(targetClass); if (logger.isTraceEnabled()) { logger.trace("No @Scheduled annotations found on bean class: " + targetClass); } } else { // Non-empty set of methods annotatedMethods.forEach((method, scheduledMethods) -> scheduledMethods.forEach(scheduled -> processScheduled(scheduled, method, bean))); if (logger.isDebugEnabled()) { logger.debug(annotatedMethods.size() + " @Scheduled methods processed on bean '" + beanName + "': " + annotatedMethods); } } } return bean; }

根据@Scheduled注解,执行相应的定时任务,不细看了

我们在看看@EnableAsync

@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Import(AsyncConfigurationSelector.class) public @interface EnableAsync { Class<? extends Annotation> annotation() default Annotation.class; boolean proxyTargetClass() default false; AdviceMode mode() default AdviceMode.PROXY; int order() default Ordered.LOWEST_PRECEDENCE; }

通过@Import加载AsyncConfigurationSelector

ImportSelector之前说过,通过接口返回的字符串数组,加载bean, 不细看了

好了,我们总结一下:

通过@EnableXXX注解上@Import加载进来相应的类

之后怎么实现就各显神通了,主要是BeanPostProcesser, ImportSelector 和Register

目录:
springboot源码解析-管中窥豹系列

 丰极

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:https://www.heiqu.com/wssgfj.html