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

相關文章
相關標籤/搜索