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源码解析-管中窥豹系列之总体结构(一)
springboot源码解析-管中窥豹系列之项目类型(二)
springboot源码解析-管中窥豹系列之Runner(三)
springboot源码解析-管中窥豹系列之Initializer(四)
springboot源码解析-管中窥豹系列之排序(五)
springboot源码解析-管中窥豹系列之aware(六)
springboot源码解析-管中窥豹系列之web服务器(七)
springboot源码解析-管中窥豹系列之BeanDefinition(八)
springboot源码解析-管中窥豹系列之自动装配(九)
springboot源码解析-管中窥豹系列之EnableXXX(十)
springboot源码解析-管中窥豹系列之BeanFactoryPostProcessor(十一)
springboot源码解析-管中窥豹系列之BeanPostProcessor(十二)
springboot源码解析-管中窥豹系列之BeanDefine如何加载(十三)
springboot源码解析-管中窥豹系列之bean如何生成?(十四)

 丰极

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

posted @ 2021-03-04 16:37  丰极  阅读(294)  评论(0编辑  收藏  举报