欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

J2Cache的SpringBootのStarter

程序员文章站 2022-04-28 18:32:04
...

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的初始化