共计 2962 个字符,预计需要花费 8 分钟才能阅读完成。
一、前言
- 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
欢送关注微信公众号:丰极,更多技术学习分享。
正文完