启用配置
1.功能
- 在springboot中使用@EnableXXX注解开启某项功能;
- 常用的包括:
- @EnableCaching:启用缓存
- @EnableAsync:启用异步调用
- @EnableScheduling:启用定时任务
- @EnableTransactionManagement:启用事务
2.原理
2.1.说明
- 使用@EnableXXX注解,相当于在spring上下文环境中导入一些java bean;
- 可参考@EnableCaching和CachingConfigurationSelector,实现EnableXXX,导入一些需要初始化的java bean;
2.2.ImportSelector接口
- 需要与@Import注解一起使用,导入selectImports返回类名的相关配置类;
2.3.过程
- @EnableCaching注解配置上引入@Import注解;
- @Import注解导入CachingConfigurationSelector实例;
- @CachingConfigurationSelector继承AdviceModeImportSelector,并实现了ImportSelector接口;
- AdviceModeImportSelector获取@EnableCaching注解配置的参数,传给CachingConfigurationSelector;
- CachingConfigurationSelector根据@EnableCaching的配置及项目是否引入jsr107的接口定义和具体实现来决定需要导入哪些java bean;
3.解析
EnableCaching注解
- 配置一些初始化参数,可传入到导入的CachingConfigurationSelector类中;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
//**导入AsyncConfigurationSelector
@Import(CachingConfigurationSelector.class)
public @interface EnableCaching {
//**是否启用CGLIB代理,默认不启用
boolean proxyTargetClass() default false;
//**代理方式:
//**PROXY:Spring动态代理(含JDK动态代理和CGLIB)
//**ASPECTJ:使用AspectJ静态代理
AdviceMode mode() default AdviceMode.PROXY;
//**注解的执行顺序
int order() default Ordered.LOWEST_PRECEDENCE;
}
AdviceModeImportSelector抽象类
- 读取EnableCaching注解中配置的参数,传给子类,并让子类决定需要导入bean的名称;
//**获取EnableCaching注解中的AdviceMode参数,并把AdviceMode传给子类,让子类决定需要导入bean的名称
public abstract class AdviceModeImportSelector<A extends Annotation> implements ImportSelector {
@Override
public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
//**获取泛型的类型
Class<?> annType = GenericTypeResolver.resolveTypeArgument(getClass(), AdviceModeImportSelector.class);
Assert.state(annType != null, "Unresolvable type argument for AdviceModeImportSelector");
//**根据泛型的类型获取注解
AnnotationAttributes attributes = AnnotationConfigUtils.attributesFor(importingClassMetadata, annType);
...
//**获取注解中的AdviceMode参数
AdviceMode adviceMode = attributes.getEnum(getAdviceModeAttributeName());
//**把AdviceMode传给子类,让子类决定需要导入bean的名称
String[] imports = selectImports(adviceMode);
...
return imports;
}
@Nullable
protected abstract String[] selectImports(AdviceMode adviceMode);
}
CachingConfigurationSelector实现类
- 根据EnableCaching注解中配置的参数,导入对应的java bean;
//**根据传入的AdviceMode参数,导入对应的bean
//**如果是PROXY代理模式,则导入AutoProxyRegistrar、ProxyCachingConfiguration。如果有jsr107的接口定义和具体实现,则额外导入ProxyJCacheConfiguration;
//**如果是ASPECTJ切面模式,则导入AspectJCachingConfiguration。如果有jsr107的接口定义和具体实现,则额外导入AspectJJCacheConfiguration;
//**以上导入的bean,大多是Configuration,各自会又会导入一些该功能依赖的bean;
public class CachingConfigurationSelector extends AdviceModeImportSelector<EnableCaching> {
private static final String PROXY_JCACHE_CONFIGURATION_CLASS =
"org.springframework.cache.jcache.config.ProxyJCacheConfiguration";
private static final String CACHE_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.cache.aspectj.AspectJCachingConfiguration";
private static final String JCACHE_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.cache.aspectj.AspectJJCacheConfiguration";
private static final boolean jsr107Present;
private static final boolean jcacheImplPresent;
static {
ClassLoader classLoader = CachingConfigurationSelector.class.getClassLoader();
//**是否有jsr107的接口定义(jsr107是java缓存规范)
jsr107Present = ClassUtils.isPresent("javax.cache.Cache", classLoader);
//**是否有jsr107的具体实现
jcacheImplPresent = ClassUtils.isPresent(PROXY_JCACHE_CONFIGURATION_CLASS, classLoader);
}
//**根据EnableCaching的mode参数决定导入的bean
@Override
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return getProxyImports();
case ASPECTJ:
return getAspectJImports();
default:
return null;
}
}
//**PROXY代理模式
private String[] getProxyImports() {
List<String> result = new ArrayList<>(3);
//**导入AutoProxyRegistrar
result.add(AutoProxyRegistrar.class.getName());
//**ProxyCachingConfiguration
result.add(ProxyCachingConfiguration.class.getName());
//**如果有jsr107的接口定义和具体实现,则导入ProxyJCacheConfiguration
if (jsr107Present && jcacheImplPresent) {
result.add(PROXY_JCACHE_CONFIGURATION_CLASS);
}
return StringUtils.toStringArray(result);
}
//**ASPECTJ切面模式
private String[] getAspectJImports() {
List<String> result = new ArrayList<>(2);
//**导入AspectJCachingConfiguration
result.add(CACHE_ASPECT_CONFIGURATION_CLASS_NAME);
//**如果有jsr107的接口定义和具体实现,则导入AspectJJCacheConfiguration
if (jsr107Present && jcacheImplPresent) {
result.add(JCACHE_ASPECT_CONFIGURATION_CLASS_NAME);
}
return StringUtils.toStringArray(result);
}
}