1. 程式人生 > >springboot原始碼解析:自己實現一個springboot自動配置

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>

新建類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;
    }
}

在這裡我們用到了@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;
    }




}

@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

上上篇講解了@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

新建新的專案。引入剛剛打包的專案

 @Autowired
 private StringRedisTemplate redisTemplate;

完成,就是這麼簡單。

很多時候我們要擴充套件spring的功能也可以從這個方向下手,例如攜程的apollo框架也是這樣,大家有興趣可以去研究下。

前段時間springCloud研究完,很多人說原始碼看不懂,我說很簡單啊,其實springcloud看不懂的就是不懂springboot原始碼。特別是我前面兩篇的東西。有機會分析下springcloud原始碼把。


菜鳥不易,望有問題指出,共同進步