springboot源码解析:自己实现一个springboot自动配置

上两篇将到了springboot自动配置和条件注解是如何实现,这篇在前两篇的基础上自己实现一个springboot的自动配置,用到条件注解。

需求:加入自己手写的jar。直接就可以使用StringRedisTemplate。

1.新建一个maven项目,pom.xml如下:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.share1024</groupId>
    <artifactId>redis</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>redis</name>
    <description>Demo project for Spring Boot</description>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>1.5.10.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <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-data-redis</artifactId>
        </dependency>


        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>

    </dependencies>


</project>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49

新建类RedisProperties.java

package com.share1024;

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

/**
 * @author : yesheng
 * @Description :
 * @Date : 2018/2/26
 */
@ConfigurationProperties(prefix = "custom.redis")
public class RedisProperties {

    private int maxTotal;

    private int maxIdle;

    private long maxWait;

    private String host;

    private int port = 6379;

    private int timeout;


    public int getMaxTotal() {
        return maxTotal;
    }

    public void setMaxTotal(int maxTotal) {
        this.maxTotal = maxTotal;
    }

    public int getMaxIdle() {
        return maxIdle;
    }

    public void setMaxIdle(int maxIdle) {
        this.maxIdle = maxIdle;
    }

    public long getMaxWait() {
        return maxWait;
    }

    public void setMaxWait(long maxWait) {
        this.maxWait = maxWait;
    }

    public String getHost() {
        return host;
    }

    public void setHost(String host) {
        this.host = host;
    }

    public int getPort() {
        return port;
    }

    public void setPort(int port) {
        this.port = port;
    }

    public int getTimeout() {
        return timeout;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74

在这里我们用到了@ConfigurationProperties(prefix = “custom.redis”),也就是将我们的application.yml/application.properties中的配置以custom.redis开头的配置。
也就是将properties转化成bean

我们使用配置常量,可以用@Value,或者Environment来获取

我们redis的常量配置已经写好。

新建类RedisAutoConfiguration.java

package com.share1024;

import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;

/**
 * @author : yesheng
 * @Description :
 * @Date : 2018/2/26
 */
@Configuration
@ConditionalOnClass({RedisTemplate.class, Jedis.class})
@EnableConfigurationProperties(RedisProperties.class)
@ConditionalOnProperty(prefix = "custom.redis",name = "host")
public class RedisAutoConfiguration {

    @Bean
    public StringRedisTemplate stringRedisTemplate(JedisConnectionFactory jedisConnectionFactory){
        StringRedisTemplate redisTemplate = new StringRedisTemplate();
        redisTemplate.setConnectionFactory(jedisConnectionFactory);
        return redisTemplate;
    }

    @Bean
    public JedisPoolConfig jedisPoolConfig(RedisProperties redisProperties){
        JedisPoolConfig poolConfig = new JedisPoolConfig();
        if(redisProperties.getMaxTotal() !=0){
            poolConfig.setMaxTotal(redisProperties.getMaxTotal());

        }
        if(redisProperties.getMaxIdle() !=0){
            poolConfig.setMaxIdle(redisProperties.getMaxIdle());

        }
        if(redisProperties.getMaxWait()!=0){
            poolConfig.setMaxWaitMillis(redisProperties.getMaxWait());
        }
        return poolConfig;
    }

    @Bean
    public JedisConnectionFactory jedisConnectionFactory(JedisPoolConfig jedisPoolConfig,RedisProperties redisProperties){
        JedisConnectionFactory jedisConnectionFactory  = new JedisConnectionFactory(jedisPoolConfig);
        jedisConnectionFactory.setHostName(redisProperties.getHost());
        jedisConnectionFactory.setPort(redisProperties.getPort());
        if(redisProperties.getTimeout() !=0){
            jedisConnectionFactory.setTimeout(redisProperties.getTimeout());
        }
        return jedisConnectionFactory;
    }




}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65

@ConditionalOnClass({RedisTemplate.class, Jedis.class})
这个类要注册到容器中,在项目上下文中必须等找到RedisTemplate.class,Jedis.class,没有这两个类就不进行配置。

@EnableConfigurationProperties(RedisProperties.class)
使@ConfigurationProperties注解生效

@ConditionalOnProperty(prefix = “custom.redis”,name = “host”)
这个就是我们的application.properties中custom.redis.host必须要有,没有就不进行配置。

文件中的3个@Bean,就是当该自动配置类,满足上面的@ConditionalOnClass({RedisTemplate.class, Jedis.class})
和@ConditionalOnProperty(prefix = “custom.redis”,name = “host”),就会将该类进行注册到spring容器中,并且会将该类下的@Bean全部注册到容器中。
这样我们就可以直接使用StringRedisTemplate

在resources目录下新建META-INF/spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.share1024.RedisAutoConfiguration
  • 1
  • 2

上上篇讲解了@EnableAutoConfiguration使用了EnableAutoConfigurationImportSelector.class。整个流程再梳理一遍。

ConfigurationClassPostProcessor在生命周期中回去扫描@Component.

然后递归的取扫描该类中的@ImportResource,@PropertySource,@ComponentScan,@Bean,@Import。一直处理完。

@EnableAutoConfiguration
使用了@Import(EnableAutoConfigurationImportSelector.class),会去扫描META-INF/spring.factories
所有的org.springframework.boot.autoconfigure.EnableAutoConfiguration。进行进一步的扫描。

完成。

mvn clean install
  • 1

新建新的项目。引入刚刚打包的项目

 @Autowired
 private StringRedisTemplate redisTemplate;
  • 1
  • 2

完成,就是这么简单。

很多时候我们要扩展spring的功能也可以从这个方向下手,例如携程的apollo框架也是这样,大家有兴趣可以去研究下。

前段时间springCloud研究完,很多人说源码看不懂,我说很简单啊,其实springcloud看不懂的就是不懂springboot源码。特别是我前面两篇的东西。有机会分析下springcloud源码把。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享