java:自定义注解,并使用【ImportBeanDefinitionRegistrar】动态加载

# 项目代码资源:

可能还在审核中,请等等。。。
https://download.csdn.net/download/chenhz2284/89432848

# 主项目

【pom.xml】

<groupId>com.chz</groupId>
<artifactId>chzopen_study</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>
<modules>
    <module>myBeanMain</module>
    <module>myBeanBranch2</module>
</modules>

子模块【myBeanBranch2】

【pom.xml】

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.15.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-web</artifactId>
    <version>5.2.15.RELEASE</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>
<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>1.3.5</version>
</dependency>

【MyRegistrarAnnotation.java】

package com.chz.myBeanRegistrar.annotation;

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
public @interface MyRegistrarAnnotation {
}

【MyImportBeanDefinitionRegistrar.java】

package com.chz.myBeanRegistrar.beanRegistrar;

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
                                        BeanDefinitionRegistry registry,
                                        BeanNameGenerator importBeanNameGenerator)
    {
        try {
            // 这里开始扫描包里面的类
            MyRegistrarScanner scanner = new MyRegistrarScanner(EnableBranchRegistrar.class.getPackageName());
            List<Class<?>> targetClassList = scanner.scan();
            for( Class<?> klass : targetClassList ){
                // 扫到类之后注册成一个bean
                GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
                beanDefinition.setBeanClass(klass);
                registry.registerBeanDefinition(klass.getName(), beanDefinition);
            }
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    public static void main(String[] args)
    {
        MyRegistrarAnnotation annotation = BranchRegistrarController.class.getAnnotation(MyRegistrarAnnotation.class);
        System.out.println(annotation);
    }
}

【BranchRegistrarController.java】

package com.chz.myBeanRegistrar.controller;

@Slf4j
@MyRegistrarAnnotation    // 这里添加了我们自己的注解
@ResponseBody
@RequestMapping("/branch/registrar")
public class BranchRegistrarController {

    public BranchRegistrarController()
    {
        log.info("chz >>> BranchRegistrarController.<init>()");
    }

    @GetMapping("/test1")
    public String test1() {
        return "test1: BranchRegistrarController";
    }
}

【ClassScanner.java】

package com.chz.myBeanRegistrar.scan;

@Slf4j
public class ClassScanner {

    private static final String DEFAULT_RESOURCE_PATTERN = "**/*.class";

    private String basePackage;
    private ClassLoader classLoader;
    private Matcher matcher;

    public ClassScanner(String basePackage, Matcher matcher)
    {
        this(basePackage, matcher, null);
    }

    public ClassScanner(String basePackage, Matcher matcher, ClassLoader classLoader)
    {
        this.basePackage = basePackage;
        this.classLoader = classLoader!=null ? classLoader : this.getClass().getClassLoader();
        this.matcher = matcher;
    }

    public List<Class<?>> scan() throws IOException {
        List<Class<?>> candidates = new ArrayList<>();
        String packageSearchPath = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + convertPath(basePackage) + '/' + DEFAULT_RESOURCE_PATTERN;
        ResourceLoader resourceLoader = new DefaultResourceLoader();
        MetadataReaderFactory readerFactory = new SimpleMetadataReaderFactory(resourceLoader);
        Resource[] resources = ResourcePatternUtils.getResourcePatternResolver(resourceLoader).getResources(packageSearchPath);
        for (Resource resource : resources) {
            Class<?> clazz = transformToClass(readerFactory.getMetadataReader(resource).getClassMetadata().getClassName());
            if( matcher.match(clazz) ) {
                candidates.add(clazz);
            }
        }
        return candidates;
    }

    private Class<?> transformToClass(String className) {
        Class<?> clazz = null;
        try {
            clazz = ClassUtils.forName(className, classLoader);
        } catch (ClassNotFoundException e) {
            log.info("未找到指定类", className, e);
        } catch (NoClassDefFoundError e) {
            log.info("未找到指定类", className, e);
            throw e;
        }
        return clazz;
    }

    private String convertPath(String path) {
        return StringUtils.replace(path, ".", "/");
    }

    public interface Matcher
    {
        boolean match(Class<?> clazz);
    }
}

【MyRegistrarScanner.java】

package com.chz.myBeanRegistrar.scan;

public class MyRegistrarScanner {

    private ClassScanner classScanner;

    public MyRegistrarScanner(String basePackage){
        classScanner = new ClassScanner(basePackage, new MoMatcher());
    }

    public MyRegistrarScanner(String basePackage, ClassLoader classLoader){
        classScanner = new ClassScanner(basePackage, new MoMatcher(), classLoader);
    }

    public List<Class<?>> scan() throws IOException {
        return (List<Class<?>>)(Object)classScanner.scan();
    }

    private static class MoMatcher implements ClassScanner.Matcher
    {
        @Override
        public boolean match(Class<?> clazz) {
            // 注意这些:要求class必须有【MyRegistrarAnnotation】注解
            return isAbstract(clazz)==false && clazz.getAnnotation(MyRegistrarAnnotation.class)!=null;
        }
    }

    public static boolean isAbstract(Class<?> clazz)
    {
        return Modifier.isAbstract(clazz.getModifiers());
    }
}

【EnableBranchRegistrar.java】

package com.chz.myBeanRegistrar;

@Retention(RetentionPolicy.RUNTIME)
@Documented
@Target(ElementType.TYPE)
@Import({
        MyImportBeanDefinitionRegistrar.class,                 // 这里使用了 ImportBeanDefinitionRegistrar
})
public @interface EnableBranchRegistrar {
}

# 子模块:【myBeanMain】

【pom.xml】

<dependency>
    <groupId>com.chz</groupId>
    <artifactId>myBeanBranch2</artifactId>
    <version>${project.version}</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>2.3.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-actuator</artifactId>
    <version>2.3.12.RELEASE</version>
</dependency>
<dependency>
    <groupId>ch.qos.logback</groupId>
    <artifactId>logback-classic</artifactId>
    <version>1.2.11</version>
</dependency>

【application.properties】

server.port=8080
spring.application.name=myBeanMain

management.server.port=7001
management.endpoints.web.exposure.include=*

【MainBean.java】

package com.chz.myBeanMain.bean;

@Slf4j
@Getter
@Setter
@Component
public class MainBean {

    @Autowired(required = false)
    private NotAnnotatedBean notAnnotatedBean;

    public MainBean()
    {
        log.info("chz >>> MainBean.<init>()");
    }

    @PostConstruct
    public void init()
    {
        log.info("chz >>> MainBean.init()");
    }
}

【NotAnnotatedBean.java】

package com.chz.myBeanMain.bean;

// 被【@Import】指过来的bean不需要添加【@Component】
@Slf4j
@Getter
@Setter
public class NotAnnotatedBean {

    private String name = "I am " + this.getClass().getSimpleName();

    public NotAnnotatedBean()
    {
        log.info("chz >>> NotAnnotatedBean.<init>()");
    }
}

【MainConfiguration.java】

package com.chz.myBeanMain.config;

@Slf4j
@Configuration
public class MainConfiguration {

    public MainConfiguration()
    {
        log.info("chz >>> MainConfiguration.<init>()");
    }
}

【MainController.java】

package com.chz.myBeanMain.controller;

@Slf4j
@RestController
@RequestMapping("/main")
public class MainController {

    @Autowired(required = false)
    private MainBean mainBean;

    @GetMapping("/notAnnotatedBean")
    public String notAnnotatedBean() {
        return "notAnnotatedBean: " + mainBean.getNotAnnotatedBean().getName();
    }
}

【MyBeanMainTest.java】

package com.chz.myBeanMain;

@Import(NotAnnotatedBean.class)         // 这里使用了@Import
@EnableBranchRegistrar                  // 这里使用了@ImportBeanDefinitionRegistrar
@SpringBootApplication
public class MyBeanMainTest {

    public static void main(String[] args) {
        SpringApplication.run(MyBeanMainTest.class, args);
    }
}

# 运行

运行【MyBeanMainTest】,可以看到【BranchRegistrarController】确实被注册进来了
在这里插入图片描述
访问【http://localhost:8080/branch/registrar/test1】,正常显示
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈鸿圳

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值