SpringEnableXX注解原理及应⽤
Spring提供了⼀系列以Enable开头的注解,这些注解本质上是激活Spring的某些管理功能。例如@EnableWebMvc注解引⼊了MVC框架在Spring应⽤中需要⽤到的所有bean,@EnableAsync注解可以使Bean在spring应⽤中⽀持异步功能,@EnableTransactionManagement开启事务⽀持。打开这些注解的源码不难发现这些@EnableXX注解的定义都包含⼀个@Import注解,通过导⼊⼀些配置类来完成特定的功能。@Import注解导⼊配置⽅式的三种类型
第⼀类配置类
例如,@EnableScheduling中直接导⼊配置类SchedulingConfiguration,这个类注解了@Configuration,且注册了⼀个scheduledAnnotationProcessor的Bean。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SchedulingConfiguration.class)
@Documented
public @interface EnableScheduling {
}
我们可以仿照着写⼀个类似的demo,将⾃定义的注解加在配置类上即可加载bean到spring容器。
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(ConfigurationDemo.class)
public @interface EnableConfigDemo {
String value() default "";
}
@Configuration
public class ConfigurationDemo {
@Bean
public TestBean01 getTestBean01(){
return  new TestBean01();
}
}
public class TestBean01 {
public void sayHello(){
System.out.println("hello ,I am TestBean01");
}
}
第⼆类 ImportSelector的实现类
@Import导⼊ImportSelector的实现类时,Spring会把selectImport⽅法的返回值对应的Bean注⼊到Spring容器(其核⼼原理是spring的BeanFactoryPostProcessor),例如@EnableAsync、@EnableTransactionManagement
public class TransactionManagementConfigurationSelector extends AdviceModeImportSelector<EnableTransactionManagement> {
@Override
protected String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {Name(),
Name()};
case ASPECTJ:
return new String[] {determineTransactionAspectClass()};
default:
return null;
}
}
private String determineTransactionAspectClass() {
return (ClassUtils.isPresent("ansaction.Transactional", getClass().getClassLoader()) ?
TransactionManagementConfigUtils.JTA_TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME :
TransactionManagementConfigUtils.TRANSACTION_ASPECT_CONFIGURATION_CLASS_NAME);
}
}
public class AsyncConfigurationSelector extends AdviceModeImportSelector<EnableAsync> {
private static final String ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME =
"org.springframework.scheduling.aspectj.AspectJAsyncConfiguration";
@Override
springframework事务@Nullable
public String[] selectImports(AdviceMode adviceMode) {
switch (adviceMode) {
case PROXY:
return new String[] {Name()};
case ASPECTJ:
return new String[] {ASYNC_EXECUTION_ASPECT_CONFIGURATION_CLASS_NAME};
default:
return null;
}
}
}
⾃⼰动⼿写⼀个demo
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(SelectorDemo.class)
public @interface EnableSelectorDemo {
String dataSourcetype() default "druid";
}
public class SelectorDemo implements ImportSelector {
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
Map<String, Object> annotationAttributes = AnnotationAttributes(Name(), false);
AnnotationAttributes annotationAttributes1 = AnnotationAttributes.fromMap(annotationAttributes);
String dataSourcetype = String("dataSourcetype");
if("druid".equals(dataSourcetype)){
return new String[]{"ample.beans.DruidDataSource"};
}else{
return new String[]{"ample.beans.HpDataSource"};
}
}
}
第三类动态注册Bean
@Import导⼊ImportBeanDefinitionRegistrar的实现类,通过重写⽅法registerBeanDefinitions()注⼊bean(其核⼼原理也是spring的BeanFactoryPostProcessor,是spring的重要扩展接⼝),例如@EnableAspectJAutoProxy
class AspectJAutoProxyRegistrar implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(
AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes enableAspectJAutoProxy =
AnnotationConfigUtils.attributesFor(importingClassMetadata, EnableAspectJAutoProxy.class);
if (enableAspectJAutoProxy != null) {
if (Boolean("proxyTargetClass")) {
AopConfigUtils.forceAutoProxyCreatorToUseClassProxying(registry);
}
if (Boolean("exposeProxy")) {
AopConfigUtils.forceAutoProxyCreatorToExposeProxy(registry);
}
}
}
}
⼿写⼀个demo
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import(RegistrarDemo.class)
public @interface EnableRegistrar {
String[] scanPackage() default "";
}
//模仿spring整合mybaits
public class RegistrarDemo implements ImportBeanDefinitionRegistrar {
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
AnnotationAttributes annotationAttributes = AnnotationAttributes.AnnotationAttributes(Name(), false));        String[] scanPackages = StringArray("scanPackage");
List<String> classNames = new ArrayList<String>();
for (String scanPackage : scanPackages) {
classNames.addAll(scanBasePackage(scanPackage));
}
try {
for (String className : classNames) {
Class<?> aClass = Class.forName(className);
if(aClass.isAnnotationPresent(MapperDemo.class)){
BeanDefinitionBuilder bdb1 = BeanDefinition(aClass);
BeanDefinition beanDefinition1 = BeanDefinition();
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
private List<String> scanBasePackage(String basePackName){
List<String> classNames = new ArrayList<String>();
String path = place(".","/");
System.out.println(path);
URL url = Class().getClassLoader().getResource(path);
System.out.println(url);
File dir = new File());
File[] files = dir.listFiles();
for (File file: files) {
if(file.isDirectory()){
scanBasePackage(basePackName +"."+Name());
}else if(file.isFile()){
classNames.add(basePackName +"." + Name().replace(".class",""));
System.out.println("扫描到的类有" + basePackName +"." + Name().replace(".class",""));
}
}
return classNames;
}
}
springboot中的⾃动装配机制
springboot中的⾃动装配机制是基于@EnableAutoConfiguration这个注解⾥完成的,这个@EnableAutoConfiguration注解可以显式地调⽤,否则它会在@SpringBootApplication注解中隐式地被调⽤,@EnableAutoConfiguration注解中使⽤了AutoConfigurationImportSelector作为ImportSelector。核⼼源码如下:
public String[] selectImports(AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return NO_IMPORTS;
}
AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader
.loadMetadata(this.beanClassLoader);
AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(
autoConfigurationMetadata, annotationMetadata);
Configurations());
}
protected AutoConfigurationEntry getAutoConfigurationEntry(
AutoConfigurationMetadata autoConfigurationMetadata,
AnnotationMetadata annotationMetadata) {
if (!isEnabled(annotationMetadata)) {
return EMPTY_ENTRY;
}
AnnotationAttributes attributes = getAttributes(annotationMetadata);
List<String> configurations = getCandidateConfigurations(annotationMetadata,
attributes);
configurations = removeDuplicates(configurations);
Set<String> exclusions = getExclusions(annotationMetadata, attributes);
checkExcludedClasses(configurations, exclusions);
configurations = filter(configurations, autoConfigurationMetadata);
fireAutoConfigurationImportEvents(configurations, exclusions);
return new AutoConfigurationEntry(configurations, exclusions);
}
//读取META-INF/spring.factories下的配置
protected List<String> getCandidateConfigurations(AnnotationMetadata metadata,
AnnotationAttributes attributes) {
List<String> configurations = SpringFactoriesLoader.loadFactoryNames(
getSpringFactoriesLoaderFactoryClass(), getBeanClassLoader());
"No auto configuration classes found in META-INF/spring.factories. If you "
+ "are using a custom packaging, make sure that file is correct.");
return configurations;
}
这也是我们封装⾃⼰的springboot-starter是需要在META-INF/spring.factories配置org.springframework.boot.autoconfigure.EnableAutoConfiguration=xxx的原因

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。