乐趣区

关于java: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

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

退出移动版