⾃定义springboot-starter实现⽇志打印,并⽀持动态可插拔
1. starter 命名规则:
springboot项⽬有很多专⼀功能的starter组件,命名都是spring-boot-starter-xx,如spring-boot-starter-logging,spring-boot-starter-web,
如果是第三⽅的starter命名⼀般是:xx-springboot-starter 如:mongodb-plus-spring-boot-starter,mybatis-spring-boot-starter;
2. starter的原理:
2.1 springboot的⾃动装配机制
2.2 属性⽂件⾃动装配
3. 需求,我们准备弄个⽇志相关的starter,当别⼈依赖我们的jar包时,在需要打印⽇志的⽅法上贴上对应的注解即可,⽇志打印的前置通知和后置通知内容可以在l或者application.properties中配置
思路:我们需要定义⼀个注解:这样别⼈在需要打⽇志的地⽅贴上该注解即可:
spring boot选择题package com.yang.log.hui.annotion;
import java.lang.annotation.*;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface MyLogAnnotation {
}
接着,我们要让注解⽣效,所以需要⼀个切⾯类:
package com.yang.fig;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import java.util.Arrays;
@Aspect
public class MyLogAspect {
private MylogProperties mylogProperties;
public MyLogAspect(MylogProperties mylogProperties) { 当⼀个bean没有⽆参构造器时,spring创建bean时,对于构造器参数会从容器中取,这⾥其实是省略了@Autowired,该注解可以⽤在⽅法参数上logProperties=mylogProperties;
}
@Pointcut("@annotation(com.yang.log.hui.annotion.MyLogAnnotation)")
public void logAnnotationAnnotationPointcut() {
}
@Around("logAnnotationAnnotationPointcut()")
public Object logInvoke(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.OrDefualtPrefix("请求参数")+ Args())); //如果配置⽂件配了对应的前缀,就⽤配置⽂件的,否则⽤默认的
Object obj = joinPoint.proceed();
System.out.OrDefualtSubfix("返回值:")+ String());//跟前缀⼀样
return obj;
}
}
切⾯类中有个配置⽂件类:
package com.yang.fig;
import org.t.properties.ConfigurationProperties;
import org.springframework.util.StringUtils;
@ConfigurationProperties(value ="mylog") //这个注解可以让配置⽂件中的属性根据前缀来注⼊对应的属性
public class MylogProperties {
//⽇志前缀
private String prefix; //会⾃动配置⽂件中 mylog.prefix的值
//⽇志后缀
private String subfix; //会⾃动配置⽂件中 mylog.subfix的值
public String getOrDefualtPrefix(String defualtPrefix){
if(StringUtils.isEmpty(prefix)){
return defualtPrefix;
}
return prefix;
}
public String getOrDefualtSubfix(String defualtSubfix){
if(StringUtils.isEmpty(subfix)){
return defualtSubfix;
}
return subfix;
}
public void setPrefix(String prefix) {
this.prefix = prefix;
}
public void setSubfix(String subfix) {
this.subfix = subfix;
}
}
要让上⾯类注⼊spring容器,需要⼀个配置类:
package com.yang.fig;
import org.springframework.beans.factory.annotation.Autowired;
import org.t.properties.EnableConfigurationProperties;
import t.annotation.Bean;
import t.annotation.Configuration;
@Configuration
@EnableConfigurationProperties(MylogProperties.class) //该注解可以使MylogProperties注⼊spring容器
public class MyLogAutoConfiguration {
@Bean
public MyLogAspect myLogAspect(@Autowired MylogProperties mylogProperties){
return new MyLogAspect(mylogProperties);
}
}
到此为⽌,只要MyLogAutoConfiguration 注⼊spring容器了,那么他⾥⾯的bean也会被注⼊,⽽怎么样使得MyLogAutoConfiguration 注⼊spring呢,那就要⽤到springboot的⾃动装配机制:
在resources下创建⼀个META-INF⽂件夹,然后在创建⼀个⽂件:spring.factories⽂件加⼊内容:key是固定的
org.springframework.boot.autoconfigure.EnableAutoConfiguration,value可以有多个
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.yang.fig.MyLogAutoConfiguration
依赖:平时我们在写l时会有提⽰,那么我也想让我的⽇志配置也会⽣效,也就是当我输⼊mylog时,会提⽰mylog.prefix 或者mylog.subfix,此时需要下⾯的配置:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
因为我们项⽬⽤到springboot和aop,所以需要:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
注意:maven打包时,不能⽤spring-boot-maven-plugin,我⽤它打包没报错,给其他服务引⽤对应的jar时,启动报错了。需要换成:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
⾄此,项⽬创建完毕:现在看下整体情况:
pom⽂件整体:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="/POM/4.0.0" xmlns:xsi="/2001/XMLSchema-instance"
xsi:schemaLocation="/POM/4.0.0 /xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.0.RELEASE</version>
<relativePath/><!-- lookup parent from repository -->
</parent>
<groupId>com.yang.xiao.hui</groupId>
<artifactId>log-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>log-spring-boot-starter</name>
<description>Demo project for Spring Boot</description>
<packaging>jar</packaging>
<properties>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</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>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
项⽬打包进⾏测试:
新建web项⽬引⼊我们的⽇志依赖:
<dependency>
<groupId>com.yang.xiao.hui</groupId>
<artifactId>log-spring-boot-starter</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
测试项⽬提供⼀个controller,对应⽅法贴上我们的⽇志注解:package com.yang.xiao.ller;
import com.yang.log.hui.annotion.MyLogAnnotation;
import com.yang.xiao.ity.Product;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class ProductController {
@RequestMapping("/info/{id}")
@ResponseBody
@MyLogAnnotation //这个是我们的⽇志注解
public Product getProductInfo(@PathVariable("id") Integer id){
Product product = new Product();
product.setId(id);
product.setName("苹果⼿机");
return product;
}
}
测试项⽬的整体情况:
此时我们没有在yml中配置⽇志前缀,启动测试项⽬测试:
浏览器输⼊:localhost:8673/info/3
控制台输出:
我们在yml配置⽂件输⼊前后缀:
可见,有提⽰,跟我们配置其他组件的属性⼀样:
重启测试项⽬,再次在浏览器输⼊:localhost:8673/info/3
⾄此,我们实现了⼀个完整的springboot starter,在springboot项⽬中,很多组件的底层原理都是这样实现的,通过这种实现,可以做底层架构,然后给其他服务使⽤,如可以校验请求参数,处理返回结果等
附加git代码地址: gitee/yangxioahui/log-spring-boot-starter.git
上⾯的实现,有个问题,当我不想⽤该功能时,相关的bean也会注⼊容器中,那如果我想实现动态可插拔功能,怎么处理?
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论