仅需四步,写一个springboot starter
这个系列分为5篇
1. @Component,@Service等注解是如何被解析的
2. @Enable驱动原理
3. @EnableAutoConfiguration处理逻辑
引言
只要你用Springboot,一定会用到各种spring-boot-starter。其实写一个spring-boot-starter
,仅需4步。下面我们就写一个starter,它将实现,在日志中打印方法执行时间。
第一步 创建maven项目
在使用spring-boot-starter,会发现,有的项目名称是 XX-spring-boot-starter,有的是
spring-boot-starter-XX,这个项目的名称有什么讲究呢?
从springboot官方文档摘录如下:
Do not start your module names with spring-boot, even if you use a different Maven groupId. We may offer official support for the thing you auto-configure in the future. As a rule of thumb, you should name a combined module after the starter.
从这段话可以看出spring-boot-starter命名的潜规则。
命名潜规则
spring-boot-starter-XX是springboot官方的starter
XX-spring-boot-starter是第三方扩展的starter
打印方法执行时间的功能,需要用到aop,咱们的项目就叫做
aspectlog-spring-boot-starter吧。
项目的pom文件如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>aspectlog-spring-boot-starter</artifactId>
<version>1.0.2</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.15.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
</dependencies>
</project>
关于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: <dependency> <groupId> org.springframework.boot </groupId> <artifactId> spring-boot-autoconfigure-processor </artifactId> <optional> true </optional> </dependency>
简单说就是 写starter时,在pom中配置 spring-boot-autoconfigure-processor,
在编译时会自动收集配置类的条件,写到一个 META-INF/spring-autoconfigure-metadata.properties中。
第二步写自动配置逻辑
各种condition
类型 |
注解 |
说明 |
---|---|---|
Class Conditions类条件注解 |
@ConditionalOnClass |
当前classpath下有指定类才加载 |
@ConditionalOnMissingClass |
当前classpath下无指定类才加载 |
|
Bean ConditionsBean条件注解 |
@ConditionalOnBean |
当期容器内有指定bean才加载 |
@ConditionalOnMissingBean |
当期容器内无指定bean才加载 |
|
Property Conditions环境变量条件注解(含配置文件) |
@ConditionalOnProperty |
prefix 前缀name 名称havingValue 用于匹配配置项值matchIfMissing 没找指定配置项时的默认值 |
ResourceConditions 资源条件注解 |
@ConditionalOnResource |
有指定资源才加载 |
Web Application Conditionsweb条件注解 |
@ConditionalOnWebApplication |
是web才加载 |
@ConditionalOnNotWebApplication |
不是web才加载 |
|
SpEL Expression Conditions |
@ConditionalOnExpression |
符合SpEL 表达式才加载 |
本次我们就选用@ConditionalOnProperty。即配置文件中有aspectLog.enable=true,才加载我们的配置类。
下面开始写自动配置类
2.1.定义AspectLog注解,该注解用于标注需要打印执行时间的方法。
package com.shanyuan.autoconfiguration.aspectlog;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* class_name: ScheduleManage
* describe: 用于控制定时任务的开启与关闭
* 对应切面
* creat_user: wenl
* creat_time: 2018/11/10 18:45
**/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AspectLog {
}
2.2定义配置文件对应类
package com.shanyuan.autoconfiguration.aspectlog;
import org.springframework.boot.context.properties.ConfigurationProperties;
@ConfigurationProperties("aspectLog")
public class AspectLogProperties {
private boolean enable;
public boolean isEnable() {
return enable;
}
public void setEnable(boolean enable) {
this.enable = enable;
}
}
2.3定义自动配置类
package com.shanyuan.autoconfiguration.aspectlog;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.*;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.core.PriorityOrdered;
@Aspect
@EnableAspectJAutoProxy(exposeProxy = true, proxyTargetClass = true)
@Configuration
@ConditionalOnProperty(prefix = "aspectLog", name = "enable",
havingValue = "true", matchIfMissing = true)
public class AspectLogAutoConfiguration implements PriorityOrdered {
protected Logger logger = LoggerFactory.getLogger(getClass());
@Around("@annotation(com.shanyuan.autoconfiguration.aspectlog.AspectLog) ")
public Object isOpen(ProceedingJoinPoint thisJoinPoint)
throws Throwable {
//执行方法名称
String taskName = thisJoinPoint.getSignature()
.toString().substring(
thisJoinPoint.getSignature()
.toString().indexOf(" "),
thisJoinPoint.getSignature().toString().indexOf("("));
taskName = taskName.trim();
long time = System.currentTimeMillis();
Object result = thisJoinPoint.proceed();
logger.info("method:{} run :{} ms", taskName,
(System.currentTimeMillis() - time));
return result;
}
@Override
public int getOrder() {
//保证事务等切面先执行
return Integer.MAX_VALUE;
}
}
配置类简要说明:
@ConditionalOnProperty(prefix = "aspectLog", name = "enable",havingValue = "true", matchIfMissing = true)
当配置文件有aspectLog.enable=true时开启,如果配置文件没有设置aspectLog.enable也开启。
第三步META-INF/spring.factories
META-INF/spring.factories是spring的工厂机制,在这个文件中定义的类,都会被自动加载。多个配置使用逗号分割,换行用
如果有兴趣可以查看这2篇blog:
2.@Enable驱动原理(设置连接)
3.@EnableAutoConfiguration处理逻辑(设置连接)
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
com.shanyuan.autoconfiguration.aspectlog.AspectLogAutoConfiguration
第四步打包测试
这是我们最终的目录结构
在IDEA中,进行mvn intall
打包完成后,在其他项目中的pom中引入进行测试
参考资料
- java教程
- Java快速入门
- Java 开发环境配置
- Java基本语法
- Java 对象和类
- Java 基本数据类型
- Java 变量类型
- Java 修饰符
- Java 运算符
- Java 循环结构
- Java 分支结构
- Java Number类
- Java Character类
- Java String类
- Java StringBuffer和StringBuilder类
- Java 数组
- Java 日期时间
- Java 正则表达式
- Java 方法
- Java 流(Stream)、文件(File)和IO
- Java 异常处理
- Java 继承
- Java 重写(Override)与重载(Overload)
- Java 多态
- Java 抽象类
- Java 封装
- Java 接口
- Java 包(package)
- Java 数据结构
- Java 集合框架
- Java 泛型
- Java 序列化
- Java 网络编程
- Java 发送邮件
- Java 多线程编程
- Java Applet基础
- Java 文档注释
- typescript基础篇(6):泛型
- Flutter 初学者必读的高级布局规则
- Docker Swarm群集配置实战——第二战
- Python 基础(五):序列
- OpenCV黑魔法之隐身衣 | 附源码
- SQL 统计用户留存
- 常用的前端JQ插件
- 面向对象编程(设计模式)需要遵循的 6 个基本原则
- SAP CRM Application Extension Tool的Custom Behavior
- Python 基础(四):字符串
- 使用Faster-RCNN进行指定GPU训练(续)
- SAP CDS view自学教程之十:SAP CDS view扩展性(Extensibility)实现原理
- 使用Faster-RCNN进行指定GPU训练
- Faster RCNN 环境配置
- SAP cross distribution chain status在Fiori应用中的draft handling