springboot實現自動配置

目錄

一  前言

二 實現原理

(1)springboot啓動類註解解析

(2)參考

三  實現

方式一:使用spring.factories文件,通過配置enable實現開關

1、目錄結構

2、關鍵代碼

3、測試

方式二:使用註解@EnableXXX實現開關

1、目錄結構

2、關鍵代碼

3、測試

四  項目git

https://github.com/HandsomeMars/springboot-autoconfig-demo 


一  前言

1、今天想寫一個自動配置的模塊,參考了一系列文章,感覺非常失望。

問題如下:
1、混淆了自動配置註解:@EanbleXXX註解 加與不加都會生效配置 其實現關鍵是自動配置上通過其他條件加載完成 
2、無效代碼:太多的模仿代碼,讓人云裏霧裏;以及不完整測試,只測開啓不測關閉

2、自己看了springboot官方文檔,寫了兩種形式的自動配置

開發環境
環境 版本
springboot 2.0.3.release
maven 3.5.2
jdk 1.8


 

二 實現原理


(1)springboot啓動類註解解析

springboot啓動類中@SpringBootApplication
包含:
@SpringBootConfiguration
@EnableAutoConfiguration
@ComponentScan

其中@EnableAutoConfiguration
包含:
@AutoConfigurationPackage
@Import({AutoConfigurationImportSelector.class})

其中
AutoConfigurationImportSelector
實現了從所有包下的 META-INF/spring.factories
讀取自動配置類信息,通過類加載初始化所描述的bean

由上即可知自動配置的最簡單的實現方式

1、新建META-INFO/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.zyj.config.Custom2AutoConfig #需要被初始化的類

2、查詢api可知,等效寫法:實現如下接口,通過@Import等方式初始化

org.springframework.context.annotation.ImportSelector

@Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
 //邏輯判斷 返回對應的配置類包全路徑
        if(annotationMetadata.getAnnotationTypes().contains(EnableCustomAutoConfig.class.getName())){
            System.out.println("沒錯你是最棒的");
            return new String[]{CustomAutoConfig.class.getName()};
        }else{
            return new String[0];
        }

    }

(2)參考

https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/#boot-features-locating-auto-configuration-candidates

 https://docs.spring.io/spring-boot/docs/2.0.3.RELEASE/reference/htmlsingle/#boot-features-custom-starter

 

三  實現

方式一:使用spring.factories文件,通過配置enable實現開關

1、目錄結構

─src
  ├─main
  │  ├─java
  │  │  └─com
  │  │      └─zyj
  │  │          │  SpringbootAutoconfigByfileApplication.java  ##可忽略
  │  │          │
  │  │          └─config
  │  │                  Custom2AutoConfig.java  ##關鍵配置類
  │  │                  Custom2Properties.java  ##參數配置類
  │  │                  Custom2Server.java      ##模擬服務(可忽略)
  │  │
  │  └─resources
  │      │  application.properties              ##可忽略
  │      │
  │      └─META-INF
  │              spring.factories               ##關鍵配置文件,指定初始化關鍵配置類
  │
  └─test
      └─java
          └─com
              └─zyj
                      SpringbootAutoconfigByfileApplicationTests.java ##可忽略

 

2、關鍵代碼

pom依賴

<!--關鍵依賴 @ConfigurationProperties-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<!--更加自動配置框架而定-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

Custom2Properties.java

package com.zyj.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 14:35
 */
/**解析spring配置文件中custom2開頭的配置信息*/
@ConfigurationProperties(prefix="custom2")
public class Custom2Properties {
    private boolean enable;

    private String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }


    @Override
    public String toString() {
        StringBuilder stringBuilder=new StringBuilder();
        stringBuilder.append("[");
        stringBuilder.append("enable:"+enable);
        stringBuilder.append(",");
        stringBuilder.append("test:"+test);
        stringBuilder.append("]");
        return stringBuilder.toString();
    }
}

 Custom2AutoConfig.java

package com.zyj.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 11:29
 */
/**類似@Import 加載屬性文件(相當於屬性文件@Component)*/
/**與下面@Autowired配合*/
@EnableConfigurationProperties(Custom2Properties.class)
public class Custom2AutoConfig {

    @Autowired
    Custom2Properties custom2Properties;

    @Bean
    /**不存在實例才加載,避免重複*/
    @ConditionalOnMissingBean(Custom2Server.class)
    /**classpath出現Custom2Server才加載*/
    @ConditionalOnClass(Custom2Server.class)
    /**配置enable true 默認true才加載*/
    @ConditionalOnProperty(prefix="custom2", value="enable", matchIfMissing = true)
    public Custom2Server custom2Server(){
        Custom2Server testServer=new Custom2Server(custom2Properties);
        return testServer;
    }

}

 Custom2Server.java

package com.zyj.config;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 14:11
 */
public class Custom2Server {


    /**
     * 初始化
     * @param custom2Properties
     */
    public Custom2Server(Custom2Properties custom2Properties) {
        System.out.println(this.getClass().getName()+"初始化了:打印配置"+ custom2Properties.toString());
    }

}

spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.zyj.config.Custom2AutoConfig

3、測試

step1:pom引入自動配置的包

<dependency>
			<groupId>com.zyj</groupId>
			<artifactId>springboot-autoconfig-byfile</artifactId>
		</dependency>

step2:配置application.properties

server.port=8099

#次自動配置方式通過enable控制開關 不寫設置爲true
custom2.test=測試文件方式自動配置
custom2.enable=true

step3:啓動

step4:取消自動配置

server.port=8099

#次自動配置方式通過enable控制開關 不寫設置爲true
custom2.test=test-auto-by-file
custom2.enable=false

方式二:使用註解@EnableXXX實現開關

1、目錄結構

src
├─main
│  ├─java
│  │  └─com
│  │      └─zyj
│  │          │  SpringbootAutoconfigByAnnoApplication.java  ##可忽略
│  │          │
│  │          ├─auto
│  │          │      CustomAutoConfigSelect.java  ##自定義配置類過濾 等價spring.factories
│  │          │      EnableCustomAutoConfig.java  ##自定義配置註解 
│  │          │
│  │          └─config
│  │                  CustomAutoConfig.java       ##自定配置類
│  │                  CustomProperties.java       ##配置屬性(可忽略)
│  │                  CustomServer.java           ##配置服務(可忽略)
│  │
│  └─resources
│          application.properties        ##可忽略
│
└─test
    └─java
        └─com
            └─zyj
                    SpringbootAutoconfigApplicationTests.java ##可忽略

2、關鍵代碼

pom依賴

<!--關鍵依賴 @ConfigurationProperties-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-configuration-processor</artifactId>
			<optional>true</optional>
		</dependency>
		<!--更加自動配置框架而定-->
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter</artifactId>
		</dependency>
		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-test</artifactId>
			<scope>test</scope>
		</dependency>

EnableCustomAutoConfig.java

package com.zyj.auto;

import org.springframework.context.annotation.Import;

import java.lang.annotation.*;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 11:26
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
/**如果使用註解則引入CustomAutoConfigSelect*/
@Import(CustomAutoConfigSelect.class)
public @interface EnableCustomAutoConfig {
}

CustomAutoConfigSelect.java

package com.zyj.auto;

import com.zyj.config.CustomAutoConfig;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 11:28
 */
public class CustomAutoConfigSelect implements ImportSelector{
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        /** 打印springboot使用的註解annotationMetadata.getAnnotationTypes().forEach(System.out::println);*/
        if(annotationMetadata.getAnnotationTypes().contains(EnableCustomAutoConfig.class.getName())){
            //配置自動配置需要加載的類
            return new String[]{CustomAutoConfig.class.getName()};
        }else{
            //沒有自動配置則不加載
            return new String[0];
        }

    }
}

CustomProperties.java

package com.zyj.config;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 14:35
 */
/**解析spring配置文件中custom開頭的配置信息*/
@ConfigurationProperties(prefix="custom")
public class CustomProperties {
    private boolean enable;

    private String test;

    public String getTest() {
        return test;
    }

    public void setTest(String test) {
        this.test = test;
    }

    public boolean isEnable() {
        return enable;
    }

    public void setEnable(boolean enable) {
        this.enable = enable;
    }


    @Override
    public String toString() {
        StringBuilder stringBuilder=new StringBuilder();
        stringBuilder.append("[");
        stringBuilder.append("enable:"+enable);
        stringBuilder.append(",");
        stringBuilder.append("test:"+test);
        stringBuilder.append("]");
        return stringBuilder.toString();
    }
}

CustomAutoConfig.java

package com.zyj.config;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 11:29
 */
/**類似@Import 加載屬性文件(相當於屬性文件@Component)*/
/**與下面@Autowired配合*/
@EnableConfigurationProperties(CustomProperties.class)
public class CustomAutoConfig {

    @Autowired
    CustomProperties customProperties;

    @Bean
    /**不存在實例才加載,避免重複*/
    @ConditionalOnMissingBean(CustomServer.class)
    /**classpath出現CustomServer才加載*/
    @ConditionalOnClass(CustomServer.class)
    /**配置enable true 默認true才加載*/
    @ConditionalOnProperty(prefix="custom", value="enable", matchIfMissing = true)
    public CustomServer customServer(){
        CustomServer testServer=new CustomServer(customProperties);
        return testServer;
    }

}

 CustomServer.java

package com.zyj.config;

/**
 * @author by zyj
 * @version V1.0
 * @Description:
 * @Date 2019/8/5 14:11
 */
public class CustomServer {


    /**
     * 初始化
     * @param customProperties
     */
    public CustomServer(CustomProperties customProperties) {
        System.out.println(this.getClass().getName()+"初始化了:打印配置"+ customProperties.toString());
    }

}

3、測試

step1:pom引入自動配置的包

<dependency>
			<groupId>com.zyj</groupId>
			<artifactId>springboot-autoconfig-byanno</artifactId>
		</dependency>

step2:springboot加註解  (配置application.properties(可忽略) )

@SpringBootApplication
@EnableCustomAutoConfig/**添加此註解實現自動配置*/
public class SpringbootAutoconfigTestApplication {
//省略
}
server.port=8099

#次自動配置方式通過enable註解即可,enable爲再擴展
custom.test=test-auto-by-anno
custom.enable=true

step3:啓動

 

step4:關閉自動配置

去除註解即可 

不去註解設置false

server.port=8099

#次自動配置方式通過enable註解即可,enable爲再擴展
custom.test=test-auto-by-anno
custom.enable=false

四  項目git

https://github.com/HandsomeMars/springboot-autoconfig-demo 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章