• 从零开始学 Java


    Memcached 客户端选择

    上一篇文章 从零开始学 Java - Spring 集成 Memcached 缓存配置(一)中我们讲到这篇要谈客户端的选择,在 Java 中一般常用的有三个:

    • Memcached Client for Java
    • SpyMemcached
    • XMemcached

    他们的对比与性能我这里不讨论,想了解自己搜索查看,我这里使用的是 XMemcached ,据说它的并发效果更好一些。

    地址:https://github.com/killme2008/xmemcached

    一些基础的准备

    首先,你要下载一个 memcached 服务端安装一下,这是他的网址:https://github.com/memcached/memcached/wiki/ReleaseNotes,如果是 Windows 系统,自己去找安装包安装一下即可。启动服务。

    然后,你需要一个 xmemcached.jar 包,你可以直接通过我GitHub上的示例项目直接获取到,我贴一个地址:https://github.com/mafly/SpringDemo/blob/master/WebContent/WEB-INF/lib/xmemcached-1.3.8.jar

    开试写代码吧

    一、在src目录下建立memcached.properties配置文件
    这个文件是用来存 memcached 服务器的地址、端口和权重的信息的

    memcached.connectionPoolSize=10  
    memcached.failureMode=true  
    
    #server1  
    server1.memcached.host=127.0.0.1
    server1.memcached.port=11211
    server1.memcached.weight=4
    
    #server2  
    server2.memcached.host=127.0.0.1
    server2.memcached.port=11212
    server2.memcached.weight=6

    我这里是配置两台服务器用以测试,不同的权重。具体文件请访问 https://github.com/mafly/SpringDemo/blob/memcached/src/memcached.properties 查看。

    二、在applicationContext.xml文件中配置
    打开applicationContext.xml文件,在下面加入 memcached 的配置:

    <!-- Memcached 配置 -->
    <bean id="memcachedClientBuilder" class="net.rubyeye.xmemcached.XMemcachedClientBuilder"
        p:connectionPoolSize="${memcached.connectionPoolSize}" p:failureMode="${memcached.failureMode}">
        <!-- XMemcachedClientBuilder have two arguments.First is server list,and second is weights array. -->
        <constructor-arg>
            <list>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg>
                        <value>${server1.memcached.host}</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>${server1.memcached.port}</value>
                    </constructor-arg>
                </bean>
                <bean class="java.net.InetSocketAddress">
                    <constructor-arg>
                        <value>${server2.memcached.host}</value>
                    </constructor-arg>
                    <constructor-arg>
                        <value>${server2.memcached.port}</value>
                    </constructor-arg>
                </bean>
            </list>
        </constructor-arg>
        <constructor-arg>
            <list>
                <value>${server1.memcached.weight}</value>
                <value>${server2.memcached.weight}</value>
            </list>
        </constructor-arg>
        <property name="commandFactory">
            <bean class="net.rubyeye.xmemcached.command.TextCommandFactory" />
        </property>
        <property name="sessionLocator">
            <bean class="net.rubyeye.xmemcached.impl.KetamaMemcachedSessionLocator" />
        </property>
        <property name="transcoder">
            <bean class="net.rubyeye.xmemcached.transcoders.SerializingTranscoder" />
        </property>
    </bean>
    <!-- Use factory bean to build memcached client -->
    <bean id="memcachedClient" factory-bean="memcachedClientBuilder"
        factory-method="build" destroy-method="shutdown" />

    这里的地址及端口就是读取刚刚的memcached.properties配置文件。当然,你不能忘了把配置文件读取到 Spring 容器中管理。

    三、建立cn.mayongfa.cache包,并新增MemcachedBasis.java基础类
    1.新建cn.mayongfa.cache包我就说了,大家都会的,重要的是建完包之后要在applicationContext.xml文件中配置扫描包,完成 Bean 的注入 。就是下面:

        <context:component-scan base-package="cn.mayongfa.cache" />

    2.新建MemcachedBasis.java类。

    @Component
    public class MemcachedBasis {
    
        @Autowired
        protected MemcachedClient memcachedClient;
    
        /**
        * 失效时间(秒)3600*24 一天
        */
        protected int Exptime = 3600 * 24;
    
        /**
        * 基础数据失效时间(秒)3600*24*7 一周
        */
        protected int DataExptime = this.Exptime * 7;
    
        protected String Prefix = "SPRINGDEMO:";
    }

    都是我们需要用的基本信息,就是一个基类的概念,主要用于其他缓存类继承它,就不需要重复定义这些变量了。

    四、新增UserBasisCache.java缓存类,继承于MemcachedBasis.java

    @Component
    public class UserBasisCache extends MemcachedBasis {
    
    private Logger log = Logger.getLogger(UserBasisCache.class);
    @Autowired
    private UserBasisDao userBasisDao;
    
    /**
     * 设置缓存
     * 
     * @param model
     *            用户model
     * @return
     */
    public Boolean set(UserBasis model) {
        Boolean result = false;
        try {
            result = memcachedClient.set(getCacheKey(model.getId()), super.Exptime, model);
        } catch (TimeoutException | InterruptedException | MemcachedException e) {
            log.error("", e);
        }
        return result;
    }
    
    /**
     * 获取缓存
     * 
     * @param id
     *            用户ID
     * @return
     */
    public UserBasis get(long id) {
        UserBasis entity = new UserBasis();
        try {
            entity = memcachedClient.get(getCacheKey(id));
            if (entity == null || entity.getId() <= 0) {
                entity = userBasisDao.getEntity(id);
                this.set(entity);
            }
        } catch (TimeoutException | InterruptedException | MemcachedException e) {
            log.error("", e);
            entity = userBasisDao.getEntity(id);
        }
        return entity;
    }
    
    /**
     * 删除缓存
     * 
     * @param id
     *            用户ID
     * @return
     */
    public Boolean delete(long id) {
        try {
            return memcachedClient.delete(getCacheKey(id));
        } catch (TimeoutException | InterruptedException | MemcachedException e) {
            log.error("", e);
        }
        return false;
    }
    
    /**
     * 获取缓存 Key
     * 
     * @param id
     *            用户ID
     * @return
     */
    private String getCacheKey(long id) {
        return super.Prefix + "UserBasis:" + id;
    }
    }

    这个就是具体的业务逻辑的缓存的获取、增加、修改和删除的处理了,这里是以每个用户来添加到缓存,只是用来演示的,具体的情况你们自己处理。

    还记不记得上篇文章说:我们怎么做到缓存对代码的侵入性,以及我们怎么更方便或者说不需要改代码就实现缓存。 其实这个时候,我们会发现我们项目架构是分层的,分层的意义不就是为了分配职责、减小耦合和定义标准嘛。那这个时候我们如果都在实现层(Service.Imp)来实现缓存的增删改查,那是不是 Controller 层的调用就不需要任何改动了,也不需要考虑缓存怎么实现的了,不需要去执行缓存的增删改查了,还是像原来那样直接调用实现层的方法就行了。

    五、修改UserBasisServiceImp.java类,实现缓存的增删改查
    最开始这个类其中的方法是这样的:

    @Override
    public long Save(UserBasis entity) {
        return UserBasisdao.Save(entity);
    }
    
    @Override
    public Boolean Delete(long ID) {
        return UserBasisdao.Delete(ID);
    }
    
    @Override
    public UserBasis getEntity(long ID) {
        return UserBasisdao.getEntity(ID);
    }

    我们改成了这样的:

    @Autowired
    private UserBasisCache UserBasiscache;
    
    @Override
    public long Save(UserBasis entity) {
        long id = UserBasisdao.Save(entity);
        if (id > 0) {
            UserBasiscache.set(entity);
        }
        return id;
    }
    
    @Override
    public Boolean Delete(long ID) {
        boolean result = UserBasisdao.Delete(ID);
        if (result) {
            UserBasiscache.delete(ID);
        }
        return result;
    }
    
    @Override
    public UserBasis getEntity(long ID) {
        return UserBasiscache.get(ID);
    }

    看出来区别了吧,就是我们在实现层处理了缓存的操作,并不需要去最外层的调用处处理了。

    总结一下

    上一篇文章我讲了整个选择缓存的心路历程,虽然没有干货,但都是值得思考的东西,这篇文章就有了干货,可以让你用「最原始版」方式来灵活在项目中实现缓存。希望我的分享对你有所帮助吧,所有这些配置及代码都可以在我的 GitHub 上关于 Spring 的示例项目看到:https://github.com/mafly/SpringDemo/tree/memcached

    又写到凌晨一点,我睡了。

  • 相关阅读:
    Android UI组件之自定义控件实现IP地址控件
    封装一个类搞定90%安卓客户端与服务器端交互
    深入理解 RecyclerView 系列之:ItemDecoration
    Android开发技巧——设置系统状态栏颜色
    Activity,Fragment的状态保存
    Activity生命周期函数、onSaveInstanceState()和onRestoreInstanceState()的介绍
    Android Fragment生命周期
    恢复云数据库MySQL的备份文件到自建数据库遇到的报错
    如何在宿主机上查看kvm虚拟机的IP
    批量分发公钥脚本
  • 原文地址:https://www.cnblogs.com/xieyulin/p/7070299.html
Copyright © 2020-2023  润新知