@Import、自定义注解、ClassPathBeanDefinitionScanner

@Import三种用法

1、引入普通类

2、引入ImportSelector的实现类

3、引入ImportBeanDefinitionRegister的实现类


以下以方式三为例:

配置类实现 ImportBeanDefinitionRegistrar 接口,可以自定义往容器中注册想注入的Bean。

该接口相比与 ImportSelector 接口的主要区别在于,ImportSelector接口是返回一个类,无法对这个类做操作, ImportBeanDefinitionRegistrar 是可以自己注入 BeanDefinition,添加属性等。

public class MyImportBeanRegistrar implements ImportBeanDefinitionRegistrar {

    /**
     * @param importingClassMetadata 当前类的注解信息
     * @param registry  注册类,registerBeanDefinition()可以注册bean
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
    
    }
}

案例:自定义注解,将使用我们自定义注解并满足条件的类注入到spring容器中


自定义注解
参考博客:https://blog.csdn.net/dongzhanglong/article/details/120130237

@Target:注解的作用目标

@Target(ElementType.TYPE)——接口、类、枚举、注解
@Target(ElementType.FIELD)——字段、枚举的常量
@Target(ElementType.METHOD)——方法
@Target(ElementType.PARAMETER)——方法参数
@Target(ElementType.CONSTRUCTOR) ——构造函数
@Target(ElementType.LOCAL_VARIABLE)——局部变量
@Target(ElementType.ANNOTATION_TYPE)——注解
@Target(ElementType.PACKAGE)——包,用于记录java文件的package信息

自定义包扫描注解
参考博客:https://blog.csdn.net/qq_16504067/article/details/120201048

// RetentionPolicy.RUNTIME 表示注解信息在运行时保留,在运行时可以通过反射获取注解信息,实现一些操作
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
public @interface MapperScan {
    /**
     * 扫描的包名
     */
    String[] basePackages() default {};
 
    /**
     * 扫描的类名
     */
    Class<?>[] basePackageClasses() default {};
}

自定义学生配置注解

//该注解可以应用于类、接口(包括注解类型)、枚举
@Target(ElementType.TYPE)
//被注解的元素包含在生成的Java文档中
@Documented
//该注解的生命周期,由JVM 加载,包含在类文件中,在运行时可以被获取到
@Retention(RetentionPolicy.RUNTIME)
public @interface StudentConfig {
    String name() default "luxifa";
    int age();
}

BeanDefinition子类实现介绍
参考博客:https://blog.csdn.net/c_c_f/article/details/119861188

对于bean定义只需要关注AbstractBeanDefinition和AnnotatedBeanDefinition就行。不要太注重与细节。

AbstractBeanDefinition:对BeanDefinition接口进行实现,并进行了扩展。
RootBeanDefinition、GenericBeanDefinition、ChildBeanDefinition是其子类。

AnnotatedBeanDefinition:注解类型的Bean定义。并扩展了注解相关的接口。

public interface AnnotatedBeanDefinition extends BeanDefinition {

	/**
	 * 获取注解的元数据
	 */
	AnnotationMetadata getMetadata();

	/*
	 * 获取工厂方法的元数据
	 */
	@Nullable
	MethodMetadata getFactoryMethodMetadata();
}

定义ImportBeanDefinitionRegister的实现类

参考博客:https://blog.csdn.net/qq_16504067/article/details/120201048

public class MyImportBean implements ImportBeanDefinitionRegistrar {

    /**
     * @param importingClassMetadata 当前类的注解信息
     * @param registry  注册类,registerBeanDefinition()可以注册bean
     */
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        // 获取要扫描的包路径
        
 
        //聚合扫描的路径
        Set<String> basePackages = getBasePackages(importingClassMetadata);
 
        //获取扫描器
        ClassPathBeanDefinitionScanner scanner = getScanner(registry);
 
        //扫描并注册bd
        for (String basePackage : basePackages) {
            //获取com.luxifa包下,使用StudentConfig注解的bean,该处值为com.luxifa.Test
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            for (BeanDefinition beanDefinition : candidateComponents) {
                //注册BD
                // ..可添加写过滤条件,比如StudentConfig注解中age小于35才让注入springbean中
                // 思路:判断bean定义是否为被注解的bean定义,是的话,转为被注解的bean定义,然后获取该被注解的bean定义中包含注解的所有信息,然后根据注解所在的类得到类加载器,根据类加载器得到我们的StudentConfig注解,然后判断StudentConfig注解上的age的值
                String beanClassName = beanDefinition.getBeanClassName();
                // 此处也可以自定义bean,然后注册
                registry.registerBeanDefinition(beanClassName, beanDefinition);
            }
    }


    private ClassPathScanningCandidateComponentProvider getScanner(BeanDefinitionRegistry registry) {
        //不使用默认的过滤器
        // true:默认TypeFilter生效,这种模式会查询出许多不符合你要求的class名
        // false:关闭默认TypeFilter
        // 参考博客:https://blog.csdn.net/qq_16504067/article/details/116642356
        ClassPathBeanDefinitionScannerscanner = new ClassPathBeanDefinitionScanner(registry, false);
        // 扫描我们自定义的注解
        scanner.addIncludeFilter(new AnnotationTypeFilter(StudentConfig.class));
        return scanner;
    }

    /**
     * 获取扫描组件的包路径
     */
    protected Set<String> getBasePackages(AnnotationMetadata importingClassMetadata) {
        Map<String, Object> attributes = importingClassMetadata
                .getAnnotationAttributes(MapperScan.class.getCanonicalName());
 
        Set<String> basePackages = new HashSet<>();
 
        for (String pkg : (String[]) attributes.get("basePackages")) {
            if (StringUtils.hasText(pkg)) {
                basePackages.add(pkg);
            }
        }
        for (Class<?> clazz : (Class<?>[]) attributes.get("basePackageClasses")) {
            basePackages.add(ClassUtils.getPackageName(clazz));
        }
 
        if (basePackages.isEmpty()) {
            basePackages.add(
                    ClassUtils.getPackageName(importingClassMetadata.getClassName()));
        }
        return basePackages;
    }

}

自定义配置类中引入MyImportBeanRegistrar对象

package com.xx.example;
@Configuration
@Import(MyImportBean.class)
@MapperScan(basePackages={"com.luxifa"})
public class MyAutoConfiguration {

}

将自定义的配置类MyAutoConfiguration 放到spring.factories文件中

#spring.factories 文件内容:
org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.xx.example.MyAutoConfiguration

Demo服务中,Test.java类使用自定义StudentConfig注解
参考博客:https://blog.csdn.net/weixin_53233197/article/details/128402888文章来源地址https://uudwc.com/A/599nJ

package com.luxifa;

@StudentConfig(name="degula",age=25)
public class Test {

}

原文地址:https://blog.csdn.net/weixin_42594143/article/details/132686079

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请联系站长进行投诉反馈,一经查实,立即删除!

h
上一篇 2023年09月06日 08:05
下一篇 2023年09月06日 08:13