Play Framework 1.2.7学习笔记之Cache

1.play framework中Cache实现默认提供了Ehcache和Memcache两种实现。Ehcache是单节点的,而Memcached是

可以集群的。涉及到的类很少,具体如下:

2.CacheImpl 实现接口

定义了从缓存中增删改查的各种接口方法:
public interface CacheImpl {

    public void add(String key, Object value, int expiration);

    public boolean safeAdd(String key, Object value, int expiration);

    public void set(String key, Object value, int expiration);

    public boolean safeSet(String key, Object value, int expiration);

    public void replace(String key, Object value, int expiration);

    public boolean safeReplace(String key, Object value, int expiration);

    public Object get(String key);

    public Map<String, Object> get(String[] keys);

    public long incr(String key, int by);

    public long decr(String key, int by);

    public void clear();

    public void delete(String key);

    public boolean safeDelete(String key);

    public void stop();
}

3.Cache 代理类

作用:play启动时会调用Cache.init方法,停止时调用Cache.stop方法。init方法中会根据配置文件决定使用Ehcache还是Memcache
/**
     * Initialize the cache system.
     */
    public static void init() {
        if(forcedCacheImpl != null) {
            cacheImpl = forcedCacheImpl;
            return;
        }
        if (Play.configuration.getProperty("memcached", "disabled").equals("enabled")) {
            try {
            	//使用Memcache
                cacheImpl = MemcachedImpl.getInstance(true);
                Logger.info("Connected to memcached");
            } catch (Exception e) {
                Logger.error(e, "Error while connecting to memcached");
                Logger.warn("Fallback to local cache");
                //使用Ehcache
                cacheImpl = EhCacheImpl.newInstance();
            }
        } else {
            cacheImpl = EhCacheImpl.newInstance();
        }
    }
stop方法调用具体实现类(Ehcache或者Memcache)的stop方法来关闭资源
/**
     * Stop the cache system.
     */
    public static void stop() {
        cacheImpl.stop();
    }
4.Ehcache 实现类
使用单例模式(不太严谨,因为实在启动的时候调用,不会出现并发的情况)来初始化Ehcache对象并提够服务。
构造方法如下:
private static EhCacheImpl uniqueInstance;

    CacheManager cacheManager;

    net.sf.ehcache.Cache cache;

    private static final String cacheName = "play";

    private EhCacheImpl() {
        this.cacheManager = CacheManager.create();
        this.cacheManager.addCache(cacheName);
        this.cache = cacheManager.getCache(cacheName);
    }

5.Memcache 实现类

同样使用单例模式(不太严谨,因为实在启动的时候调用,不会出现并发的情况)来初始化Memcache对象并提够服务。
单例方法如下:里面有一段逻辑不理解,期待大牛指点,嘿嘿。
public static MemcachedImpl getInstance(boolean forceClientInit) throws IOException {
        if (uniqueInstance == null) {
            uniqueInstance = new MemcachedImpl();
        } else if (forceClientInit) {
        	//这部分不理解,期待大牛指点,嘿嘿。
            // When you stop the client, it sets the interrupted state of this thread to true. If you try to reinit it with the same thread in this state,
            // Memcached client errors out. So a simple call to interrupted() will reset this flag
            Thread.interrupted();
            uniqueInstance.initClient();
        }
        return uniqueInstance;

    }
initClient方法如下:只有主机、用户名、密码配置项,配置项较少(没有超时时间,连接池等配置项),难于精确控制。
public void initClient() throws IOException {
        System.setProperty("net.spy.log.LoggerImpl", "net.spy.memcached.compat.log.Log4JLogger");
        
        List<InetSocketAddress> addrs;
        if (Play.configuration.containsKey("memcached.host")) {
        	//单节点
            addrs = AddrUtil.getAddresses(Play.configuration.getProperty("memcached.host"));
        } else if (Play.configuration.containsKey("memcached.1.host")) {
            int nb = 1;
            String addresses = "";
            //集群配置
            while (Play.configuration.containsKey("memcached." + nb + ".host")) {
                addresses += Play.configuration.get("memcached." + nb + ".host") + " ";
                nb++;
            }
            addrs = AddrUtil.getAddresses(addresses);
        } else {
            throw new ConfigurationException("Bad configuration for memcached: missing host(s)");
        }
        if (Play.configuration.containsKey("memcached.user")) {
        	//用户名
            String memcacheUser = Play.configuration.getProperty("memcached.user");
            //密码
            String memcachePassword = Play.configuration.getProperty("memcached.password");
            if (memcachePassword == null) {
                throw new ConfigurationException("Bad configuration for memcached: missing password");
            }
            
            // Use plain SASL to connect to memcached
            AuthDescriptor ad = new AuthDescriptor(new String[]{"PLAIN"},
                                    new PlainCallbackHandler(memcacheUser, memcachePassword));
            ConnectionFactory cf = new ConnectionFactoryBuilder()
                                        .setProtocol(ConnectionFactoryBuilder.Protocol.BINARY)
                                        .setAuthDescriptor(ad)
                                        .build();
            
            client = new MemcachedClient(cf, addrs);
        } else {
            client = new MemcachedClient(addrs);
        }
    }
6.CacheFor 注解类
/**
 * Cache an action's result.
 *
 * <p>If a time is not specified, the results will be cached for 1 hour by default.
 *
 * <p>Example: <code>@CacheFor("1h")</code>
 */
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface CacheFor {
    String value() default "1h";
    String id() default "";
}
在controller类的方法上使用。例如:@CacheFor("1h")。当用浏览器访问这个方法的url时,play会从Cache的缓存中查找,如果没有,就会把result放到缓存中。如果一小时内在收到同样的url请求,就会直接从Cache中获取并直接返回 (根据代码推测而来,目前还在学习中,有误请指教,谢谢)
以下只复制了部分代码:
//判断必须是GET或者HEAD请求,并且被CacheFor注解的方法
                // Check the cache (only for GET or HEAD)
                if ((request.method.equals("GET") || request.method.equals("HEAD")) && actionMethod.isAnnotationPresent(CacheFor.class)) {
                    cacheKey = actionMethod.getAnnotation(CacheFor.class).id();
                    if ("".equals(cacheKey)) {
                        cacheKey = "urlcache:" + request.url + request.querystring;
                    }
                    actionResult = (Result) play.cache.Cache.get(cacheKey);
                }
                //如果缓存中不存在,添加结果到缓存中并返回
                if (actionResult == null) {
                    ControllerInstrumentation.initActionCall();
                    try {
                        inferResult(invokeControllerMethod(actionMethod));
                    } catch(Result result) {
                        actionResult = result;
                        // Cache it if needed
                        if (cacheKey != null) {
                            play.cache.Cache.set(cacheKey, actionResult, actionMethod.getAnnotation(CacheFor.class).value());
                        }
                    } catch (InvocationTargetException ex) {
7.小结
play中的Cache实现相对简单(简单也有还未明白的地方),大概逻辑应该清楚了,具体细节有很多还未明白,求指导。









  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值