SpringBoot自定义日志Starter,可动态拔插配置

在作SpringBoot开发时,各类starter (场景启动器) 必不可少,它们就像可插拔式的插件,只要在pom文件中引用 springboot 提供的场景启动器, 再进行少许的配置就可使用相应的功能,但SpringBoot并不能囊括咱们的全部使用场景,这时候就须要咱们自定义starter来实现定制化功能。java

项目源码地址:GitHubgit

命名规范

官方命名(Springboot旗下)

前缀:spring-boot-starter- 模式:spring-boot-starter-{模块名} 举例:spring-boot-starter-test、spring-boot-starter-log4j2github

自定义命名(第三方)

后缀:-spring-boot-starter 模式:{模块}-spring-boot-starter 举例:mybatis-spring-boot-starterspring

Spring Boot Starter工做原理

  • 1.SpringBoot在启动的时候会扫描项目所依赖的JAR包,寻找包含spring.factories文件的JAR包
  • 2.读取spring.factories文件获取配置的自动配置类AutoConfiguration
  • 3.将自动配置类下知足条件(@ConditionalOnXxx)的@Bean放入到Spring容器中(Spring Context)

img

自定义Starter

建立工程

image-20210110102712650

添加gradle依赖

annotationProcessor "org.springframework.boot:spring-boot-configuration-processor"implementation 'org.springframework.boot:spring-boot-starter-aop'复制代码

建立日志注解

package com.codelong.log.annotion;import java.lang.annotation.*;/**
 * 日志注解
 *
 * @author codelong
 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.METHOD)@Documentedpublic @interface MyLog {

}复制代码

建立Proprerty类

package com.codelong.log.config;import org.springframework.boot.context.properties.ConfigurationProperties;import org.springframework.context.annotation.PropertySource;/**
 * 日志配置文件类
 *
 * @author codelong
 */@ConfigurationProperties(value = "mylog")@PropertySource(value = "classpath:application.yml", encoding = "UTF-8")public class MyLogProperties {/**
     * 日志开始前缀
     */private String prefix;/**
     * 日志结束前缀
     */private String suffix;public String getPrefix() {return prefix;
    }public void setPrefix(String prefix) {this.prefix = prefix;
    }public String getSuffix() {return suffix;
    }public void setSuffix(String suffix) {this.suffix = suffix;
    }
}复制代码

建立AOP注解切面类

package com.codelong.log.config;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;/**
 * MyLog注解切面类
 *
 * @author codelong
 */@Aspectpublic class MyLogAspect {private MyLogProperties myLogProperties;public MyLogAspect(MyLogProperties myLogProperties) {this.myLogProperties = myLogProperties;
    }@Pointcut("@annotation(com.codelong.log.annotion.MyLog)")public void logAnnotationAnnotationPointcut() {
    }@Around("logAnnotationAnnotationPointcut()")public Object logInvoke(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println(myLogProperties.getPrefix().concat(Arrays.toString(joinPoint.getArgs())));
        Object obj = joinPoint.proceed();
        System.out.println(myLogProperties.getSuffix().concat(obj.toString()));return obj;
    }

}复制代码

建立自动配置类

要让上面类注入spring容器,须要一个自动配置类springboot

package com.codelong.log.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/**
 * 配置类
 *
 * @author codelong
 */@Configuration@EnableConfigurationProperties(MyLogProperties.class) // 该注解可使MyLogProperties注入spring容器public class MyLogAutoConfiguration {@Beanpublic MyLogAspect myLogAspect(@Autowired MyLogProperties myLogProperties) {return new MyLogAspect(myLogProperties);
    }
}复制代码

@Configuration //指定这个类是一个配置类 @ConditionalOnXXX //指定条件成立的状况下自动配置类生效 @AutoConfigureOrder //指定自动配置类的顺序 @Bean //向容器中添加组件 @ConfigurationProperties //结合相关xxxProperties来绑定相关的配置 @EnableConfigurationProperties //让xxxProperties生效加入到容器中 @ConditionalOnClass:当类路径classpath下有指定的类的状况下进行自动配置 @ConditionalOnMissingBean:当容器(Spring Context)中没有指定Bean的状况下进行自动配置 @ConditionalOnProperty(prefix = “example.service”,name = "auth", value = “enabled”, matchIfMissing = true),当配置文件中example.service.auth.enabled=true时进行自动配置,若是没有设置此值就默认使用matchIfMissing对应的值 @ConditionalOnMissingBean,当Spring Context中不存在该Bean时。 @ConditionalOnBean:当容器(Spring Context)中有指定的Bean的条件下 @ConditionalOnMissingClass:当类路径下没有指定的类的条件下 @ConditionalOnExpression:基于SpEL表达式做为判断条件 @ConditionalOnJava:基于JVM版本做为判断条件 @ConditionalOnJndi:在JNDI存在的条件下查找指定的位置 @ConditionalOnNotWebApplication:当前项目不是Web项目的条件下 @ConditionalOnWebApplication:当前项目是Web项目的条件下 @ConditionalOnResource:类路径下是否有指定的资源 @ConditionalOnSingleCandidate:当指定的Bean在容器中只有一个,或者在有多个Bean的状况下,用来指定首选的Beanmybatis

配置文件

在resources/META-INF/下建立文件spring.factories,SpringBoot在启动的时候会扫描项目所依赖的JAR包,寻找包含spring.factories文件的JAR包,读取spring.factories文件获取配置的自动配置类AutoConfiguration,而后将自动配置类下知足条件(@ConditionalOnXxx)的@Bean放入到Spring容器中(Spring Context),这样使用者就能够直接用来注入,由于该类已经在容器中了app

spring.factories文件内容:key是固定的org.springframework.boot.autoconfigure.EnableAutoConfiguration,value能够有多个maven

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
  com.codelong.log.config.MyLogAutoConfiguration复制代码

目录结构以下ide

image-20210110145850252

打包安装到本地

这里使用maven-publish打包插件,不用插件的可使用maven打包命令spring-boot

添加插件

id 'maven-publish'复制代码

添加打包信息

publishing {
    publications {
        mavenJava(MavenPublication) {
            from components.java
        }
    }
    repositories {
        mavenLocal()
    }
}
tasks.withType(GenerateModuleMetadata) {
    enabled = false}

jar {
    enabled = true}复制代码

执行打包任务

image-20210110144525750

测试

新建一个基础项目,添加本身的依赖

implementation 'com.codelong:log-spring-boot-starter:1.0.0'复制代码

添加一个接口用于测试

    /**
     * 测试
     */@MyLog@PostMapping("/testLog")public String testLog(@RequestBody Message message) {return "日志测试";
    }复制代码

修改yml文件(会有咱们日志配置的提示)

image-20210110144913031

server:
  port: 8080
  servlet:context-path: /mylog:
  prefix: 请求开始---
  suffix: 请求结束---复制代码

启动项目post访问:http://127.0.0.1:8080/testLog

查看控制台日志

image-20210110145321969

拓展动态拔插开关

当咱们不用这个功能时,这些bean仍是会注入到spring容器中,这时咱们就须要动态拔插这个功能,主要是用到了@ConditionalOnBean这个注解,下面咱们来改造一下上面写的log-spring-boot-starter项目。

@ConditionalOnBean:当容器(Spring Context)中有指定的Bean的条件下才问生效配置

建立一个标记类

package com.codelong.log.config;/**
 * 开关标记类
 *
 * @author codelong
 */public class LogMarker {
}复制代码

建立@Enable注解

package com.codelong.log.annotion;import com.codelong.log.config.LogMarker;import org.springframework.context.annotation.Import;import java.lang.annotation.*;/**
 * EnableMyLog注解将LogMarker注入到spring容器
 *
 * @author longwang
 */@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.TYPE)@Documented@Import(LogMarker.class)public @interface EnableMyLog {
}复制代码

修改Configuration配置类

package com.codelong.log.config;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;import org.springframework.boot.context.properties.EnableConfigurationProperties;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/**
 * 配置类
 *
 * @author codelong
 */@Configuration@EnableConfigurationProperties(MyLogProperties.class) // 该注解可使MyLogProperties注入spring容器@ConditionalOnBean(LogMarker.class) //当容器中有这个LogMarkerBean就会使得下面配置生效public class MyLogAutoConfiguration {@Beanpublic MyLogAspect myLogAspect(@Autowired MyLogProperties myLogProperties) {return new MyLogAspect(myLogProperties);
    }
}复制代码

这里经过EnableMyLog注解来控制是否启动日志功能,只有使用EnableMyLog注解才会将LogMarkerBean注入到Spring容器内,当Spring容器内有LogMarkerBean才会使MyLogAutoConfiguration生效。

因此当咱们要开启日志功能时,在springboot启动类上添加@EnableMyLog注解就能够了。

image-20210110152004693

相关文章
相关标签/搜索