一、前言

  • Springboot源码解析是一件大工程,逐行逐句的去钻研代码,会很干燥,也不容易坚持下去。
  • 咱们不谋求大而全,而是试着每次去钻研一个小知识点,最终聚沙成塔,这就是咱们的springboot源码管中窥豹系列。

二、EnableXXX

  • 咱们上一节讲了主动拆卸,用到了@SpringBootApplication外面的@EnableAutoConfiguration
  • springboot还封装了其它的EnableXXX注解
  • 比方咱们想开启定时工作,要加上注解:@EnableScheduling
  • 比方咱们想用异步编程,要加上注解:@EnableAsync
  • 主动拆卸用的是:@Import(AutoConfigurationImportSelector.class)
  • 是不是都是这个套路呢?咱们钻研一下

三、源码剖析

咱们先看看@EnableScheduling

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Import(SchedulingConfiguration.class)@Documentedpublic @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

欢送关注微信公众号:丰极,更多技术学习分享。