J2Cache的SpringBootのStarter

qixiaobo發表於2018-01-05

title: J2Cache的SpringBootのStarter tags:

  • SpringBoot
  • J2Cache
  • Starter categories: springboot date: 2017-11-27 23:28:37

背景

J2Cache是OsChina的兩級快取實現框架 但是程式碼比較老 程式碼考慮也比較死板 不支援多種配置

對於多profile的實現來說也 只能使用通過Maven的profile實現【不支援動態變更】

    public class J2Cache {
     
     
     
        private final static Logger log = LoggerFactory.getLogger(J2Cache.class);
     
     
     
        private final static String CONFIG_FILE = "/j2cache.properties";
     
        private final static CacheChannel channel;
     
        private final static Properties config;
     
     
     
        static {
     
            try {
     
                config = loadConfig();
     
                String cache_broadcast = config.getProperty("cache.broadcast");
     
                if ("redis".equalsIgnoreCase(cache_broadcast))
     
                    channel = RedisCacheChannel.getInstance();
     
                else if ("jgroups".equalsIgnoreCase(cache_broadcast))
     
                    channel = JGroupsCacheChannel.getInstance();
     
                else
     
                    throw new CacheException("Cache Channel not defined. name = " + cache_broadcast);
     
            } catch (IOException e) {
     
                throw new CacheException("Unabled to load j2cache configuration " + CONFIG_FILE, e);
     
            }
     
        }
     
     
     
        public static CacheChannel getChannel(){
     
            return channel;
     
        }
     
     
     
        public static Properties getConfig(){
     
            return config;
     
        }
     
     
     
        /**
     
         * 載入配置
     
         * @return
     
         * @throws IOException
     
         */
     
        private static Properties loadConfig() throws IOException {
     
            log.info("Load J2Cache Config File : [{}].", CONFIG_FILE);
     
            InputStream configStream = J2Cache.class.getClassLoader().getParent().getResourceAsStream(CONFIG_FILE);
     
            if(configStream == null)
     
                configStream = CacheManager.class.getResourceAsStream(CONFIG_FILE);
     
            if(configStream == null)
     
                throw new CacheException("Cannot find " + CONFIG_FILE + " !!!");
     
     
     
            Properties props = new Properties();
     
     
     
            try{
     
                props.load(configStream);
     
            }finally{
     
                configStream.close();
     
            }
     
     
     
            return props;
     
        }
     
     
     
    }
複製程式碼

很明顯此處程式碼必須要讀取j2cache.properties

那麼在不同環境【profile】想要使用不同的配置只有通過maven在編譯時修改配置檔案了【或者同樣的其他手段】

思路

  1. 為了最小化的修改代價 不建議直接將所有的配置放到SpringBoot的application-${profile}.properties中 因為比如其他Jar中都是依靠J2Cache.getChannel() 來獲取對應的cacheChannel
  2. 那麼我們可以修改讀取的配置檔案即可【換言之我們考慮讀取不同的j2cache.properties】
  3. 保留靜態方法 但是靜態程式碼塊移除【以免一旦載入到該Class就會直接初始化】
  4. 在getChannel等方法做檢查必須提前呼叫初始化方法

方案

    /**
     * 快取入口
     *
     * @author winterlau
     */
    public class J2Cache {
     
        private final static Logger log = LoggerFactory.getLogger(J2Cache.class);
     
        private final static String CONFIG_FILE = "/j2cache.properties";
        private static CacheChannel channel;
        private static Properties config;
        private static AtomicBoolean initlized = new AtomicBoolean(false);
     
     
        public static void init() {
            init(CONFIG_FILE);
        }
     
        public static void init(String filePath) {
            if (initlized.compareAndSet(false, true)) {
                try {
                    config = loadConfig(filePath);
                    String cache_broadcast = config.getProperty("cache.broadcast");
                    if ("redis".equalsIgnoreCase(cache_broadcast)) {
                        channel = RedisCacheChannel.getInstance();
                    } else if ("jgroups".equalsIgnoreCase(cache_broadcast)) {
                        channel = JGroupsCacheChannel.getInstance();
                    } else {
                        initlized.set(false);
                        throw new CacheException("Cache Channel not defined. name = " + cache_broadcast);
                    }
                } catch (IOException e) {
                    initlized.set(false);
                    throw new CacheException("Unabled to load j2cache configuration " + filePath, e);
                }
            } else {
                log.warn("J2cache initlized alerday!");
            }
        }
     
        private static void checkInitlized() {
            if (!initlized.get()) {
                throw new CacheException("J2cache init not yet! You should call j2Cache.init(String) first!");
            }
        }
     
        public static CacheChannel getChannel() {
            checkInitlized();
            return channel;
        }
     
        public static Properties getConfig() {
            checkInitlized();
            return config;
        }
     
        /**
         * 載入配置
         *
         * @param filePath
         * @return
         * @throws IOException
         */
        private static Properties loadConfig(String filePath) throws IOException {
            if (filePath == null || filePath.trim().length() == 0) filePath = CONFIG_FILE;
            log.info("Load J2Cache Config File : [{}].", filePath);
            InputStream configStream = J2Cache.class.getResourceAsStream(filePath);
            if (configStream == null)
                configStream = CacheManager.class.getResourceAsStream(filePath);
            if (configStream == null)
                throw new CacheException("Cannot find " + filePath + " !!!");
     
            Properties props = new Properties();
     
            try {
                props.load(configStream);
            } finally {
                configStream.close();
            }
     
            return props;
        }
     
    }
複製程式碼

基於目前SpringBoot的使用我們建立對應的Starter

建立配置類

    package net.oschina.j2cache.autoconfigure;
     
    import org.springframework.boot.context.properties.ConfigurationProperties;
     
    @ConfigurationProperties(prefix = "j2cache")
    public class J2CacheConfig {
        private String configLocation = "/j2cache.properties";
     
        public String getConfigLocation() {
            return configLocation;
        }
     
        public void setConfigLocation(String configLocation) {
            this.configLocation = configLocation;
        }
    }
複製程式碼

建立初始化呼叫類

    package net.oschina.j2cache.autoconfigure;
     
    import net.oschina.j2cache.J2Cache;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
     
    import javax.annotation.PostConstruct;
     
    public class J2CacheIniter {
        private static Logger logger = LoggerFactory.getLogger(J2CacheIniter.class);
        private final J2CacheConfig j2CacheConfig;
     
        public J2CacheIniter(J2CacheConfig j2CacheConfig) {
            this.j2CacheConfig = j2CacheConfig;
        }
     
        @PostConstruct
        public void init() {
            J2Cache.init(j2CacheConfig.getConfigLocation());
        }
    }
複製程式碼

根據條件判斷載入

    package net.oschina.j2cache.autoconfigure;
     
    import net.oschina.j2cache.J2Cache;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    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.Configuration;
     
    @ConditionalOnClass(J2Cache.class)
    @EnableConfigurationProperties({J2CacheConfig.class})
    @Configuration
    public class J2CacheAutoConfigure {
        private static Logger logger = LoggerFactory.getLogger(J2CacheAutoConfigure.class);
     
        private final J2CacheConfig j2CacheConfig;
     
        public J2CacheAutoConfigure(J2CacheConfig j2CacheConfig) {
            this.j2CacheConfig = j2CacheConfig;
        }
     
        @ConditionalOnMissingBean(J2CacheIniter.class)
        public J2CacheIniter j2CacheIniter() {
            return new J2CacheIniter(j2CacheConfig);
        }
     
     
    }
複製程式碼

建立META-INF/spring.factories

    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    net.oschina.j2cache.autoconfigure.J2CacheAutoConfigure
複製程式碼

這樣就會自動載入對應的

J2CacheAutoConfigure  可以參考SpringBoot之自動配置
複製程式碼

使用

系統中我們使用J2Cache作為SpringCache的實現

比如我們可以如此

    /*
     * Copyright (c) 2017. Lorem ipsum dolor sit amet, consectetur adipiscing elit.
     * Morbi non lorem porttitor neque feugiat blandit. Ut vitae ipsum eget quam lacinia accumsan.
     * Etiam sed turpis ac ipsum condimentum fringilla. Maecenas magna.
     * Proin dapibus sapien vel ante. Aliquam erat volutpat. Pellentesque sagittis ligula eget metus.
     * Vestibulum commodo. Ut rhoncus gravida arcu.
     */
     
    package com.f6car.base.config;
     
    import net.oschina.j2cache.autoconfigure.J2CacheConfig;
    import net.oschina.j2cache.autoconfigure.J2CacheIniter;
    import org.nutz.j2cache.spring.SpringJ2CacheManager;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.cache.CacheManager;
    import org.springframework.cache.ehcache.EhCacheManagerUtils;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.DependsOn;
    import org.springframework.context.annotation.PropertySource;
     
    @Configuration
    @PropertySource("classpath:j2cache/j2cache-${spring.profiles.active}.properties")
    public class CacheConfig {
        @Value("${ehcache.ehcache.name}")
        private String ehcacheName;
     
        @Bean("ehCacheManager")
        public net.sf.ehcache.CacheManager ehCacheManager() {
            return EhCacheManagerUtils.buildCacheManager(ehcacheName);
        }
     
        @DependsOn({"ehCacheManager", "j2CacheIniter"})
        @Bean
        public CacheManager springJ2CacheManager() {
            return new SpringJ2CacheManager();
        }
     
        @Bean("j2CacheIniter")
        public J2CacheIniter j2CacheIniter(J2CacheConfig j2cacheConfig) {
            return new J2CacheIniter(j2cacheConfig);
        }
     
    }
複製程式碼

如上我們就可以載入到不同的j2cache/j2cache-${spring.profiles.active}.properties

這樣就完成了J2cache的初始化

相關文章