news 2026/4/16 12:49:11

自定义starter,扫描指定注解的bean

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
自定义starter,扫描指定注解的bean

自定义starter

相当于自己根据配置信息,生成了一个默认的bean,

  1. 导入依赖:
<?xml version="1.0" encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>3.5.10</version><relativePath/><!-- lookup parent from repository --></parent><groupId>com.cj</groupId><artifactId>hello-spring-boot-starter</artifactId><version>0.0.1-SNAPSHOT</version><name>hello-spring-boot-starter</name><description>hello-spring-boot-starter</description><url/><licenses><license/></licenses><developers><developer/></developers><scm><connection/><developerConnection/><tag/><url/></scm><properties><java.version>17</java.version></properties><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency></dependencies><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><annotationProcessorPaths><path><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId></path><path><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></path></annotationProcessorPaths></configuration></plugin></plugins></build></project>

将springboot启动类,测试类删掉,,将maven打包成jar的配置删掉,,
2. 自定义一个配置类,,来定义配置

packagecom.cj.hellospringbootstarter;importlombok.Data;importorg.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix="mytest")@DatapublicclassHelloProperties{privateStringid;privateStringname;privateStringaddress;}
  1. 通过这个配置加载一个默认的 Bean
@Data@NoArgsConstructorpublicclassHelloService{privateStringname;privateStringaddress;publicHelloService(Stringname,Stringaddress){this.name=name;this.address=address;}}
@Configuration@ComponentScan@EnableConfigurationProperties(HelloProperties.class)publicclassHelloServiceAutoConfiguration{@AutowiredprivateHelloPropertieshelloProperties;@BeanpublicHelloServicehelloService(){returnnewHelloService(helloProperties.getName(),helloProperties.getAddress());}}

容器中就有这个默认的 HelloService的bean,,

  1. 设置自动装配
    springboot3是在META-INF/spring文件夹下创建org.springframework.boot.autoconfigure.AutoConfiguration.imports这个文件,,
    填入自动配置类的全限定类名

springboot2是在META-INF下面创建spring.factories

  1. 打包使用
<dependency><groupId>com.cj</groupId><artifactId>hello-spring-boot-starter</artifactId><version>0.0.1-SNAPSHOT</version></dependency>
@RestController@LogpublicclassHelloController{@AutowiredHelloServicehelloService;@GetMapping("/hello")publicHelloServicegetHelloService(){returnhelloService;}}

自定义一个注解,写在starter里面,动态的增强被标注这个注解的类,,,
可以用spring中BeanPostProcessor: spring完成 实例化,配置,,, 在初始化bean的前后,可以实现一些自定义的配置,有两个方法:

  • postProcessBeforeInitialization : bean初始化之前调用
  • postProcessAfterInitialization: bean初始化之后调用

如果想增强指定的注解标注的类,,就可以写在BeanPostProcessor中,拦截指定注解,增强:

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public@interfaceLog{/** * 是否打印参数 * @return */booleanprintArgs()defaulttrue;booleanprintResult()defaulttrue;/** * 是否打印方法耗时 * @return */booleanprintCostTime()defaulttrue;}
packagecom.cj.hellospringbootstarter.annotation;importorg.springframework.beans.BeansException;importorg.springframework.beans.factory.config.BeanPostProcessor;importorg.springframework.cglib.proxy.Callback;importorg.springframework.cglib.proxy.Enhancer;importorg.springframework.cglib.proxy.MethodInterceptor;importorg.springframework.cglib.proxy.MethodProxy;importorg.springframework.stereotype.Component;importjava.lang.reflect.Method;importjava.util.Arrays;/** * 对@Log 标注的 bean进行统一的 增强 * * * BeanPostProcessor : spring完成实例化,配置,初始化一个bean之后,,可以实现一些自定义的逻辑 * - postProcessBeforeInitialization : bean初始化之前调用 * - postProcessAfterInitialization : bean初始化之后调用 */@ComponentpublicclassLogBeanPostProcessorimplementsBeanPostProcessor{@OverridepublicObjectpostProcessAfterInitialization(Objectbean,StringbeanName)throwsBeansException{Class<?>beanClass=getTargetClass(bean);// 是否标记了 @Log注解if(beanClass.isAnnotationPresent(Log.class)){LoglogAnnotation=beanClass.getAnnotation(Log.class);ObjectenhanceBean=createLogEnhanceProxy(bean,beanClass,logAnnotation);returnenhanceBean;}returnbean;}privateObjectcreateLogEnhanceProxy(ObjecttargetBean,Class<?>targetClass,LoglogAnnotation){Enhancerenhancer=newEnhancer();enhancer.setSuperclass(targetClass);// MethodInterceptor : cglib的方法拦截器,,当你调任何方法的时候,都会执行这个enhancer.setCallback(newMethodInterceptor(){@OverridepublicObjectintercept(Objectobj,Methodmethod,Object[]args,MethodProxyproxy)throwsThrowable{// 跳过Object的基础方法if(isObjectBaseMethod(method)){returnproxy.invokeSuper(obj,args);}try{if(logAnnotation.printArgs()){System.out.printf("[日志增强]%s.%s()入参:%s%n",targetClass.getSimpleName(),method.getName(),Arrays.toString(args));}longstartTime=System.currentTimeMillis();Objectresult=proxy.invokeSuper(obj,args);if(logAnnotation.printCostTime()){longendTime=System.currentTimeMillis();System.out.printf("[日志耗时]%s.%s() 耗时%s",targetClass.getSimpleName(),method.getName(),startTime-endTime);}returnresult;}catch(Throwablee){System.out.printf("日志增强失败 %s.%s() 异常为:%s",targetClass.getSimpleName(),method.getName(),e.getMessage());throwe;}};});ObjectenhancedBean=enhancer.create();System.out.println("增强完成"+targetClass.getName());returnenhancedBean;}/** * 获取bean的真实类型 * @param bean * @return */privateClass<?>getTargetClass(Objectbean){Class<?>clazz=bean.getClass();// 如果是CGLIB代理类,,获取父类if(clazz.getName().contains("$$EnhancerByCGLIB$$")){returnclazz.getSuperclass();}returnclazz;}privatebooleanisObjectBaseMethod(Methodmethod){// 获取声明该方法的类Class<?>declaringClass=method.getDeclaringClass();// method.getDeclaringClass()returndeclaringClass==Object.class&&(method.getName().equals("toString")||method.getName().equals("hashCode")||method.getName().equals("equals"));}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/7 21:03:17

从 Clawdbot 看:如何打造一个真正有价值的智能 Bot 产品

很多 Bot 看起来很“智能”&#xff0c;但真正能长期创造价值的却很少。 Clawdbot 这一类产品的关键不在“会不会 AI”&#xff0c;而在是否把人的工作能力&#xff0c;系统性地转化成可复制、可进化的产品能力。一、Clawdbot 的核心价值&#xff0c;本质是什么&#xff1f; 一…

作者头像 李华
网站建设 2026/4/13 12:40:00

Qt Creator中修改源文件编码

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 一、查看当前文件编码&#xff08;前提&#xff09;二、单个文件编码修改&#xff08;核心操作&#xff09;方式1&#xff1a;编辑器工具栏快捷修改&#xff08;推荐…

作者头像 李华
网站建设 2026/4/16 9:05:01

文明6-mod制作-游戏素材AI生成记录

目录 主流工具深度解析 关键更新&#xff1a;免费工具的最新实时动态&#xff08;截至2026年1月30日&#xff09; 给开发者的核心建议 AI生成提示词参考 总结 主流工具深度解析 Midjourney&#xff1a;生成效果惊艳&#xff0c;适合概念设计&#xff0c;但需付费。 Stable…

作者头像 李华
网站建设 2026/4/15 22:42:00

基于springboot的旧物回收商城系统的设计与实现

背景分析 随着环保意识增强和可持续发展理念普及&#xff0c;旧物回收成为减少资源浪费的重要途径。传统回收模式存在信息不对称、效率低下等问题&#xff0c;数字化平台能有效解决这些痛点。SpringBoot作为轻量级Java框架&#xff0c;具备快速开发、微服务支持等优势&#xf…

作者头像 李华
网站建设 2026/4/16 1:08:31

Java毕设选题推荐:基于Java web的酒店管理系统设计与实现办理入住登记、分配具体房间,系统自动更新房态【附源码、mysql、文档、调试+代码讲解+全bao等】

博主介绍&#xff1a;✌️码农一枚 &#xff0c;专注于大学生项目实战开发、讲解和毕业&#x1f6a2;文撰写修改等。全栈领域优质创作者&#xff0c;博客之星、掘金/华为云/阿里云/InfoQ等平台优质作者、专注于Java、小程序技术领域和毕业项目实战 ✌️技术范围&#xff1a;&am…

作者头像 李华