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官方文档,写了两种形式的自动配置

开发环境
环境版本
springboot2.0.3.release
maven3.5.2
jdk1.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 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Mars'Ares

请我喝杯咖啡吧

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值