`

Ehcache简单应用——RSSReaderTag

阅读更多
关于缓存,关于自己运用,大部分情况是通过ORM配置生效。基本上不曾写过什么代码,甭说是心得了!但难免会遇到没有ORM提供帮助的时候,咱就只好写写代码做作缓存了! 相信你想到了我的名言——之前写了一堆,没整理,现在翻来找不到!
缓存代码以前写了不少,不过一直没有整理,丢三落四总犯懒!

这次遇到这么个需求,要在页面上动态显示RSS条目。如果要在页面上获取RSS,就需要向远程服务器发送请求,同时需要解析,展示。如果这页面被多次访问,就会导致多次HTTP请求,很可能自己的网站没打开,反倒把RSS服务器搞宕机了!这时候,就需要通过缓存RSS信息,减少请求次数来提高响应效率了!
再者,通过标签简化JSP代码实现!
路透: 科技电子作为样例,最后搞一个这样的页面:

说说RSS的节点,这里先说image
RSS中给出如下结构
<image>
	<title>Reuters News</title>
	<width>120</width>
	<height>35</height>
	<link>http://cn.reuters.com</link>
	<url>http://cn.reuters.com/resources/images/reuters120.gif</url>
</image>

对应给出域对象Image
import java.io.Serializable;

/**
 * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
 * @since 1.0
 */
public class Image implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 3377367647893337410L;

	/**
	 * 高
	 */
	private String height;
	/**
	 * 宽
	 */
	private String width;
	/**
	 * 链接
	 */
	private String link;

	/**
	 * 标题
	 */
	private String title;
	/**
	 * 图片路径
	 */
	private String url;
}

import java.io.Serializable; Why?
考虑到这些域对象可能需要缓存,就需要涉及到将对象保存到文件中,也就是序列化操作。因此,当我们构建域对象时,最好实现序列化接口!
再看Item
RSS中给出如下结构
<item>
	<title>摩托罗拉和Verizon合作开发数字平板设备--FT</title>
	<description>  路透伦敦8月4日电---金融时报周三报导,美国移动电话生产商摩托罗拉正在与Verizon Wireless合作开发一款数字平板设备,用来与苹果的iPad竞争.</description>
	<link>http://cn.reuters.com/article/CNTechNews/idCNCHINA-2770720100804?feedType=RSS&amp;feedName=CNTechNews</link>
	<guid isPermaLink="false">CNCHINA-2770720100804</guid>
	<category>CNTechNews</category>
	<pubDate>Wed, 04 Aug 2010 11:08:34 +0800</pubDate>
</item>

给出对应绑定域对象
import java.io.Serializable;

/**
 * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
 * @since 1.0
 * 
 */
public class Item implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = -8860646418160016186L;

	/**
	 * 标题
	 */
	private String title;
	/**
	 * 描述
	 */
	private String description;
	/**
	 * 链接
	 */
	private String link;
	/**
	 * guid
	 */
	private String guid;
	/**
	 * 分类
	 */
	private String category;
	/**
	 * 发布日期
	 */
	private String pubDate;
}

最后是Channel
RSS中给出如下结构,也是一个完整的RSS。
<?xml version="1.0" encoding="UTF-8" ?>
<rss version="2.0" >
	<channel>
		<title>路透: 科技电子</title>
		<link>http://cn.reuters.com</link>
		<description>路透中文网提供实时新闻,财经资讯和投资信息。路透社是全球最大的新闻通讯社之一,为全球媒体,金融实体,商业组织和个人提供新闻报道,金融资讯和相关技术方案。</description>
		<image>
			<title>Reuters News</title>
			<width>120</width>
			<height>35</height>
			<link>http://cn.reuters.com</link>
			<url>http://cn.reuters.com/resources/images/reuters120.gif</url>
		</image>
		<language>en-us</language>
		<lastBuildDate>Wed, 04 Aug 2010 14:03:25 +0800</lastBuildDate>
		<copyright>All rights reserved. Users may download and print extracts of content from this website for their own personal and non-commercial use only. Republication or redistribution of Reuters content, including by framing or similar means, is expressly prohibited without the prior written consent of Reuters. Reuters and the Reuters sphere logo are registered trademarks or trademarks of the Reuters group of companies around the world. &#169; Reuters 2010</copyright>
		<item>
			<title>摩托罗拉和Verizon合作开发数字平板设备--FT</title>
			<description>  路透伦敦8月4日电---金融时报周三报导,美国移动电话生产商摩托罗拉正在与Verizon Wireless合作开发一款数字平板设备,用来与苹果的iPad竞争.</description>
			<link>http://cn.reuters.com/article/CNTechNews/idCNCHINA-2770720100804?feedType=RSS&amp;feedName=CNTechNews</link>
			<guid isPermaLink="false">CNCHINA-2770720100804</guid>
			<category>CNTechNews</category>
			<pubDate>Wed, 04 Aug 2010 11:08:34 +0800</pubDate>
		</item>
	</channel>
</rss>

image节点只有一个,但item节点就可能有多个!
对应的Channel域对象如下:
import java.io.Serializable;
import java.util.List;

/**
 * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
 * @since 1.0
 * 
 */
public class Channel implements Serializable {
	/**
	 * 
	 */
	private static final long serialVersionUID = 549783894750767576L;

	/**
	 *标题
	 */
	private String title;
	/**
	 * 链接
	 */
	private String link;
	/**
	 * 描述
	 */
	private String description;
	/**
	 * 上次发布时间
	 */
	private String lastBuildDate;
	/**
	 * doc
	 */
	private String docs;
	/**
	 * 语言
	 */
	private String language;
	/**
	 * 版权
	 */
	private String copyright;
	/**
	 * 图片
	 */
	private Image image;

	/**
	 * 项列表
	 */
	private List<Item> itemList;

域对象准备好了,我们就需要对xml进行转换,通过Dom4J做相应实现!这部分内容,太基础了,详见附件吧!(查看RSSReader类)
今天的主角是CacheHolder,用来维护缓存调用!
import net.sf.ehcache.Cache;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Element;

import org.apache.log4j.Logger;

/**
 * 缓存控制器
 * 
 * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
 * @since 1.0
 * 
 */
public class CacheHolder {

	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(CacheHolder.class);

	private static CacheHolder INSTANCE;

	/**
	 * 缓存管理器
	 */
	private CacheManager cm;

	/**
	 * 缓存
	 */
	private Cache cache;

	/**
	 * 获取缓存控制器
	 * 
	 * @param cacheName
	 * @return
	 */
	public static synchronized CacheHolder getCacheHolder(String cacheName) {

		if (INSTANCE == null) {
			INSTANCE = new CacheHolder(cacheName);
		}
		return INSTANCE;
	}

	/**
	 * @param cacheName
	 */
	private CacheHolder(String cacheName) {
		try {

			cm = CacheManager.create();

		} catch (CacheException e) {
			logger.warn(e.getMessage());
		}

		cache = cm.getCache(cacheName);

		if (cache == null) {
			cache = new Cache("LRU", 500, false, false, 60 * 60 * 24,
					60 * 60 * 12);
			cm.addCache(cache);
		}
	}

	/**
	 * 添加缓存对象
	 * 
	 * @param key
	 * @param value
	 */
	public void add(Object key, Object value) {
		Element e = new Element(key, value);
		cache.put(e);
		if (logger.isDebugEnabled()) {
			logger.debug("Cache:[" + key + "]");
		}
	}

	/**
	 * 获得缓存对象
	 * 
	 * @param key
	 */
	public Object get(Object key) {
		Element e = cache.get(key);
		if (e != null) {
			if (logger.isDebugEnabled()) {
				logger.debug("Cache Hit:[" + key + "]");
			}
			return e.getObjectValue();
		}
		return null;
	}

	/**
	 * 删除指定缓存对象
	 * 
	 * @param key
	 * @return {@link Object}
	 */
	public void remove(Object key) {
		cache.remove(key);
	}

	/**
	 * 删除所有缓存对象
	 * 
	 */
	public void removeAll() {
		cache.removeAll();
	}

}

通常,我们需要通过单例模式进行调度:
	private static CacheHolder INSTANCE;

	/**
	 * 缓存管理器
	 */
	private CacheManager cm;

	/**
	 * 获取缓存控制器
	 * 
	 * @param cacheName
	 * @return
	 */
	public static synchronized CacheHolder getCacheHolder(String cacheName) {

		if (INSTANCE == null) {
			INSTANCE = new CacheHolder(cacheName);
		}
		return INSTANCE;
	}

在构建单例模式时,最重要的是使得构造方法为私有方法:

	/**
	 * 缓存
	 */
	private Cache cache;
	/**
	 * @param cacheName
	 */
	private CacheHolder(String cacheName) {
		try {

			cm = CacheManager.create();

		} catch (CacheException e) {
			logger.warn(e.getMessage());
		}

		cache = cm.getCache(cacheName);

		if (cache == null) {
			cache = new Cache("LRU", 500, false, false, 60 * 60 * 24,
					60 * 60 * 12);
			cm.addCache(cache);
		}
	}

这里设定了默认的调用算法为“LRU”也就是最近最少访问的对象将被清理!
默认的timeToLiveSeconds为60 * 60 * 24=1day,也就是说缓存最多保留1天,时间一到自动清理。
默认的timeToIdleSeconds为60 * 60 * 12=0.5day,也就是说缓存空闲最多为半天,如果这个对象半天内不被访问将被清理。
如果想要灵活配置,就配置ehcache.xml文件好了:
<?xml version="1.0" encoding="UTF-8"?>
<ehcache
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:noNamespaceSchemaLocation="ehcache.xsd">
	<diskStore
		path="java.io.tmpdir" />
	<defaultCache
		maxElementsInMemory="10000"
		eternal="false"
		timeToIdleSeconds="120"
		timeToLiveSeconds="120"
		overflowToDisk="true"
		diskPersistent="false"
		diskSpoolBufferSizeMB="30"
		maxElementsOnDisk="10000000"
		diskExpiryThreadIntervalSeconds="120"
		memoryStoreEvictionPolicy="LRU" />
	<cache
		name="com.netqin.tag.rss.Channel"
		maxElementsInMemory="1"
		eternal="false"
		overflowToDisk="true"
		timeToIdleSeconds="3600"
		timeToLiveSeconds="3600"
		memoryStoreEvictionPolicy="LFU" />
</ehcache>

这里通过
<cache
		name="com.netqin.tag.rss.Channel"
		maxElementsInMemory="1"
		eternal="false"
		overflowToDisk="true"
		timeToIdleSeconds="3600"
		timeToLiveSeconds="3600"
		memoryStoreEvictionPolicy="LFU" />
对com.netqin.tag.rss.Channel进行配置,确保1小时内刷新缓存!
How?
给出部分RSSReader类实现:
import org.apache.log4j.Logger;

import java.util.LinkedList;
import java.util.List;

import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

/**
 * RSSReader
 * 
 * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
 * @since 1.0
 * 
 */
public abstract class RSSReader {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(RSSReader.class);

	private static final CacheHolder cacheHolder = CacheHolder
			.getCacheHolder("com.netqin.tag.rss");
	public static final String KEY = "com.netqin.tag.rss.Channel";

	/**
	 * 获得渠道
	 * 
	 * @param doc
	 * @return
	 */
	public static Channel getChannel(String url) throws Exception {
		Channel channel = (Channel) cacheHolder.get(KEY);

		if (channel == null) {

			Document doc = getDocument(url);
			channel = toChannel(doc);

			cacheHolder.add(KEY, channel);
		}
		return channel;
	}
}

使用,就这么简单!
最后,用tag包装一下:
import org.apache.log4j.Logger;

import javax.servlet.jsp.JspException;
import javax.servlet.jsp.tagext.TagSupport;

/**
 * RSSTag标签
 * 
 * @author <a href="mailto:zlex.dongliang@gmail.com">梁栋</a>
 * @since 1.0
 * 
 */
public class RSSTag extends TagSupport {
	/**
	 * Logger for this class
	 */
	private static final Logger logger = Logger.getLogger(RSSTag.class);

	/**
	 * 
	 */
	private static final long serialVersionUID = -8392115916509318259L;

	public static final String REQUEST_ATTRIBUTE_NAME = "rssChannel";

	/**
	 * 请求路径
	 */
	private String url;

	/**
	 * request的Attribute中的Channel名字
	 */
	private String channelName;

	/**
	 * @return the channelName
	 */
	public String getChannelName() {
		return channelName == null ? REQUEST_ATTRIBUTE_NAME : channelName;
	}

	/**
	 * @param channelName
	 *            the channelName to set
	 */
	public void setChannelName(String channelName) {
		this.channelName = channelName;
	}

	/**
	 * @param url
	 *            the url to set
	 */
	public void setUrl(String url) {
		this.url = url;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see javax.servlet.jsp.tagext.TagSupport#doStartTag()
	 */
	@Override
	public int doStartTag() throws JspException {
		try {
			Channel channel = RSSReader.getChannel(url);
			this.pageContext.getRequest().setAttribute(getChannelName(),
					channel);
		} catch (Exception e) {
			logger.warn(e.getMessage());
			throw new JspException(e);
		}
		return super.doStartTag();
	}

}

我们通过url设置请求的rss站点,通过设置channelName,指定Channel对象在Request的Attribute中的命名。
再构建一个TLD:
<?xml version="1.0" encoding="UTF-8"?>
<taglib
	xmlns="http://java.sun.com/xml/ns/j2ee"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-jsptaglibrary_2_0.xsd"
	version="2.0">
	<description>Restricts JSP pages to the RSS tag libraries</description>
	<display-name>rssTaglibs</display-name>
	<tlib-version>1.0</tlib-version>
	<short-name>rss</short-name>
	<uri>http://www.zlex.org/tag/rss</uri>

	<!-- <rss:rss/> -->
	<tag>
		<description>&lt;rss:rss/&gt;</description>
		<name>rss</name>
		<tag-class>org.zlex.commons.web.tag.rss.RSSTag</tag-class>
		<body-content>JSP</body-content>
		<attribute>
			<description>请求地址</description>
			<name>url</name>
			<required>true</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
		<attribute>
			<description>Request的Attribute中的Channel名称</description>
			<name>channelName</name>
			<required>false</required>
			<rtexprvalue>true</rtexprvalue>
		</attribute>
	</tag>

</taglib>

这就够用了!
注意打包时,包含tld文件,注意要包含在META-INF目录中:

这样,我们就不需要在web.xml中配置了!
在页面中使用
<%@ taglib prefix="rss" uri="http://www.zlex.org/tag/rss"%>

引入标签,然后在JSP中写入如下代码:
<rss:rss url="http://cn.reuters.com/rssFeed/CNTechNews/"
	channelName="channel" />
<a href="${channel.link}"><img
	src='<c:url value="${channel.image.url}"/>'
	alt="${channel.image.title}" /></a>
<dt><c:out value="${channel.title}" /></dt>
<dl>
	<c:forEach begin="0" end="2" items="${channel.itemList}" var="item">
		<dd><a href='<c:url value="${item.link}" />'><c:out
			value="${item.title}" /></a></dd>
	</c:forEach>
</dl>

就可以获得本文开篇的图样!
缓存有没有效果:

详细内容,看附件,下次需要缓存实现,我就不用到处翻了!呵呵!
  • 大小: 34.4 KB
  • 大小: 36.1 KB
  • 大小: 63 KB
  • rss.rar (1.7 MB)
  • 下载次数: 139
3
1
分享到:
评论
3 楼 zhhaojie 2015-11-15  
写得非常好。清晰明了。
2 楼 di1984HIT 2014-04-14  
写的真的很好啊。
1 楼 rockyeah 2010-08-09  
JavaEye不让下载了?

相关推荐

    Ehcache 简单的监控

    本文将深入探讨Ehcache的简单监控,帮助开发者更好地理解其工作原理和性能状态。 首先,了解Ehcache的核心概念是至关重要的。Ehcache分为三个主要部分:内存缓存、磁盘存储和缓存复制。内存缓存用于存储最近使用的...

    Ehcache分布式缓存与其在SpringBoot应用

    Ehcache是一个高性能的、基于Java的进程内缓存解决方案,它被广泛应用于各种Java应用程序,包括Java EE和轻量级容器。Ehcache的主要优势在于它的快速响应、易用性和丰富的缓存策略。它提供了两种级别的缓存存储:...

    springmvc+ehcache简单例子

    在这个“springmvc+ehcache简单例子”中,我们将探讨如何将两者结合使用,以实现高效的数据缓存。 首先,让我们了解一下Spring MVC。Spring MVC提供了一个分层架构,允许开发者将业务逻辑、数据访问和用户界面分离...

    Mybatis入门实例(二)——添加ehcache缓存支持

    在本篇《Mybatis入门实例(二)——添加ehcache缓存支持》中,我们将深入探讨如何在Mybatis框架中集成Ehcache作为二级缓存,以提高数据访问的效率和性能。Ehcache是一个开源的Java分布式缓存,广泛用于缓存应用程序中...

    java 缓存插件ehcache 应用实例

    Ehcache是一款广泛使用的开源Java缓存框架,尤其在处理大量数据时,它可以显著提升应用程序的效率。本文将深入探讨Ehcache在实际应用中的实例。 一、Ehcache简介 Ehcache是由Terracotta公司开发的高性能、易用的...

    Spring AOP+ehCache简单缓存系统解决方案

    在IT行业中,Spring AOP(面向切面编程)和ehCache是两个重要的工具,它们在构建高效、可扩展的应用程序时发挥着关键作用。本文将深入探讨如何利用这两个技术实现一个简单的缓存系统解决方案。 首先,Spring AOP是...

    ehcache.jar及源码

    Ehcache是一个广泛使用的开源Java缓存库,它为应用程序提供了高效的内存管理和数据缓存功能。Ehcache的核心目标是提高应用性能,通过将频繁访问的数据存储在内存中,减少对数据库的依赖,从而降低系统负载。这次我们...

    Ehcache缓存框架的简单应用

    Ehcache是一个开源的、高性能的Java缓存框架,它被广泛用于提高应用程序的性能,减少数据库的负载,以及优化数据访问。在本文中,我们将深入探讨Ehcache的基本概念、配置、使用方法以及其在实际应用中的优势。 **...

    ehcache-core-2.6.11.jar

    这里我们关注的是Ehcache的核心库,具体是三个不同版本——ehcache-core-2.6.11,ehcache-core-2.6.9,以及ehcache-core-2.5.0。 1. Ehcache核心功能: Ehcache的核心功能包括内存缓存、磁盘缓存、分布式缓存以及...

    ehcache.xsd_ehcache.xml代码提示.rar

    Ehcache是一个广泛使用的开源Java缓存解决方案,它能够提高应用程序性能,通过缓存数据和对象来减少数据库查询。 【描述解析】:描述中提到“已测试有效的ehcache.xsd文件”,这指的是Ehcache的XML Schema定义文件...

    EHCache的使用

    通过以上步骤,我们可以轻松地将 EHCache 整合到基于 Spring 的应用程序中,从而提高系统的整体性能和响应速度。 ### 总结 EHCache 作为一款成熟的缓存解决方案,在处理高并发、高性能的应用场景中表现出色。通过...

    ehcache监控工具ehcache-monitor-kit-1.0.3

    1.解压缩到目录下,复制ehcache-monitor-kit-1.0.0\lib\ehcache-probe-1.0.0.jar包到application的web-inf/lib目录下 2.将以下配置copy的ehcache.xml文件的ehcache标签中,注:上述链接中说的配置少写了个probe包名...

    Ehcache通过Jgroups做集群

    在Ehcache通过Jgroups进行集群配置时,首先需要理解Jgroups的配置文件——`jgroups.xml`。这个文件定义了集群中节点如何相互发现、通信以及故障检测的规则。配置文件中的关键元素包括: 1. **Transport**: 定义了...

    hibernate+ehcache

    综上所述,Hibernate 与 Ehcache 的整合为 Java 应用提供了高效的数据缓存能力,减少了数据库交互,提升了应用性能。理解和掌握它们的整合方式及优化策略,对于构建高性能的 Java Web 应用至关重要。

    Ehcache经典教程实例应用-原创

    - **简单**:其API简洁明了,易于集成到Java应用程序中。 - **多种缓存策略**:支持LRU(最近最少使用)、LFU(最不经常使用)等缓存替换策略。 - **两级缓存**:内存和磁盘,当内存满时,数据会被自动移至磁盘,...

    ehcache资料(包含ehcache jar包)

    9. **API友好**:Ehcache提供了简单易用的API,使得开发者能够轻松地进行缓存操作。 **Ehcache的使用步骤:** 1. **添加依赖**:将提供的Ehcache jar包引入到项目类路径中,如果是Maven或Gradle项目,需要在配置...

    ehcache

    Ehcache 是一个开源的、高性能的缓存解决方案,广泛应用于Java应用程序中,尤其在提升系统性能和减少数据库负载方面表现突出。它支持内存和磁盘存储,并且可以与Java持久层框架如Hibernate、JPA等无缝集成。 ## 1. ...

    Java缓存框架 EhCache

    6. **API与集成**:EhCache提供了简单易用的API,开发者可以通过Java API进行缓存操作。同时,EhCache与许多流行框架如Spring、Hibernate等有很好的集成,使得在这些框架中使用EhCache变得十分方便。在Hibernate中,...

Global site tag (gtag.js) - Google Analytics