自定义一个starter

简介: 自定义一个打印方法执行时间的切面starter

1. starter工程的命名

starter 是一个开箱即用的组件,减少不必要的重复代码,重复配置。

例如,redis 的 starter,spring-boot-starter-data-redis  

Spring 官方定义的 starter 通常命名遵循的格式为 spring-boot-starter-{name}。

例如 spring-boot-starter-web

非官方 starter 命名应遵循 {name}-spring-boot-starter 的格式。

例如,dubbo-spring-boot-starterimage.png

2. 需求

定义 @AspectLog 注解,用于标注需要打印执行时间的方法

3. 实现

3.1 创建一个SpringBoot项目

这里项目名称为 aspectlog-spring-boot-starter

3.2 导入依赖

<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency>

关于 spring-boot-configuration-processor 的说明,引自 springBoot 官方文档

Spring Boot uses an annotation processor to collect the conditions on auto-configurations in a metadata file ( META-INF/spring-autoconfigure-metadata.properties ). If that file is present, it is used to eagerly filter auto-configurations that do not match, which will improve startup time. It is recommended to add the following dependency in a module that contains auto-configurations

大概意思就是:写 starter 时,在 pom 中配置 spring-boot-configuration-processor,在编译时会自动收集配置类的条件,写到一个 META-INF/spring-configuration-metadata.properties 文件中

3.3 编写自动配置逻辑

3.3.1 各种 Conditions
Conditions 描述
@ConditionalOnBean 在存在某个 bean 的时候
@ConditionalOnMissingBean 不存在某个 bean 的时候
@ConditionalOnClass 当前 classpath 可以找到某个类型的类时
@ConditionalOnMissingClass 当前 classpath 不可以找到某个类型的类时
@ConditionalOnResource 当前 classpath 是否存在某个资源文件
@ConditionalOnProperty 当前 jvm 是否包含某个系统属性为某个值
@ConditionalOnWebApplication 当前 spring context 是 web 应用程序才加载
@ConditionalOnNotWebApplication

不是web应用才加载

这里选用 @ConditionalOnProperty。即配置文件中的属性aspectLog.enable=true,才加载我们的配置类。

3.3.2 定义 @AspectLog 注解

该注解用于标注需要打印执行时间的方法

packageorg.example.aspectlog.interfaces;
importjava.lang.annotation.*;
/*** 定义AspectLog注解,该注解用于标注需要打印执行时间的方法。*/@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Documentedpublic@interfaceAspectLog {
}
3.3.3 定义配置文件类
packageorg.example.aspectlog.configuration;
importorg.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties(prefix=AspectLogProperties.PREFIX)
publicclassAspectLogProperties {
publicstaticfinalStringPREFIX="aspectlog";
privatebooleanenable;
publicbooleanisEnable() {
returnenable;
    }
publicvoidsetEnable(booleanenable) {
this.enable=enable;
    }
}
3.3.4 定义自动配置类
packageorg.example.aspectlog.configuration;
importorg.aspectj.lang.ProceedingJoinPoint;
importorg.aspectj.lang.annotation.Around;
importorg.aspectj.lang.annotation.Aspect;
importorg.slf4j.Logger;
importorg.slf4j.LoggerFactory;
importorg.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
importorg.springframework.boot.context.properties.EnableConfigurationProperties;
importorg.springframework.context.annotation.Configuration;
importorg.springframework.context.annotation.EnableAspectJAutoProxy;
importorg.springframework.core.PriorityOrdered;
@Aspect@EnableAspectJAutoProxy(exposeProxy=true, proxyTargetClass=true)
@EnableConfigurationProperties(AspectLogProperties.class)
@Configuration@ConditionalOnProperty(prefix=AspectLogProperties.PREFIX, name="enable", havingValue="true", matchIfMissing=true)
publicclassAspectLogAutoConfigurationimplementsPriorityOrdered {
privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(AspectLogAutoConfiguration.class);
@Around("@annotation(org.example.aspectlog.interfaces.AspectLog)")
publicObjectisOpen(ProceedingJoinPointpjp) throwsThrowable {
StringtaskName=pjp.getSignature().toString().substring(pjp.getSignature().toString().indexOf(" "), pjp.getSignature().toString().indexOf("("));
taskName=taskName.trim();
longtime=System.currentTimeMillis();
Objectresult=pjp.proceed();
LOGGER.info("method:{} run:{} ms", taskName, (System.currentTimeMillis() -time));
returnresult;
    }
@OverridepublicintgetOrder() {
// 保证事务等切面先执行returnInteger.MAX_VALUE;
    }
}

上面 @ConditionalOnProperty 中的参数说明

prefix = AspectLogProperties.PREFIX,即AspectLogProperties中常量属性PREFIX="aspectlog"

name = "enable",name的名称为enable时

havingValue = "true",上面的name为enable的值为true时才开启

matchIfMissing = true,匹配不到对应的属性的时也开启

即:

当配置文件有aspectLog.enable=true时开启,如果配置文件没有设置aspectLog.enable也开启。

3.4 配置 META-INF/spring.factories

META-INF/spring.factories是spring的工厂机制,在这个文件中定义的类,都会被自动加载。多个配置使用逗号分割,换行用\

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\org.example.aspectlog.configuration.AspectLogAutoConfiguration

3.5 打包测试

3.5.1 目录结构

image.png

3.5.2 mvn install到本地

image.png

3.5.3 其他项目中引用测试
3.5.3.1 pom引用
<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId><optional>true</optional></dependency><dependency><groupId>org.example</groupId><artifactId>aspectlog-spring-boot-starter</artifactId><version>1.0.0</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency></dependencies>
3.5.3.2 测试代码
@RestController@RequestMapping("/test")
publicclassTestController {
@AspectLog@GetMapping("/test")
publicStringtest () throwsInterruptedException {
return"success";
    }
}
3.5.3.3 测试结果

image.png

目录
相关文章
|
1月前
|
弹性计算 人工智能 双11
2025年阿里云双十一优惠活动,云服务器租赁价格多少钱一年?
2025阿里云双11优惠来袭!轻量应用服务器38元/年起,ECS云服务器99元/年起,2核4G配置仅需199元/年,新老用户同享,续费不涨价。限量秒杀+大额代金券叠加,企业用户还可领专属补贴,最高享10万出海支持。点击直达活动页抢购→
561 5
|
安全 NoSQL Java
SpringSecurity原理简述(上)
SpringSecurity原理简述
282 2
|
SQL 数据库
解决SQL报错提供了过多的参数,最多应为 2100
解决SQL报错提供了过多的参数,最多应为 2100
1061 0
|
SQL NoSQL Oracle
响应式关系数据库处理R2DBC
响应式关系数据库处理R2DBC
|
人工智能 运维 监控
阿里云ACK容器服务生产级可观测体系建设实践
本文整理自2024云栖大会冯诗淳(花名:行疾)的演讲,介绍了阿里云容器服务团队在生产级可观测体系建设方面的实践。冯诗淳详细阐述了容器化架构带来的挑战及解决方案,强调了可观测性对于构建稳健运维体系的重要性。文中提到,阿里云作为亚洲唯一蝉联全球领导者的容器管理平台,其可观测能力在多项关键评测中表现优异,支持AI、容器网络、存储等多个场景的高级容器可观测能力。此外,还介绍了阿里云容器服务在多云管理、成本优化等方面的最新进展,以及即将推出的ACK AI助手2.0,旨在通过智能引擎和专家诊断经验,简化异常数据查找,缩短故障响应时间。
阿里云ACK容器服务生产级可观测体系建设实践
|
Java Spring
面对Spring 不支持java8的改变方法
面对Spring 不支持java8的改变方法
|
Kubernetes Cloud Native 云计算
探索K8S的绝佳选择:Killercoda与Play-with-K8s在线练习平台
探索K8S的绝佳选择:Killercoda与Play-with-K8s在线练习平台
3209 1
|
JSON NoSQL 前端开发
SpringBoot定义优雅全局统一Restful API 响应框架完结撒花篇封装starter组件
SpringBoot定义优雅全局统一Restful API 响应框架完结撒花篇封装starter组件
SpringBoot定义优雅全局统一Restful API 响应框架完结撒花篇封装starter组件