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

news2025/2/23 18:13:20

# 项目代码资源:

可能还在审核中,请等等。。。
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】,正常显示
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1824439.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL之优化服务器设置(二)

优化服务器设置 InnoDB事务日志(包含:Redo log 重做日志和Undo log回滚日志) 了解清楚"把日志缓冲写到日中文件"和"把日志刷新到持久化存储"之间的不同是很重要的。在大部分操作系统中&#xff0c;把缓冲写到日志只是简单地把数据从InnoDB的内存缓冲转移…

门控循环单元GRU与长短期记忆网络LSTM

门控循环单元与长短期记忆网络 门控隐状态 问题提出&#xff1a;对于一个序列来说不是每个观察值都是同等重要想只记住相关的观察需要&#xff1a; 能关注的机制&#xff08;更新门&#xff09;能遗忘的机制&#xff08;重置门&#xff09; 第一个词元的影响至关重要。 我们…

深入理解Java多线程:解密程序设计的核心概念

咦咦咦&#xff0c;各位小可爱&#xff0c;我是你们的好伙伴 bug菌&#xff0c;今天又来给大家手把手教学Java SE系列知识点啦&#xff0c;赶紧出来哇&#xff0c;别躲起来啊&#xff0c;听我讲干货记得点点赞&#xff0c;赞多了我就更有动力讲得更欢哦&#xff01;所以呀&…

基于SSM+Jsp的在线教育资源管理系统

开发语言&#xff1a;Java框架&#xff1a;ssm技术&#xff1a;JSPJDK版本&#xff1a;JDK1.8服务器&#xff1a;tomcat7数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;数据库工具&#xff1a;Navicat11开发软件&#xff1a;eclipse/myeclipse/ideaMaven包…

phpStudy里面的MySQL启动不了

C:\Users\Administrator>netstat -an | find "3306" TCP 0.0.0.0:3306 0.0.0.0:0 LISTENING TCP 0.0.0.0:33060 0.0.0.0:0 LISTENING TCP [::]:3306 [::]:0 LISTENING TCP [::]:33060 [::]:0 LISTENING 从你提供的输出结果可以看到&#xff0c;端口3306和33060已经…

9.1 图片的分割处理(c++)

本文的图片处理分为图片分割、图像的亚像素坐标处理。亚像素处理的原理可以看论文一种基于多项式插值改进的亚像素细分算法&#xff0c;该论文的详解及c的代码实现可以看博文基于多项式插值的亚像素边缘定位算法_基于多项式插值的亚像素算法-CSDN博客。下面的内容很多来自以上博…

Sylar C++高性能服务器学习记录22 【ByteArray模块-代码分析篇】

早在19年5月就在某站上看到sylar的视频了&#xff0c;一直认为这是一个非常不错的视频。 由于本人一直是自学编程&#xff0c;基础不扎实&#xff0c;也没有任何人的督促&#xff0c;没能坚持下去。 每每想起倍感惋惜&#xff0c;遂提笔再续前缘。 为了能更好的看懂sylar&…

LLMs的基本组成:向量、Tokens和嵌入

编者按&#xff1a;随着人工智能技术的不断发展&#xff0c;大模型&#xff08;语言、视觉&#xff0c;或多模态模型&#xff09;已成为当今AI应用的核心组成部分。这些模型具有处理和理解自然语言等模态输入的能力&#xff0c;推动了诸如聊天机器人、智能助手、自动文本生成等…

好像也没那么失望!SD3玩起来,Stable Diffusion 3工作流商业及广告设计(附安装包)

今天基于SD3 base 工作流来尝试进行下广告设计&#xff0c;这要是一配上设计文案&#xff0c;视觉感就出来了。下面来看看一些效果展示~ SD3 Medium模型及ComfyUI工作流下载地址&#xff1a;文末领取&#xff01; 1.清凉夏日——西瓜音乐会 提示词&#xff1a; a guitar wi…

数字孪生火电厂:传统能源的数字化转型

通过图扑自主研发的产品 HT for Web &#xff0c;采用可视化与数字孪生技术&#xff0c;打造多样化设计风格和业务视角下的火电厂数字孪生方案。为智慧电厂综合“一张图”管理提供了上层展示技术支撑&#xff0c;助力企业增强对火电厂的信息化和数字化管理水平。

11.docker镜像分层dockerfile优化

docker镜像的分层&#xff08;kvm 链接克隆&#xff0c;写时复制的特性&#xff09; 镜像分层的好处&#xff1a;复用,节省磁盘空间&#xff0c;相同的内容只需加载一份到内存。 修改dockerfile之后&#xff0c;再次构建速度快 分层&#xff1a;就是在原有的基础镜像上新增了服…

Netflix 机器学习科学家的提示词优化经验分享

编者按&#xff1a; 如何充分发挥大模型的潜能&#xff0c;用好大模型&#xff0c;关键在于如何优化向它们发送的提示词&#xff08;prompt&#xff09;&#xff0c;是为提示词工程&#xff08;prompt engineering&#xff09;。 本文Netflix 机器学习科学家Cameron R. Wolfe的…

抖音视频素材在哪找无版权?免版权可以剪辑视频素材网站分享

在抖音视频制作中&#xff0c;素材的选择至关重要。今天&#xff0c;我就为大家推荐几个宝藏网站&#xff0c;帮你找到既好用又无版权纠纷的视频素材。无论你是新手还是老手&#xff0c;这些网站都能满足你的需求。 蛙学府 首先推荐的是蛙学府。这个网站提供丰富的视频素材&am…

STM32硬件接口I2C应用(基于HMC5883L)

目录 概述 1 STM32Cube控制配置I2C 1.1 I2C参数配置 1.2 使用STM32Cube产生工程 2 HAL库函数介绍 2.1 初始化函数 2.2 写数据函数 2.3 读数据函数 3 认识HMC5883L 3.1 HMC5883L功能介绍 3.2 HMC5883L的寄存器 4 HMC5883L驱动程序实现 4.1 驱动函数实现 4.2 完整驱…

xgo 原理探索

Go 单测 mock 方案 Mock 方法原理依赖优点缺点接口 Mock为依赖项定义接口&#xff0c;并提供接口的 Mock 实现。需要定义接口和 Mock 实现。灵活&#xff0c;遵循 Go 的类型系统&#xff1b;易于替换实现。需要更多的样板代码来定义接口和 Mock 实现。Monkey Patching&#xf…

AIGC绘画设计—揭秘Midjourney关键词魔法:让你的AI绘画瞬间起飞

在这个数字化飞速发展的时代&#xff0c;AI技术正以前所未有的速度改变着我们的生活和创作方式。在艺术创作领域&#xff0c;Midjourney作为一款强大的AI绘画工具&#xff0c;正逐渐受到越来越多创作者和爱好者的青睐。今天&#xff0c;我就来为大家揭秘Midjourney背后的关键词…

11.3 Go 标准库的使用技巧

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

Kafka消息能正常发送,但是无法消费问题排查

这里是小奏,觉得文章不错可以关注公众号小奏技术 kafka version kafka_2.13-3.5.0 背景 线上的kafka集群要进行扩容&#xff0c;原先的2broker&#xff0c;扩容之后变成了新增3个broker&#xff0c;然后下掉了原先老的broker。 新集群看着没问题&#xff0c;但是出现了一个…

Java面向对象-抽象类和抽象方法

Java面向对象-抽象类和抽象方法 1、代码案例展示2、抽象类和抽象方法的关系&#xff1a; 1、代码案例展示 1、在一个类中会有一类方法&#xff0c;无需重写&#xff0c;直接使用 2、在一个类中会有一类方法&#xff0c;会对这个方法进行重写 3、一个方法的方法体去掉&#xff…

蚓链数字化营销教你寻找快准直达市场路径小绝招

在当今数字化的商业世界中&#xff0c;蚓链数字化营销成为了企业开拓市场、实现增长的有力工具。它犹如一盏明灯&#xff0c;为您照亮寻找快速直达市场路径的方向。 绝招一&#xff1a;深入的市场调研。利用蚓链数字化营销的大数据分析能力&#xff0c;全面了解目标市场的规模、…