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

目录
相关文章
|
2月前
|
JavaScript Java 程序员
SpringBoot自动配置及自定义Starter
Java程序员依赖Spring框架简化开发,但复杂的配置文件增加了负担。SpringBoot以“约定大于配置”理念简化了这一过程,通过引入各种Starter并加载默认配置,几乎做到开箱即用。
133 10
SpringBoot自动配置及自定义Starter
|
9月前
|
IDE Java Maven
SpringBoot自定义starter及自动配置
SpringBoot自定义starter及自动配置
|
9月前
|
消息中间件 Java Maven
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
深入理解Spring Boot Starter:概念、特点、场景、原理及自定义starter
|
8月前
|
Java Maven 开发者
Spring Boot中的自定义Starter开发
Spring Boot中的自定义Starter开发
|
9月前
|
Java Maven
6.自定义starter
6.自定义starter
51 0
|
XML Java 数据格式
如何实现一个自定义的starter
SpringFactoriesLoader加载器加载指定ClassLoader下面的所有的META-INF/spring.factories文件,并将文件解析内容存在Map&lt;string,list&gt;中。然后通过loadFactoryNames传递过来的class的名称从map中获取该类的配置列表。通过Set集合进行去重操作。执行过滤组件操作,而这些操作都是在AutoConfigurationImportFilter接口下的组件实现的,也即FilterSpringBootCondition实现抽象类的。下面有OnBeanCondition、OnClassCondition、OnWebApplic
36844 5
如何实现一个自定义的starter
|
NoSQL Java Redis
SpringBoot自定义Starter
SpringBoot自定义Starter
202 0
|
Java Maven
自定义Starter
启动器模块是一个 空 jar 文件,仅提供辅助性依赖管理,这些依赖可能用于自动装配或者其他类库;
自定义Starter
|
Java 测试技术 Maven
玩转Spring-自定义Spring Starter
玩转Spring-自定义Spring Starter
|
Java Maven 开发者
自定义 starter|学习笔记
快速学习自定义 starter
自定义 starter|学习笔记

热门文章

最新文章