自定义一个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

目录
相关文章
|
5月前
|
消息中间件 Java Maven
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
|
4月前
|
Java Maven 开发者
Spring Boot中的自定义Starter开发
Spring Boot中的自定义Starter开发
|
5月前
|
Java Maven
6.自定义starter
6.自定义starter
31 0
|
6月前
|
Java 微服务 Spring
Spring Boot中获取配置参数的几种方法
Spring Boot中获取配置参数的几种方法
543 2
|
NoSQL Java Redis
自定义Sprin-Boot-Starter
自定义Sprin-Boot-Starter
42 0
|
Java Maven
自定义Starter
启动器模块是一个 空 jar 文件,仅提供辅助性依赖管理,这些依赖可能用于自动装配或者其他类库;
自定义Starter
|
Java 大数据 数据库
Spring Boot配置绑定
你好看官,里面请!今天笔者讲的是Spring Boot配置绑定。不懂或者觉得我写的有问题可以在评论区留言,我看到会及时回复。 注意:本文仅用于学习参考,不可用于商业用途,如需转载请跟我联系。
219 2
|
Java Maven 开发者
自定义 starter|学习笔记
快速学习自定义 starter
自定义 starter|学习笔记
|
NoSQL Java 应用服务中间件
SpringBoot项目为什么需要引入大量的starter?如何自定义starter?
为什么我们在使用SpringBoot框架开发Java Web应用需要引入大量的starter?例如,我们引入Redis就在Maven中导入spring-boot-starter-data-redis。大家都知道SpringBoot的核心功能是自动装配,简化配置,我们通过starter实现SpringBoot自动装配的功能。那么我们如何去构建自己的starter呢?
299 0
|
消息中间件 Java
你可知道publisherReturns参数在spring-boot-starter-amqp中的作用?
你可知道publisherReturns参数在spring-boot-starter-amqp中的作用?
你可知道publisherReturns参数在spring-boot-starter-amqp中的作用?