- 浏览: 755068 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
lgh1992314:
a offset: 26b offset: 24c offse ...
java jvm字节占用空间分析 -
ls0609:
语音实现在线听书http://blog.csdn.net/ls ...
Android 语音输入API使用 -
wangli61289:
http://viralpatel-net-tutorials ...
Android 语音输入API使用 -
zxjlwt:
学习了素人派http://surenpi.com
velocity宏加载顺序 -
tt5753:
谢啦........
Lucene的IndexWriter初始化时的LockObtainFailedException的解决方法
encache的web cache代码分析
1.抽象filter分析
public abstract class Filter implements javax.servlet.Filter {
...... public final void doFilter(final ServletRequest request, final ServletResponse response, final FilterChain chain) throws ServletException, IOException { final HttpServletRequest httpRequest = (HttpServletRequest) request; final HttpServletResponse httpResponse = (HttpServletResponse) response; try { //NO_FILTER set for RequestDispatcher forwards to avoid double gzipping if (filterNotDisabled(httpRequest)) { //判断是否需要进行改cache filter的处理,防止再次进入,简单的通过获取attribute属性来判断 doFilter(httpRequest, httpResponse, chain); } else { chain.doFilter(request, response); } } catch (final Throwable throwable) { logThrowable(throwable, httpRequest); } } protected boolean filterNotDisabled(final HttpServletRequest httpRequest) { return httpRequest.getAttribute(NO_FILTER) == null; } ...... //提供几个抽象方法供子类覆盖 /** * A template method that performs any Filter specific destruction tasks. * Called from {@link #destroy()} */ protected abstract void doDestroy(); /** * A template method that performs the filtering for a request. * Called from {@link #doFilter(ServletRequest,ServletResponse,FilterChain)}. */ protected abstract void doFilter(final HttpServletRequest httpRequest, final HttpServletResponse httpResponse, final FilterChain chain) throws Throwable; /** * A template method that performs any Filter specific initialisation tasks. * Called from {@link #init(FilterConfig)}. * @param filterConfig */ protected abstract void doInit(FilterConfig filterConfig) throws Exception; }
2.实现上面filter的CachingFilter类分析
public abstract class CachingFilter extends Filter{
//初始化参数列表 public void doInit(FilterConfig filterConfig) throws CacheException { synchronized (this.getClass()) { if (blockingCache == null) { setCacheNameIfAnyConfigured(filterConfig); //从web.xml里面取出encache对应配置的cache名称 final String localCacheName = getCacheName(); Ehcache cache = getCacheManager().getEhcache(localCacheName); //根据cachename从encache管理器获取cache实例 if (cache == null) { throw new CacheException("cache '" + localCacheName + "' not found in configuration"); } if (!(cache instanceof BlockingCache)) { // decorate and substitute BlockingCache newBlockingCache = new BlockingCache(cache); getCacheManager().replaceCacheWithDecoratedCache(cache, newBlockingCache); } blockingCache = (BlockingCache) getCacheManager().getEhcache( localCacheName); //这里使用的是blockingCache Integer blockingTimeoutMillis = parseBlockingCacheTimeoutMillis(filterConfig);//从init-param里面获取设置的blocking的超时时间 if (blockingTimeoutMillis != null && blockingTimeoutMillis > 0) { blockingCache.setTimeoutMillis(blockingTimeoutMillis); } } } } protected void doFilter(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws AlreadyGzippedException, AlreadyCommittedException, FilterNonReentrantException, LockTimeoutException, Exception { if (response.isCommitted()) { throw new AlreadyCommittedException( "Response already committed before doing buildPage."); } logRequestHeaders(request);//记录request的日志 PageInfo pageInfo = buildPageInfo(request, response, chain);//从缓存里面取出缓存页面信息,如果缓存中不存在,则通过 chain.doFilter(request, wrapper);处理后,再把页面存入缓存, if (pageInfo.isOk()) { if (response.isCommitted()) { throw new AlreadyCommittedException( "Response already committed after doing buildPage" + " but before writing response from PageInfo."); } writeResponse(request, response, pageInfo);//更新request的header,status,cookie等相关信息,因为如果从缓存获取的话,需要把所有信息都写到response } } //再来看看buildPageInfo的处理 /** * Build page info either using the cache or building the page directly. * <p/> * Some requests are for page fragments which should never be gzipped, or * for other pages which are not gzipped. */ protected PageInfo buildPageInfo(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws Exception { // Look up the cached page final String key = calculateKey(request);//构造key,抽象方法,由子类覆盖 PageInfo pageInfo = null; try { checkNoReentry(request); //检查是否是同一个请求再次今夕,通过localthread来判断,如果已经进入过,则抛出FilterNonReentrantException异常,否则记录已经该请求进入处理 Element element = blockingCache.get(key); //从缓存取出对象 if (element == null || element.getObjectValue() == null) { try { // Page is not cached - build the response, cache it, and // send to client pageInfo = buildPage(request, response, chain);//如果缓存不存在,则正常处理, if (pageInfo.isOk()) {//如果处理ok, if (LOG.isDebugEnabled()) { LOG.debug("PageInfo ok. Adding to cache " + blockingCache.getName() + " with key " + key); } blockingCache.put(new Element(key, pageInfo));//则把页面内容重新存入缓存 } else { if (LOG.isDebugEnabled()) { LOG.debug("PageInfo was not ok(200). Putting null into cache " + blockingCache.getName() + " with key " + key); } blockingCache.put(new Element(key, null));//如果处理出错,则缓存设置为null } } catch (final Throwable throwable) { // Must unlock the cache if the above fails. Will be logged // at Filter blockingCache.put(new Element(key, null)); throw new Exception(throwable); } } else { pageInfo = (PageInfo) element.getObjectValue();//如果缓存存在,则取出内容 } } catch (LockTimeoutException e) { // do not release the lock, because you never acquired it throw e; } finally { // all done building page, reset the re-entrant flag visitLog.clear(); } return pageInfo; } /** * Builds the PageInfo object by passing the request along the filter chain * * @param request * @param response * @param chain * @return a Serializable value object for the page or page fragment * @throws AlreadyGzippedException * if an attempt is made to double gzip the body * @throws Exception */ //缓存不存在时的处理 protected PageInfo buildPage(final HttpServletRequest request, final HttpServletResponse response, final FilterChain chain) throws AlreadyGzippedException, Exception { // Invoke the next entity in the chain final ByteArrayOutputStream outstr = new ByteArrayOutputStream(); final GenericResponseWrapper wrapper = new GenericResponseWrapper( response, outstr);//这个responsewrapper,用于保存正常处理后的状态,cookie,header,结果信息,用于缓存 chain.doFilter(request, wrapper);//缓存不存在,则跳过由后续filter处理 wrapper.flush(); long timeToLiveSeconds = blockingCache.getCacheConfiguration() .getTimeToLiveSeconds(); // Return the page info return new PageInfo(wrapper.getStatus(), wrapper.getContentType(), wrapper.getCookies(), outstr.toByteArray(), true, timeToLiveSeconds, wrapper.getAllHeaders());//构造信息的该请求的缓存对象信息 } /** * Writes the response from a PageInfo object. * <p/> * Headers are set last so that there is an opportunity to override * * @param request * @param response * @param pageInfo * @throws IOException * @throws DataFormatException * @throws ResponseHeadersNotModifiableException * */ //从pageinfo里面取出response的相关信息写入到当前的response中 protected void writeResponse(final HttpServletRequest request, final HttpServletResponse response, final PageInfo pageInfo) throws IOException, DataFormatException, ResponseHeadersNotModifiableException { boolean requestAcceptsGzipEncoding = acceptsGzipEncoding(request); setStatus(response, pageInfo);//设置response的状态 setContentType(response, pageInfo);//设置response的contentType setCookies(pageInfo, response);//设置response的cookie // do headers last so that users can override with their own header sets setHeaders(pageInfo, requestAcceptsGzipEncoding, response);//设置response的header writeContent(request, response, pageInfo);//设置response的内容 } //比如: protected void setContentType(final HttpServletResponse response, final PageInfo pageInfo) { String contentType = pageInfo.getContentType(); if (contentType != null && contentType.length() > 0) { response.setContentType(contentType); } } /** * Set the serializableCookies * * @param pageInfo * @param response */ protected void setCookies(final PageInfo pageInfo, final HttpServletResponse response) { final Collection cookies = pageInfo.getSerializableCookies(); for (Iterator iterator = cookies.iterator(); iterator.hasNext();) { final Cookie cookie = ((SerializableCookie) iterator.next()) .toCookie(); response.addCookie(cookie); } } /** * Status code * * @param response * @param pageInfo */ protected void setStatus(final HttpServletResponse response, final PageInfo pageInfo) { response.setStatus(pageInfo.getStatusCode()); } protected void writeContent(final HttpServletRequest request, final HttpServletResponse response, final PageInfo pageInfo) throws IOException, ResponseHeadersNotModifiableException { byte[] body; boolean shouldBodyBeZero = ResponseUtil.shouldBodyBeZero(request, pageInfo.getStatusCode()); if (shouldBodyBeZero) { body = new byte[0]; } else if (acceptsGzipEncoding(request)) { body = pageInfo.getGzippedBody(); if (ResponseUtil.shouldGzippedBodyBeZero(body, request)) { body = new byte[0]; } else { ResponseUtil.addGzipHeader(response); } } else { body = pageInfo.getUngzippedBody(); } response.setContentLength(body.length); OutputStream out = new BufferedOutputStream(response.getOutputStream()); out.write(body); out.flush(); } }
对于checkNoReentry的实现,很简单
/**
* Check that this caching filter is not being reentered by the same * recursively. Recursive calls will block indefinitely because the first * request has not yet unblocked the cache. * <p/> * This condition usually indicates an error in filter chaining or * RequestDispatcher dispatching. * * @param httpRequest * @throws FilterNonReentrantException * if reentry is detected */ protected void checkNoReentry(final HttpServletRequest httpRequest) throws FilterNonReentrantException { String filterName = getClass().getName(); if (visitLog.hasVisited()) { throw new FilterNonReentrantException( "The request thread is attempting to reenter" + " filter " + filterName + ". URL: " + httpRequest.getRequestURL()); } else { // mark this thread as already visited visitLog.markAsVisited(); if (LOG.isDebugEnabled()) { LOG.debug("Thread {} has been marked as visited.", Thread .currentThread().getName()); } } } /** * threadlocal class to check for reentry * * @author hhuynh * */ private static class VisitLog extends ThreadLocal<Boolean> { @Override protected Boolean initialValue() { return false; } public boolean hasVisited() { return get(); } public void markAsVisited() { set(true); } public void clear() { super.remove(); } }
当然还有两个抽象方法
/**
* Gets the CacheManager for this CachingFilter. It is therefore up to * subclasses what CacheManager to use. * <p/> * This method was introduced in ehcache 1.2.1. Older versions used a * singleton CacheManager instance created with the default factory method. * * @return the CacheManager to be used * @since 1.2.1 */ protected abstract CacheManager getCacheManager(); /** * CachingFilter works off a key. * <p/> * The key should be unique. Factors to consider in generating a key are: * <ul> * <li>The various hostnames that a request could come through * <li>Whether additional parameters used for referral tracking e.g. google * should be excluded to maximise cache hits * <li>Additional parameters can be added to any page. The page will still * work but will miss the cache. Consider coding defensively around this * issue. * </ul> * <p/> * Implementers should differentiate between GET and HEAD requests otherwise * blank pages can result. See SimplePageCachingFilter for an example * implementation. * * @param httpRequest * @return the key, generally the URL plus request parameters */ protected abstract String calculateKey(final HttpServletRequest httpRequest);
3.SimplePageCachingFilter的处理
public class SimplePageCachingFilter extends CachingFilter {
public static final String DEFAULT_CACHE_NAME = "SimplePageCachingFilter"; private static final Logger LOG = LoggerFactory.getLogger(SimplePageCachingFilter.class); protected String getCacheName() { if (cacheName != null && cacheName.length() > 0) { LOG.debug("Using configured cacheName of {}.", cacheName); return cacheName; } else { LOG.debug("No cacheName configured. Using default of {}.", DEFAULT_CACHE_NAME); return DEFAULT_CACHE_NAME; } } protected CacheManager getCacheManager() { return CacheManager.getInstance(); } protected String calculateKey(HttpServletRequest httpRequest) { StringBuffer stringBuffer = new StringBuffer(); stringBuffer.append(httpRequest.getMethod()).append(httpRequest.getRequestURI()).append(httpRequest.getQueryString()); String key = stringBuffer.toString(); return key; } }
而SimpleCachingHeadersPageCachingFilter的处理
public class SimpleCachingHeadersPageCachingFilter extends SimplePageCachingFilter{
@Override protected PageInfo buildPage(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws AlreadyGzippedException, Exception { PageInfo pageInfo = super.buildPage(request, response, chain); final List<Header<? extends Serializable>> headers = pageInfo.getHeaders(); long ttlMilliseconds = calculateTimeToLiveMilliseconds(); //Remove any conflicting headers for (final Iterator<Header<? extends Serializable>> headerItr = headers.iterator(); headerItr.hasNext();) { final Header<? extends Serializable> header = headerItr.next(); final String name = header.getName(); if ("Last-Modified".equalsIgnoreCase(name) || "Expires".equalsIgnoreCase(name) || "Cache-Control".equalsIgnoreCase(name) || "ETag".equalsIgnoreCase(name)) { headerItr.remove(); } } //add expires and last-modified headers //trim the milliseconds off the value since the header is only accurate down to the second long lastModified = pageInfo.getCreated().getTime(); lastModified = TimeUnit.MILLISECONDS.toSeconds(lastModified); lastModified = TimeUnit.SECONDS.toMillis(lastModified); headers.add(new Header<Long>("Last-Modified", lastModified)); headers.add(new Header<Long>("Expires", System.currentTimeMillis() + ttlMilliseconds)); headers.add(new Header<String>("Cache-Control", "max-age=" + ttlMilliseconds / MILLISECONDS_PER_SECOND)); headers.add(new Header<String>("ETag", generateEtag(ttlMilliseconds))); return pageInfo; } @Override protected void writeResponse(HttpServletRequest request, HttpServletResponse response, PageInfo pageInfo) throws IOException, DataFormatException, ResponseHeadersNotModifiableException { final List<Header<? extends Serializable>> headers = pageInfo.getHeaders(); for (final Header<? extends Serializable> header : headers) { if ("ETag".equals(header.getName())) { String requestIfNoneMatch = request.getHeader("If-None-Match"); if (header.getValue().equals(requestIfNoneMatch)) { response.sendError(HttpServletResponse.SC_NOT_MODIFIED); // use the same date we sent when we created the ETag the first time through //response.setHeader("Last-Modified", request.getHeader("If-Modified-Since")); return; } break; } if ("Last-Modified".equals(header.getName())) { long requestIfModifiedSince = request.getDateHeader("If-Modified-Since"); if (requestIfModifiedSince != -1) { final Date requestDate = new Date(requestIfModifiedSince); final Date pageInfoDate; switch (header.getType()) { case STRING: pageInfoDate = this.getHttpDateFormatter().parseDateFromHttpDate((String)header.getValue()); break; case DATE: pageInfoDate = new Date((Long)header.getValue()); break; default: throw new IllegalArgumentException("Header " + header + " is not supported as type: " + header.getType()); } if (!requestDate.before(pageInfoDate)) { response.sendError(HttpServletResponse.SC_NOT_MODIFIED); response.setHeader("Last-Modified", request.getHeader("If-Modified-Since")); return; } } } } super.writeResponse(request, response, pageInfo); } }
这个类对于缓存的内容的头信息 Last-Modified Expires Cache-Control ETag删除,替换成当前encache里面的系统信息,输出的时候也输出encache处理过的头信息,这样我们就不管浏览器的缓存处理了,只能等待encache的缓存过期。
4.PageFragmentCachingFilter的简单处理
protected PageInfo buildPage(final HttpServletRequest request, final HttpServletResponse response,
final FilterChain chain) throws AlreadyGzippedException, Exception { // Invoke the next entity in the chain final ByteArrayOutputStream outstr = new ByteArrayOutputStream(); final GenericResponseWrapper wrapper = new GenericResponseWrapper(response, outstr); chain.doFilter(request, wrapper); wrapper.flush(); long timeToLiveSeconds = blockingCache.getCacheConfiguration().getTimeToLiveSeconds(); // Return the page info return new PageInfo(wrapper.getStatus(), wrapper.getContentType(), wrapper.getCookies(), outstr.toByteArray(), false, timeToLiveSeconds, wrapper.getAllHeaders()); //其中第五个参数false表示不存储gzip过的信息 } /** * Assembles a response from a cached page include. * These responses are never gzipped * The content length should not be set in the response, because it is a fragment of a page. * Don't write any headers at all. */ //也不处理gzip过的信息 protected void writeResponse(final HttpServletResponse response, final PageInfo pageInfo) throws IOException { // Write the page final byte[] cachedPage = pageInfo.getUngzippedBody(); //needed to support multilingual final String page = new String(cachedPage, response.getCharacterEncoding()); String implementationVendor = response.getClass().getPackage().getImplementationVendor(); if (implementationVendor != null && implementationVendor.equals("\"Evermind\"")) { response.getOutputStream().print(page); } else { response.getWriter().write(page); } }
5.PageInfo缓存对象的几个要点
public class PageInfo implements Serializable {
private static final long serialVersionUID = 1L; private static final Logger LOG = LoggerFactory.getLogger(PageInfo.class); private static final int FOUR_KB = 4196; private static final int GZIP_MAGIC_NUMBER_BYTE_1 = 31; private static final int GZIP_MAGIC_NUMBER_BYTE_2 = -117; private static final long ONE_YEAR_IN_SECONDS = 60 * 60 * 24 * 365; //存储的信息包括状态码,contentType,cookie,body,是否gzip过,过期时间,headers等信息 public PageInfo(final int statusCode, final String contentType, final Collection cookies, final byte[] body, boolean storeGzipped, long timeToLiveSeconds, final Collection<Header<? extends Serializable>> headers) throws AlreadyGzippedException { //Note that the ordering is switched with headers at the end to deal with the erasure issues with Java generics causing //a conflict with the deprecated PageInfo header this.init(statusCode, contentType, headers, cookies, body, storeGzipped, timeToLiveSeconds); } /** * @param ungzipped the bytes to be gzipped * @return gzipped bytes */ //提供的gzip处理方法 private byte[] gzip(byte[] ungzipped) throws IOException, AlreadyGzippedException { if (isGzipped(ungzipped)) { throw new AlreadyGzippedException("The byte[] is already gzipped. It should not be gzipped again."); } final ByteArrayOutputStream bytes = new ByteArrayOutputStream(); final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(bytes); gzipOutputStream.write(ungzipped); gzipOutputStream.close(); return bytes.toByteArray(); } private byte[] ungzip(final byte[] gzipped) throws IOException { final GZIPInputStream inputStream = new GZIPInputStream(new ByteArrayInputStream(gzipped)); ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(gzipped.length); final byte[] buffer = new byte[FOUR_KB]; int bytesRead = 0; while (bytesRead != -1) { bytesRead = inputStream.read(buffer, 0, FOUR_KB); if (bytesRead != -1) { byteArrayOutputStream.write(buffer, 0, bytesRead); } } byte[] ungzipped = byteArrayOutputStream.toByteArray(); inputStream.close(); byteArrayOutputStream.close(); return ungzipped; } }
6.GzipFilter的filter,这个filter对于浏览器支持gzip的则进行gzip压缩之后输出
发表评论
-
对字符串进行验证之前先进行规范化
2013-09-17 23:18 13957对字符串进行验证之前先进行规范化 应用系统中经常对字 ... -
使用telnet连接到基于spring的应用上执行容器中的bean的任意方法
2013-08-08 09:17 1482使用telnet连接到基于spring的应用上执行容器中 ... -
jdk7和8的一些新特性介绍
2013-07-06 16:07 10113更多ppt内容请查看:htt ... -
Lucene的IndexWriter初始化时的LockObtainFailedException的解决方法
2013-06-28 21:35 11808原文链接: http://www.javaarch.net ... -
java对于接口和抽象类的代理实现,不需要有具体实现类
2013-06-12 09:50 2957原文链接:http://www.javaarch.net/j ... -
Excel2007格式分析和XML解析
2013-06-07 09:56 10744在物料清单采购中,用到excel上传文件解析功能,不 ... -
Java EE 7中对WebSocket 1.0的支持
2013-06-05 09:27 3845原文链接:http://www.javaarch.n ... -
java QRCode生成示例
2013-06-05 09:26 1514原文链接:http://www.javaarch.n ... -
Spring Security Logout
2013-06-03 00:05 2371原文地址:http://www.javaarch.net/ ... -
Spring Security Basic Authentication
2013-06-03 00:04 1741原文地址:http://www.javaarch.net/ ... -
Spring Security Form Login
2013-06-02 16:16 2149原文地址:http://www.javaarch.net/j ... -
spring3 的restful API RequestMapping介绍
2013-06-02 14:53 1155原文链接:http://www.javaarch.net/j ... -
Java Web使用swfobject调用flex图表
2013-05-28 19:05 1127Java Web使用swfobject调用 ... -
spring使用PropertyPlaceholderConfigurer扩展来满足不同环境的参数配置
2013-05-21 15:57 3341spring使用PropertyPlaceholderCon ... -
java国际化
2013-05-20 20:57 4478java国际化 本文来自:http://www.j ... -
RSS feeds with Java
2013-05-20 20:52 1225RSS feeds with Java 原文来自:htt ... -
使用ibatis将数据库从oracle迁移到mysql的几个修改点
2013-04-29 10:40 1678我们项目在公司的大战略下需要从oracle ... -
线上机器jvm dump分析脚本
2013-04-19 10:48 2911#!/bin/sh DUMP_PIDS=`p ... -
spring3学习入门示例工程
2013-04-18 09:28 11311. github地址 https://github ... -
spring map使用annotation泛型注入问题分析
2013-04-15 13:30 8547今天在整一个spring的ioc学习demo,碰到 ...
相关推荐
`EnCache`在Java社区中广受欢迎,尤其在大数据量、高并发的Web应用中扮演着关键角色。 **EnCache的基本概念:** 1. **缓存**: 缓存是一种存储技术,用于暂时存储经常访问的数据,以减少处理时间。在`EnCache`中,...
标题中的"spring-cache.xsd+spring-encache.xsd"提到了两个XML Schema定义文件,它们是Spring框架中用于缓存管理的配置规范。Spring框架是一个广泛应用的Java企业级应用开发框架,它提供了多种功能,包括但不限于...
EnCache是一个流行的选择,它为Java应用程序提供了高效、可扩展的缓存解决方案。本文将详细介绍EnCache缓存系统,以及与之相关的jar包需求。 EnCache是由Spring社区开发的一个分布式缓存系统,它支持在多个节点之间...
Ehcache,作为一款高效的Java开源缓存框架,它的广泛应用在于其灵活性和高效性。它不仅可以与Spring框架无缝集成,自Spring 3.1版本之后,通过注解配置即可便捷地使用,还能够与Hibernate ORM框架配合,成为其默认的...
**encache.web.jar** 则是针对Web应用程序的扩展,它提供了与Web应用服务器的集成,使得在Web环境中使用Ehcache更为方便。它可能包含对Servlet容器的适配器、过滤器、监听器等,以支持Web应用的缓存需求。 源码的...
总的来说,EnCache系列jar包为Java开发者提供了多样化的缓存解决方案。通过合理选择和使用encache-1.1.jar、encache-1.3.jar或encache-1.5.jar,开发者可以根据项目的具体需求,构建出高效、稳定、易维护的缓存系统...
页面静态化技术可以使用模板技术来生成静态页面,例如 Velocity 和 FreeMaker 等。 4. 数据库优化 数据库优化是指对数据库的结构和 SQL 语句进行优化,以提高网站的性能和可扩展性。常见的数据库优化方法有: * ...
使用Encache进行缓存存取的工具类,java中使用,配置好配置文件就可以使用
总的来说,"encache+jgroups集群缓存共享"是一个深度整合分布式缓存和群组通信的技术方案,它结合了EnCache的高性能缓存特性与JGroups的稳定通信能力,为大型分布式系统提供了高效、可靠的缓存解决方案。理解和掌握...
J2Cache是一个流行的Java缓存解决方案,它允许开发者将数据存储在内存中以减少对数据库的访问。在这个配置中,J2Cache结合了Caffeine作为一级缓存和Redis作为二级缓存,构建了一个高效的分布式缓存系统。 首先,让...
**EnCache** 主要是Java环境中的一种缓存框架,最初由Apache提供,后来被Adobe接手并开源。EnCache提供了缓存管理、事务处理、缓存分区等功能,支持多种缓存策略。它可以在应用程序服务器内部运行,减少了网络通信...
首先,**Struts2** 是一个基于MVC设计模式的Web应用框架,它提供了强大的Action类来处理用户请求,并通过配置文件定义了视图与动作之间的映射关系。在Struts2中,开发者可以方便地进行表单验证、拦截器的使用以及...
标题 "看透 Spring MVC 源代码分析与实践" 提示我们主要关注的是Spring MVC这一Web开发框架的源代码分析和实际应用。Spring MVC是Spring框架的一个模块,它提供了处理HTTP请求、响应以及数据绑定等功能,是构建Web...
在Spring框架中,Ehcache可以与Spring Cache模块集成,方便地在项目中启用缓存功能。 这四个框架的整合使用,能够构建出一套完整的JavaWeb后台解决方案。Spring作为基础框架,提供整体的管理和服务;Spring MVC处理...
EhCache是一个开源的、高性能的Java缓存框架,它被广泛用于提高应用程序的性能,减少数据库负载。在这个“ehcache缓存入门项目”中,我们将深入探讨EhCache的基本概念、配置、使用方法以及一些实用技巧。 1. **...
例如,你可以使用`CacheManager.create()`初始化缓存管理器,并调用`getCache()`获取或创建缓存实例。 ```java CacheManager cacheManager = CacheManager.create(); Cache cache = cacheManager.getCache("myCache...
Spring MVC 是一个强大的Java Web开发框架,用于构建高效、可维护的Web应用程序。它与Ehcache和MySQL的集成,可以极大地提升应用的性能和用户体验。在这个项目中,Ehcache作为缓存机制,用于存储频繁访问的数据,以...
总结来说,Ehcache与Spring的结合提供了强大的缓存解决方案,可以显著提升Java应用的性能。通过注解驱动的缓存管理,开发者可以轻松地在代码中实现缓存策略,而无需深入底层细节。结合Spring的其他模块,如Web和ORM...
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 是一款广泛应用于Java开发中的开源缓存框架,其高效、易用且功能强大的特点使其在处理大量数据快速访问的问题上表现出色。本文将详细介绍Ehcache的基础知识、配置以及如何在实际项目中应用。 1. **Ehcache...