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-starter
。
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注解,该注解用于标注需要打印执行时间的方法。*/ElementType.METHOD) (RetentionPolicy.RUNTIME) (public@interfaceAspectLog { }
3.3.3 定义配置文件类
packageorg.example.aspectlog.configuration; importorg.springframework.boot.context.properties.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; exposeProxy=true, proxyTargetClass=true) (AspectLogProperties.class) (prefix=AspectLogProperties.PREFIX, name="enable", havingValue="true", matchIfMissing=true) (publicclassAspectLogAutoConfigurationimplementsPriorityOrdered { privatestaticfinalLoggerLOGGER=LoggerFactory.getLogger(AspectLogAutoConfiguration.class); "@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; } publicintgetOrder() { // 保证事务等切面先执行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 目录结构
3.5.2 mvn install到本地
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 测试代码
"/test") (publicclassTestController { "/test") (publicStringtest () throwsInterruptedException { return"success"; } }
3.5.3.3 测试结果