自定义Springboot @EnableXXX注解

上一篇大概讲了springboot 的@EnableAutoConfiguration的实现,这篇我们自定义一个@EnableMyCache注解实现。

1.利用@Import注解加载不在包扫描范围的类,并将其注册到容器。

2.我们知道将Bean注册到IOC容器有很多种方式,从最初的使用XML配置文件的<bean/>标签,到使用注解@Component或@ManagedBean及其派生注解,以及JavaConfig配置类(@Bean)的方式将Bean注册到容器,但是这些方式都是静态(写死的配置或代码),如果我们想要在某些情况成立,或一个开关来决定是否将这些Bean注册到容器。

此时我们就要使用动态的注册Bean,根据代码逻辑按需注册。

3.动态注册有两种方式,一是和实现ImportSelector接口,二是实现 ImportBeanDefinitionRegistrar

4.示例:

代码结构:

两个示例类:

public class DBRepo {
}

public class LogService {
}

@Configuration
public class CacheConfig {

    @Bean
    public CacheService cacheService() {
        return new CacheService();
    }
}

实现ImportSelector接口

public class DefinedClassImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.demo.extentions.DBRepo","com.demo.extentions.CacheConfig"};
    }
}

实现ImportBeanDefinitionRegistrar接口

public class ImportBeanDefinedRegistry implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(LogService.class);
        String name = StringUtils.uncapitalize(LogService.class.getName());
        registry.registerBeanDefinition(name, rootBeanDefinition);
    }
}

自定义的@EnableXXX注解,该注解上使用@Import注解将上面的两个实现类引入。

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({DefinedClassImportSelector.class, ImportBeanDefinedRegistry.class})
public @interface EnableDefinedBean {


}

最后在启动类上加上@EnableDefinedBean就能将LogService和DBRepo两个类的Bean注册到容器。

容器中我们就能拿到动态注册的Bean(扫描以外的包)

@SpringBootApplication
@EnableDefinedBean
public class AppMain {

    public static void main(String[] args) {
        ConfigurableApplicationContext context = SpringApplication.run(AppMain.class, args);
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
    }
}

结果:

最后附上springboot对@Import的Class的处理

for (SourceClass candidate : importCandidates) {
	if (candidate.isAssignable(ImportSelector.class)) {
		// Candidate class is an ImportSelector -> delegate to it to determine imports
		Class<?> candidateClass = candidate.loadClass();
		ImportSelector selector = BeanUtils.instantiateClass(candidateClass, ImportSelector.class);
		ParserStrategyUtils.invokeAwareMethods(
				selector, this.environment, this.resourceLoader, this.registry);
		if (this.deferredImportSelectors != null && selector instanceof DeferredImportSelector) {
			this.deferredImportSelectors.add(
					new DeferredImportSelectorHolder(configClass, (DeferredImportSelector) selector));
		}
		else {
			String[] importClassNames = selector.selectImports(currentSourceClass.getMetadata());
			Collection<SourceClass> importSourceClasses = asSourceClasses(importClassNames);
			processImports(configClass, currentSourceClass, importSourceClasses, false);
		}
	}
	else if (candidate.isAssignable(ImportBeanDefinitionRegistrar.class)) {
		// Candidate class is an ImportBeanDefinitionRegistrar ->
		// delegate to it to register additional bean definitions
		Class<?> candidateClass = candidate.loadClass();
		ImportBeanDefinitionRegistrar registrar =
				BeanUtils.instantiateClass(candidateClass, ImportBeanDefinitionRegistrar.class);
		ParserStrategyUtils.invokeAwareMethods(
				registrar, this.environment, this.resourceLoader, this.registry);
		configClass.addImportBeanDefinitionRegistrar(registrar, currentSourceClass.getMetadata());
	}
	else {
		// Candidate class not an ImportSelector or ImportBeanDefinitionRegistrar ->
		// process it as an @Configuration class
		this.importStack.registerImport(
				currentSourceClass.getMetadata(), candidate.getMetadata().getClassName());
		processConfigurationClass(candidate.asConfigClass(configClass));
	}
}

 

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值