1. 程式人生 > >Spring Boot 自定義starter和autoconfigure

Spring Boot 自定義starter和autoconfigure

一、spring-data-redis本來的自動配置怎麼用:

我們只需要引入spring-boot-starter-data-redis包就可以使用redis了,不用關心其他依賴的包

這個包中會把我們需要的其他包一起引入

看spring-data-redis中原始碼的自定義配置

可以知道,它給redis自動配置了一些預設屬性,如:

maxActive = 8
maxIdle = 8
minIdle = 0
maxWait = -1

然後我們在引入了autoconfigure和spring-boot-starter-data-redis後,這些預設配置會自動到redis的連線池配置中。如果需要修改指定值,則在application.yml中配置

spring:
  redis:
    database: 0
    host: 192.168.2.240
    password: 456987
    port: 6379
    pool:
      maxActive: 60
      maxIdle: 60
      maxWait: 3000

application.yml沒有配置,則Redis的配置用原始碼中自動配置的屬性,如果application.yml有配置,則會被application.yml中的配置覆蓋。比如:沒有application.yml,則maxToal=8,有application.yml,則maxActive=60

二、自定義starter和autoconfigure

使用場景:

工作中有接到如下需求:

1.封裝apache http client ,讓業務開發的組可以開箱即用,不用關心配置。(這個不介紹,類似的)

2.封裝redis,讓業務開發組開箱即用,不用關心連線池的配置。這裡就有個問題了,spring-data-redis已經做了自動配置了,為什麼還要再封裝,因為spring-data-redis做的自動配置的那些屬性,跟我們期待的標準配置太不一樣了。

比如,我們期待的預設配置是

        private int maxIdle = 60;

        private int minIdle = 0;

        private int maxActive = 60;

        private int maxWait = 3000;

        private boolean testOnCreate = false;

        private boolean testOnBorrow = false;

        private boolean testOnReturn = false;

        private boolean testWhileIdle = true;

        private long minEvictableIdleTimeMillis = 70000;

        private long timeBetweenEvictionRunsMillis = 40000;

        private int numTestsPerEvictionRun = -1;

各個業務系統根據實際情況,自己還可以再改。

建立一個專案common-redis-spring-boot

在這個專案中建立兩個modules

common-redis-spring-boot-autoconfigure

common-redis-spring-boot-starter

結構如下

1.common-redis-spring-boot

這個工程中不要引入掃描相關的註解,如@Autowire, @componet, @Service, @Controller等

這個工程主要定義子模組的需要用到的jar。

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.sid</groupId>
    <artifactId>common-redis-spring-boot</artifactId>
    <!-- 父模組必須以pom方式打包  -->
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <java.version>1.8</java.version>
        <spring-boot.version>1.5.8.RELEASE</spring-boot.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <common-redis.springboot.verison>1.0-SNAPSHOT</common-redis.springboot.verison>
        <common-redis.version>1.0-SNAPSHOT</common-redis.version>
    </properties>

    <!-- 定義兩個子模組 -->
    <modules>
        <module>common-redis-spring-boot-autoconfigure</module>
        <module>common-redis-spring-boot-starter</module>
    </modules>

    <!-- 定義子模組中需要的jar
        所有使用dependencyManagement預先定義相關的jar和版本
        保證在子類中需要使用時,只需要引入包,而不用使用版本號
     -->
    <dependencyManagement>
        <dependencies>
            <!-- spring boot -->
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-web</artifactId>
                <version>${spring-boot.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>

            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-starter-data-redis</artifactId>
                <version>${spring-boot.version}</version>
            </dependency>

            <dependency>
                <groupId>com.gs</groupId>
                <artifactId>common-redis-spring-boot-autoconfigure</artifactId>
                <version>${common-redis.springboot.verison}</version>
            </dependency>
            <!--  common-redis 自己寫的一個redis包 裡面全是靜態方法-->
            <dependency>
                <groupId>com.sid</groupId>
                <artifactId>common-redis</artifactId>
                <version>${common-redis.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

</project>

2.common-redis-spring-boot-autoconfigure

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">

    <parent>
        <artifactId>common-redis-spring-boot</artifactId>
        <groupId>com.sid</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../../common-redis-spring-boot/pom.xml</relativePath>
    </parent>

    <properties>
    <jackson.version>2.8.10</jackson.version>
    </properties>
    <modelVersion>4.0.0</modelVersion>


    <artifactId>common-redis-spring-boot-autoconfigure</artifactId>


    <dependencies>
        <!-- @ConfigurationProperties annotation processing (metadata for IDEs)
            生成spring-configuration-metadata.json類,需要引入此類
            -->
        <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-autoconfigure</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- spring-boot redis -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.sid</groupId>
            <artifactId>common-redis</artifactId>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.47</version>
            <optional>true</optional>
        </dependency>

        <!-- spring-boot 測試包 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>

    </dependencies>

</project>

spring-boot-configuration-processor 的作用是編譯時生成spring-configuration-metadata.json,在intellij idea中,當配置此jar相關配置屬性在application.properties,你可以用ctlr+滑鼠左鍵,IDE會跳轉到你配置此屬性的類中  

MyRedisProperties.java  屬性類

自動從配置檔案中解析屬性並生成物件

package common.redis.spring.boot.autoconfigure.properties;

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

import java.util.List;

/**
 * @program: common-redis-spring-boot
 * @description:
 * @author: Sid
 * @date: 2018-11-01 17:18
 * @since: 1.0
 **/
//注入application.yml中spring.redis開頭的屬性
/**
 * 通過@EnableConfigurationProperties可以將被@ConfigurationProperties註解的類生成一個bean
 * */
@ConfigurationProperties(prefix = "spring.redis")
public class MyRedisProperties {
    /**
     * Database index used by the connection factory.
     */
    private int database = 0;

    /**
     * Redis url, which will overrule host, port and password if set.
     */
    private String url;

    /**
     * Redis server host.
     */
    private String host = "localhost";

    /**
     * Login password of the redis server.
     */
    private String password;

    /**
     * Redis server port.
     */
    private int port = 6379;

    /**
     * Enable SSL.
     */
    private boolean ssl;

    /**
     * Connection timeout in milliseconds.
     */
    private int timeout;

    private Pool pool  = new Pool();

    private Sentinel sentinel;

    private Cluster cluster;

    public int getDatabase() {
        return this.database;
    }

    public void setDatabase(int database) {
        this.database = database;
    }

    public String getUrl() {
        return this.url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getHost() {
        return this.host;
    }

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

    public String getPassword() {
        return this.password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public int getPort() {
        return this.port;
    }

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

    public boolean isSsl() {
        return this.ssl;
    }

    public void setSsl(boolean ssl) {
        this.ssl = ssl;
    }

    public void setTimeout(int timeout) {
        this.timeout = timeout;
    }

    public int getTimeout() {
        return this.timeout;
    }

    public Sentinel getSentinel() {
        return this.sentinel;
    }

    public void setSentinel(Sentinel sentinel) {
        this.sentinel = sentinel;
    }

    public Pool getPool() {
        return this.pool;
    }

    public void setPool(Pool pool) {
        this.pool = pool;
    }

    public Cluster getCluster() {
        return this.cluster;
    }

    public void setCluster(Cluster cluster) {
        this.cluster = cluster;
    }

    /**
     * Pool properties.
     */
    public static class Pool {

        /**
         * Max number of "idle" connections in the pool. Use a negative value to indicate
         * an unlimited number of idle connections.
         */
        private int maxIdle = 60;

        /**
         * Target for the minimum number of idle connections to maintain in the pool. This
         * setting only has an effect if it is positive.
         */
        private int minIdle = 0;

        /**
         * Max number of connections that can be allocated by the pool at a given time.
         * Use a negative value for no limit.
         */
        private int maxActive = 60;

        /**
         * Maximum amount of time (in milliseconds) a connection allocation should block
         * before throwing an exception when the pool is exhausted. Use a negative value
         * to block indefinitely.
         */
        private int maxWait = 3000;

        private boolean testOnCreate = false;

        private boolean testOnBorrow = false;

        private boolean testOnReturn = false;

        private boolean testWhileIdle = true;

        private long minEvictableIdleTimeMillis = 60000;

        private long timeBetweenEvictionRunsMillis = 30000;

        private int numTestsPerEvictionRun = -1;

        public int getMaxIdle() {
            return this.maxIdle;
        }

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

        public int getMinIdle() {
            return this.minIdle;
        }

        public void setMinIdle(int minIdle) {
            this.minIdle = minIdle;
        }

        public int getMaxActive() {
            return this.maxActive;
        }

        public void setMaxActive(int maxActive) {
            this.maxActive = maxActive;
        }

        public int getMaxWait() {
            return this.maxWait;
        }

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

        public boolean getTestOnCreate() {
            return testOnCreate;
        }

        public void setTestOnCreate(boolean testOnCreate) {
            this.testOnCreate = testOnCreate;
        }

        public boolean getTestOnBorrow() {
            return testOnBorrow;
        }

        public void setTestOnBorrow(boolean testOnBorrow) {
            this.testOnBorrow = testOnBorrow;
        }

        public boolean getTestOnReturn() {
            return testOnReturn;
        }

        public void setTestOnReturn(boolean testOnReturn) {
            this.testOnReturn = testOnReturn;
        }

        public boolean getTestWhileIdle() {
            return testWhileIdle;
        }

        public void setTestWhileIdle(boolean testWhileIdle) {
            this.testWhileIdle = testWhileIdle;
        }

        public long getMinEvictableIdleTimeMillis() {
            return minEvictableIdleTimeMillis;
        }

        public void setMinEvictableIdleTimeMillis(long minEvictableIdleTimeMillis) {
            this.minEvictableIdleTimeMillis = minEvictableIdleTimeMillis;
        }

        public long getTimeBetweenEvictionRunsMillis() {
            return timeBetweenEvictionRunsMillis;
        }

        public void setTimeBetweenEvictionRunsMillis(long timeBetweenEvictionRunsMillis) {
            this.timeBetweenEvictionRunsMillis = timeBetweenEvictionRunsMillis;
        }

        public int getNumTestsPerEvictionRun() {
            return numTestsPerEvictionRun;
        }

        public void setNumTestsPerEvictionRun(int numTestsPerEvictionRun) {
            this.numTestsPerEvictionRun = numTestsPerEvictionRun;
        }
    }

    /**
     * Cluster properties.
     */
    public static class Cluster {

        /**
         * Comma-separated list of "host:port" pairs to bootstrap from. This represents an
         * "initial" list of cluster nodes and is required to have at least one entry.
         */
        private List<String> nodes;

        /**
         * Maximum number of redirects to follow when executing commands across the
         * cluster.
         */
        private Integer maxRedirects;

        public List<String> getNodes() {
            return this.nodes;
        }

        public void setNodes(List<String> nodes) {
            this.nodes = nodes;
        }

        public Integer getMaxRedirects() {
            return this.maxRedirects;
        }

        public void setMaxRedirects(Integer maxRedirects) {
            this.maxRedirects = maxRedirects;
        }

    }

    /**
     * Redis sentinel properties.
     */
    public static class Sentinel {

        /**
         * Name of Redis server.
         */
        private String master;

        /**
         * Comma-separated list of host:port pairs.
         */
        private String nodes;

        public String getMaster() {
            return this.master;
        }

        public void setMaster(String master) {
            this.master = master;
        }

        public String getNodes() {
            return this.nodes;
        }

        public void setNodes(String nodes) {
            this.nodes = nodes;
        }

    }
}

RedisAutoConfig.java  自動配置類

package common.redis.spring.boot.autoconfigure;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.List;

import com.alibaba.fastjson.JSON;
import common.redis.RedisUtil;
import common.redis.spring.boot.autoconfigure.properties.MyRedisProperties;
import common.redis.spring.boot.autoconfigure.properties.MyRedisProperties.Sentinel;
import common.redis.spring.boot.autoconfigure.properties.MyRedisProperties.Cluster;
import org.apache.commons.pool2.impl.GenericObjectPool;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPoolConfig;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.connection.RedisClusterConfiguration;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.connection.RedisNode;
import org.springframework.data.redis.connection.RedisSentinelConfiguration;
import org.springframework.data.redis.connection.jedis.JedisConnection;
import org.springframework.data.redis.connection.jedis.JedisConnectionFactory;
import org.springframework.data.redis.core.RedisOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import javax.annotation.PostConstruct;


/**
 * @program: common-redis-spring-boot
 * @description:
 * @author: Sid
 * @date: 2018-11-01 17:02
 * @since: 1.0
 **/
@Configuration  //定義配置類
@AutoConfigureBefore(RedisAutoConfiguration.class)
@ConditionalOnClass({ JedisConnection.class, RedisOperations.class, Jedis.class })
@EnableConfigurationProperties(MyRedisProperties.class)
public class RedisAutoConfig {

    /**
     * Redis connection configuration.
     */
    @Configuration
    @ConditionalOnClass(GenericObjectPool.class)
    protected static class RedisConnectionConfiguration {

        private final MyRedisProperties properties;

        private final RedisSentinelConfiguration sentinelConfiguration;

        private final RedisClusterConfiguration clusterConfiguration;

        public RedisConnectionConfiguration(MyRedisProperties properties,
                                            ObjectProvider<RedisSentinelConfiguration> sentinelConfiguration,
                                            ObjectProvider<RedisClusterConfiguration> clusterConfiguration) {
            this.properties = properties;
            this.sentinelConfiguration = sentinelConfiguration.getIfAvailable();
            this.clusterConfiguration = clusterConfiguration.getIfAvailable();
        }

        @Bean
        @ConditionalOnMissingBean(RedisConnectionFactory.class)
        public JedisConnectionFactory redisConnectionFactory()  {
            return applyProperties(createJedisConnectionFactory());
        }

        protected final JedisConnectionFactory applyProperties(JedisConnectionFactory factory) {
            configureConnection(factory);
            if (this.properties.isSsl()) {
                factory.setUseSsl(true);
            }
            factory.setDatabase(this.properties.getDatabase());
            if (this.properties.getTimeout() > 0) {
                factory.setTimeout(this.properties.getTimeout());
            }
            return factory;
        }

        private void configureConnection(JedisConnectionFactory factory) {
            if (StringUtils.hasText(this.properties.getUrl())) {
                configureConnectionFromUrl(factory);
            }
            else {
                factory.setHostName(this.properties.getHost());
                factory.setPort(this.properties.getPort());
                if (this.properties.getPassword() != null) {
                    factory.setPassword(this.properties.getPassword());
                }
            }
        }

        private void configureConnectionFromUrl(JedisConnectionFactory factory) {
            String url = this.properties.getUrl();
            if (url.startsWith("rediss://")) {
                factory.setUseSsl(true);
            }
            try {
                URI uri = new URI(url);
                factory.setHostName(uri.getHost());
                factory.setPort(uri.getPort());
                if (uri.getUserInfo() != null) {
                    String password = uri.getUserInfo();
                    int index = password.lastIndexOf(":");
                    if (index >= 0) {
                        password = password.substring(index + 1);
                    }
                    factory.setPassword(password);
                }
            }
            catch (URISyntaxException ex) {
                throw new IllegalArgumentException("Malformed 'spring.redis.url' " + url,
                        ex);
            }
        }

        protected final RedisSentinelConfiguration getSentinelConfig() {
            if (this.sentinelConfiguration != null) {
                return this.sentinelConfiguration;
            }
            Sentinel sentinelProperties = this.properties.getSentinel();
            if (sentinelProperties != null) {
                RedisSentinelConfiguration config = new RedisSentinelConfiguration();
                config.master(sentinelProperties.getMaster());
                config.setSentinels(createSentinels(sentinelProperties));
                return config;
            }
            return null;
        }

        /**
         * Create a {@link RedisClusterConfiguration} if necessary.
         * @return {@literal null} if no cluster settings are set.
         */
        protected final RedisClusterConfiguration getClusterConfiguration() {
            if (this.clusterConfiguration != null) {
                return this.clusterConfiguration;
            }
            if (this.properties.getCluster() == null) {
                return null;
            }
            Cluster clusterProperties = this.properties.getCluster();
            RedisClusterConfiguration config = new RedisClusterConfiguration(
                    clusterProperties.getNodes());

            if (clusterProperties.getMaxRedirects() != null) {
                config.setMaxRedirects(clusterProperties.getMaxRedirects());
            }
            return config;
        }

        private List<RedisNode> createSentinels(Sentinel sentinel) {
            List<RedisNode> nodes = new ArrayList<RedisNode>();
            for (String node : StringUtils.commaDelimitedListToStringArray(sentinel.getNodes())) {
                try {
                    String[] parts = StringUtils.split(node, ":");
                    Assert.state(parts.length == 2, "Must be defined as 'host:port'");
                    nodes.add(new RedisNode(parts[0], Integer.valueOf(parts[1])));
                }
                catch (RuntimeException ex) {
                    throw new IllegalStateException(
                            "Invalid redis sentinel " + "property '" + node + "'", ex);
                }
            }
            return nodes;
        }

        private JedisConnectionFactory createJedisConnectionFactory() {
            JedisPoolConfig poolConfig = this.properties.getPool() != null
                    ? jedisPoolConfig() : new JedisPoolConfig();

            if (getSentinelConfig() != null) {
                return new JedisConnectionFactory(getSentinelConfig(), poolConfig);
            }
            if (getClusterConfiguration() != null) {
                return new JedisConnectionFactory(getClusterConfiguration(), poolConfig);
            }
            return new JedisConnectionFactory(poolConfig);
        }

        private JedisPoolConfig jedisPoolConfig() {
            JedisPoolConfig config = new JedisPoolConfig();
            MyRedisProperties.Pool props = this.properties.getPool();
            config.setMaxTotal(props.getMaxActive());
            config.setMaxIdle(props.getMaxIdle());
            config.setMinIdle(props.getMinIdle());
            config.setMaxWaitMillis(props.getMaxWait());

            //sid since1.0 允許使用者自定義這幾個屬性
            config.setTestOnCreate(props.getTestOnCreate());
            config.setTestOnBorrow(props.getTestOnBorrow());
            config.setTestOnReturn(props.getTestOnReturn());
            config.setTestWhileIdle(props.getTestWhileIdle());
            config.setMinEvictableIdleTimeMillis(props.getMinEvictableIdleTimeMillis());
            config.setTimeBetweenEvictionRunsMillis(props.getTimeBetweenEvictionRunsMillis());
            config.setNumTestsPerEvictionRun(props.getNumTestsPerEvictionRun());


            return config;
        }

    }

    /**
     * Standard Redis configuration.
     */
    @Configuration
    protected static class RedisConfiguration {

        @Bean
        @ConditionalOnMissingBean(name = "redisTemplate")
        public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory){
            RedisTemplate<Object, Object> template = new RedisTemplate<Object, Object>();
            template.setConnectionFactory(redisConnectionFactory);

            template.setKeySerializer(new StringRedisSerializer());
            template.setHashKeySerializer(new StringRedisSerializer());
            template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
            template.setHashValueSerializer(new GenericJackson2JsonRedisSerializer());
            template.afterPropertiesSet();
            return template;
        }

        @Bean
        @ConditionalOnMissingBean(StringRedisTemplate.class)
        public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory) {
            StringRedisTemplate template = new StringRedisTemplate();
            template.setConnectionFactory(redisConnectionFactory);
            return template;
        }

    }

    @Bean
    @ConditionalOnBean(RedisTemplate.class)
    public RedisUtilConfig redisUtilConfig() {
        return new RedisUtilConfig();
    }

    public class RedisUtilConfig {
        private  final Logger logger = LoggerFactory.getLogger(RedisUtilConfig.class);
        @Autowired
        private RedisTemplate redisTemplate;

        @PostConstruct
        public void afterPropertiesSet() {
            //往com.sid.common.redis中注入,這裡面封裝了各種靜態方法。
            RedisUtil.init(redisTemplate);
            JedisConnectionFactory connectionFactory = (JedisConnectionFactory) redisTemplate.getConnectionFactory();
            logger.info("redisTemplate-->JedisConnectionFactory-->PoolConfig-->{}", JSON.toJSONString(connectionFactory.getPoolConfig(), true));
        }
    }
}

註解介紹

@Configuration:定義配置類

@EnableConfigurationProperties:屬性類

@AutoConfigureAfter: 自動配置應在XXX的自動配置類之後應用。

@AutoConfigureBefore: 自動配置應在XXX的自動配置類之前應用

@AutoConfigureOrder:定義配置類執行的順序

@ConditionalOnBean:當容器裡有指定的Bean 時才生成

@ConditionalOnMissingBean:當容器裡沒有指定Bean 時才生成

@ConditionalOnClass:當類路徑下有指定的類時才生成

@ConditionalOnMissingClass:當類路徑下沒有指定的類時才生成

@ConditionalOnExpression:基於SpEL 表示式作為判斷條件。

@ConditionalOnJava:基於JVM 版本作為判斷條件。

@ConditionalOnJndi:在JNDI存在的條件下查詢指定的位置。

@ConditionalOnProperty:指定的屬性是否有指定的值。

@ConditionalOnResource:類路徑是否有指定的值。

@ConditionalOnSingleCandidate:當指定Bean 在容器中只有一個,或者雖然有多個但是指定首選的Bean。

@ConditionalOnWebApplication:當前專案是Web 專案的條件下。

@ConditionalOnNotWebApplication:當前專案不是Web 專案的條件下。

 

 spring.factories

src/resources/META-INF/spring.factories:  配置RedisAutoConfig在此檔案,則spring boot會自動生成初始化此類

# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
common.redis.spring.boot.autoconfigure.RedisAutoConfig

3.common-redis-spring-boot-starter

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">

    <parent>
        <artifactId>common-redis-spring-boot</artifactId>
        <groupId>com.sid</groupId>
        <version>1.0-SNAPSHOT</version>
        <relativePath>../../common-redis-spring-boot/pom.xml</relativePath>
    </parent>

    <modelVersion>4.0.0</modelVersion>


    <artifactId>common-redis-spring-boot-starter</artifactId>


    <dependencies>
        <dependency>
            <groupId>com.sid</groupId>
            <artifactId>common-redis-spring-boot-autoconfigure</artifactId>
        </dependency>

        <dependency>
            <groupId>com.sid</groupId>
            <artifactId>common-redis</artifactId>
        </dependency>

    </dependencies>


</project>

4.common-redis

common-redis包中大致程式碼

public class RedisUtil  {

    /**
    * @Description: 這個redisTemplate 自動配置了連線池
     * maxIdle = 60
     * maxActive = 60
     * maxWait = 3000
     *
     * 預設使用序列化:
     *             template.setKeySerializer(new StringRedisSerializer());
     *             template.setHashKeySerializer(new StringRedisSerializer());
     *             template.setValueSerializer(new GenericJackson2JsonRedisSerializer());
     *             template.setHashValueSerializer(new       GenericJackson2JsonRedisSerializer());
    * @Author: Sid
    * @Date: 2018-11-08 15:16
    * @since: 1.0
    */
    private static RedisTemplate redisTemplate;

    private static final AtomicBoolean init = new AtomicBoolean(false);

    public static void init(RedisTemplate redisTemplate) {
        if (init.compareAndSet(false, true)) {
            RedisUtil.redisTemplate = redisTemplate;
        }
    }


    public static<V> V get(String key) {
        return (V)redisTemplate.opsForValue().get(key);
    }

    public static <V>  void set(String key ,V value){
        redisTemplate.opsForValue().set(key,value);
    }
}

5.測試

新建一個專案,引入common-redis-spring-boot-starter包

然後直接使用common-redis中的RedisUtil

 ModelTest modelTest = new ModelTest();
 modelTest.setName("小李");
 modelTest.setAge(27);

 RedisUtil.set("common-redis:test:modelTest1",modelTest);
 RedisUtil.set("common-redis:test:string1","測試");

 RedisUtil.get("common-redis:test:string1");