Spring -importbeandefinitionregister用法

importBeanDefinationRegister接口

该接口只能通过@import导入到配置bean中,该接口才被调用。而一般的如@Component,@Configuration都不会让Spring自动去调用该接口,必须结合@import才能使用。

void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry);

第一个参数annotationMetadata
用来读取***@import所在类上***的注解信息,需要注意:@import在那里被发现,就可以读取到该class上的注解。我们也可以使用自定义注解,主要注解上有@import父注解即可。一般情况下如果需要读取其他Spring注解的配置,就要放在那个注解的旁边。如我们需要读取Spring的@component注解,那么放到run就好了。
第二个参数register
用来向容器中进行bean的注册,我们可以用GenericBeanDefinition de =new GenericBeanDefinition(beanclass) 来定一个bean,然后通过registry.registerBeanDefinition(“dataSource”, beanDefinition); 注册到容器中。
实现一个向容器中注册bean的demo:
GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
beanDefinition.setBeanClass(DynamicDataSource.class);

    beanDefinition.setSynthetic(true);
    MutablePropertyValues mpv = beanDefinition.getPropertyValues();

    mpv.addPropertyValue("defaultTargetDataSource", masterDataSource);
    log.debug("defaultTargetDataSource is masterDataSource");
    mpv.addPropertyValue("targetDataSources", targetDataSources);
    registry.registerBeanDefinition("dataSource", beanDefinition);

当然向容器中注册,方式繁多,也可以使用@Bean ,@Import 等等

实现自定义注解扫描bean,类似于@cache @aspect 这些注解为什么能被自动扫描,加载到容器中呢?
1.首先我们可以通过AnnotationMetadata 参数拿到注解信息,我们可以使用自定义注解来@import,并可以配置一些信息,例如我们想被扫描的包,作为扫描的注解filter等等。
如:
/*
可以制定扫描的包,如果不指定,则读取AppBootStrap中的@Component 注解的扫描路径。
*/
@Target({java.lang.annotation.ElementType.TYPE})
//我们在使用注解时最好加上@Retention,如果只是编译时使用,可以不指定,如果需要在运行时使用,加上runtime类型,否则会失效,例如下面的例子该注解就会失效
@Retention(RetentionPolicy.RUNTIME)
@Import(ImportPersonalBeanRegister.class)
public @interface EnablePersonalBeanScanner {

@AliasFor("packages")
//value 可以直接在注解中使用
String[] value() default "";

@AliasFor("value")
String[] packages() default "";

boolean useComponentPath() default true;

Class<? extends Annotation>[] typeFilterAnnotations() default PersonalRegister.class;

}
通过该注解可以制定我们的filter 注解,以及扫描的包,以及是否使用容器的@component信息作为扫描包。
/*
AnnotationMetadata 只能获取到被import进来的注解所在类的注解信息,拿不到容器中其他class定义的注解。例如ImportBeanUseingMyRegister 该类被@import的注解所在的class上。
所以如果我们希望获取Springboot的全局注解,或者是某个注解时,注意把@import 注解放到那个位置。
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata annotationMetadata, BeanDefinitionRegistry beanDefinitionRegistry) {
try{
List packages = Lists.newArrayList();
@NonNull Map<String,Object> annotationAttributes = annotationMetadata.getAnnotationAttributes(EnablePersonalBeanScanner.class.getName(),false);
String [] componentPaths = (String[]) annotationAttributes.get(“packages”);
mergePackages(packages,componentPaths);
if ( null == annotationAttributes || (boolean)annotationAttributes.get(“useComponentPath”) == true) {
Map<String,Object> componentPackages = annotationMetadata.getAnnotationAttributes(ComponentScan.class.getName(),false);
if ( componentPackages != null ){
componentPaths = (String[]) componentPackages.get(“basePackages”);
mergePackages(packages,componentPaths);
}
}
if ( packages.size() == 0 ) {
log.error(“registerBeanDefinitions fail, packages is empty”);
return;
}
@NonNull Class<? extends Annotation> [] filters = (Class<? extends Annotation>[]) annotationAttributes.get(“typeFilterAnnotations”);
//使用PersonalRegisterBeanDefinitionScanner 进行扫描
PersonalRegisterBeanDefinitionScanner scanner =
new PersonalRegisterBeanDefinitionScanner(beanDefinitionRegistry,resourceLoader,packages.toArray(new String[packages.size()]));
scanner.registerFilters(filters);
Set result = scanner.start();
log.info(“registerBeanDefinitions scan result:{}”,result);
}catch (Exception e){
log.error(“registerBeanDefinitions err:{}”,e);
throw e;
}
}
通过该注解可以拿到要扫描的包,以及扫描filter等信息。
3.创建我们的scanner
@Data
public class PersonalRegisterBeanDefinitionScanner extends ClassPathBeanDefinitionScanner {

private String [] packages ;

public PersonalRegisterBeanDefinitionScanner(BeanDefinitionRegistry registry){
    super(registry);
}
public PersonalRegisterBeanDefinitionScanner(BeanDefinitionRegistry registry,boolean useDefaultFilter) {
    super(registry,useDefaultFilter);
}
public PersonalRegisterBeanDefinitionScanner(BeanDefinitionRegistry registry, ResourceLoader resourceLoader, String ... packages){
    super(registry);
    super.setResourceLoader(resourceLoader);
    this.packages = packages;
}

protected PersonalRegisterBeanDefinitionScanner registerFilters(Class<? extends Annotation> ... annotations){
    for( Class<? extends Annotation> a : annotations){
        super.addIncludeFilter(new AnnotationTypeFilter(a));
    }
    return this;
}

public PersonalRegisterBeanDefinitionScanner registerFilters (List<Class<? extends Annotation>> annotations) {
    registerFilters(annotations.toArray(new Class[annotations.size()]));
    return this;
}

public PersonalRegisterBeanDefinitionScanner setPackages(String ... basePackages ){
    this.packages = basePackages;
    return this;
}

public Set<BeanDefinitionHolder> start(){
    return doScan(this.packages);
}

@Override
protected Set<BeanDefinitionHolder> doScan(String... basePackages) {
    return super.doScan(basePackages);
}

}
这样我们在容器中可以直接使用@EnablePersonalBeanScanner来配置任意自定义的注解来作为扫描filter,进行bean的注入。

@import注解

该注解会让bean被容器加载初始化,还会调用importbeandefinitionregister接口,注意,只要继承了次注解的注解才能作为import,对class进行加载。
对于如果我们希望对某个class进行注入到容器的话,可以使用该注解进行导入,但是一般我们使用这个注解来导入importbeandefinitionregister的类。

BeanPostProcessor

bean的生命周期中很重要的一个接口,用来对bean进行初始化操作,实际上底层是通过AOP来实现的。
里面有2个方法
@Nullable
default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

@Nullable
default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    return bean;
}
分别表示前置处理器,第一个方法为bean create后,初始化(init)之前执行的方法,第二个方法为后置处理器,即在bean执行完init后,执行的方法。

所以我们可以通过该接口来当bean被加载到容器后,进行一些特殊操作,例如对bean进行代理等等。。

InstantiationAwareBeanPostProcessor
是对beanpostprocess的扩展,表示在bean创建前进行的一些操作,例如执行我们自己的创建bean的逻辑,如果前置方法postProcessBeforeInstantiation 返回不为null,那么就不会再执行docreateBean以及beanpostprocessbefore方法,而是直接执行beanpostproecesafterInit方法。

@EnableAspectJAutoProxy

该注解用来注入aspectj的,内部使用@Import({AspectJAutoProxyRegistrar.class})注入了AspectJAutoProxyRegistrar这个bean。

  1. aspectjAturoProxyRegister内部registerbean中通过:
    AopConfigUtils.registerAspectJAnnotationAutoProxyCreatorIfNecessary(registry);来注册 AnnotationAwareAspectJAutoProxyCreator 类。
    2. AnnotationAwareAspectJAutoProxyCreator 的注册先判断org.springframework.aop.config.internalAutoProxyCreator是否以及在容器中注册了(通过register.contaionsDefinition(name)来判断),如果没有注册,那么使用rootBeandefinition来进行注册到容器中。
    3. AnnotationAwareAspectJAutoProxyCreator的初始化,该类实现了SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware 这两个接口,用来对bean完成一些的初始化,第一个接口是一个很重要的接口,里面继承了InstantiationAwareBeanPostProcessor,而instantiationAware 接口继承了BeanPostPostProcess接口。所以这两个接口会对bean进行初始化。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值