实现一个java web缓存

默认情况下,java并不完成缓存。要安装URL类使用的系统级缓存,需要由:
ResponseCache的一个具体子类。
CacheRequest的一个具体子类。
CacheResponse的一个具体子类。
要安装你的ResponseCache子类来处理你的CacheRequest子类和CacheResponse子类,需要把它传递到静态放ResponseCache.setDefault()。这会把这个缓存对象安装为系统的默认缓存。Java虚拟机只支持一个共享缓存。
一旦安装了缓存,只要系统尝试加载一个新的URL,它手下会在缓存中查找。如果缓存返回了所要的内容,URLConnecton就不需要与远程服务器连接。不过,如果所请求的数据不在缓存中,协议处理器将从远程服务器下载相应数据。完成之后,它会把这个响应放在缓存中,使得下一次加载这个URL时,可以很快从缓存中得到这个内容。
ResponseCache提供了两个抽象方法,可以存储和获取系统缓存中的数据:
public abtract CacheResponse get(URI uri, String requestMethod, Map<String,List<String>> requestHeaders ) throws IOException
public abtract CacheResponse put(URI uri, URLConnection connection) throws IOException
put()方法返回一个CacheResponse 对象,它包装了一个OutputStream,URL将把读取的可缓存数据写入这个输入流。

get()方法从缓存中获取数据和首部,包装在CacheResponse对象中返回           

package cache;

import java.util.Date;
import java.util.Locale;

//缓存参数类
public class CacheControl {

	private Date maxAge = null; //从现在知道缓存项过期前的秒数
	private Date sMaxAge = null; //从现在起,直到缓存项在共享缓存中过期之前的秒数
	private boolean mustRevalidate = false; //
	private boolean noCache = false; //这个策略的作用与名字不太一致。缓存 项任然可以缓存,不过客户端在每次访问时要用一个Etag或者Last-modified首部重新验证响应的状态
	private boolean noStore = false;//不管怎么样都不缓存
	private boolean proxyRevalidate = false; 
	private boolean publicCache = false; //可以缓存一个经过认证的响应
	private boolean privateCache = false;//仅单个用户缓存可以保存响应
	
	public CacheControl(String s){
		if(s == null || !s.contains(":")){
			return;
		}
		
		String value = s.split(":")[1].trim();
		String[] components = value.split(",");
		
		Date now = new Date();
		for(String component : components){
			try{
				component = component.trim().toLowerCase(Locale.US);
				if(component.startsWith("max-age=")){
					int secondsInTheFuture = Integer.parseInt(component.substring(8));
					maxAge = new Date(now.getTime() + 1000 * secondsInTheFuture);
				}else if(component.startsWith("s-maxage=")){
					int secondsInTheFuture = Integer.parseInt(component.substring(8));
					maxAge = new Date(now.getTime() + 1000 * secondsInTheFuture);
				}else if(component.equals("must-revalidate")){
					mustRevalidate = true;
				}else if(component.equals("proxy-revalidate")){
					proxyRevalidate = true;
				}else if(component.equals("no-cache")){
					noCache = true;
				}else if(component.equals("public")){
					publicCache = true;
				}else if(component.equals("private")){
					privateCache = true;
				}
			}catch(RuntimeException ex){
				continue;
			}
			
			
		}
	}

	public Date getMaxAge() {
		return maxAge;
	}

	public Date getsMaxAge() {
		return sMaxAge;
	}

	public boolean isMustRevalidate() {
		return mustRevalidate;
	}

	public boolean isNoCache() {
		return noCache;
	}

	public boolean isNoStore() {
		return noStore;
	}

	public boolean isProxyRevalidate() {
		return proxyRevalidate;
	}

	public boolean isPublicCache() {
		return publicCache;
	}

	public boolean isPrivateCache() {
		return privateCache;
	}
}

package cache;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.net.CacheRequest;

public class MyCacheRequest extends CacheRequest{

	private ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
	
	//返回从协议处理器获得的输出流
	@Override
	public OutputStream getBody() throws IOException {
		return outputStream;
	}

	//当协议处理器把从服务器读取的数据复制到OutputStream时发生意外中断,协议处理器就调用该方法删除缓存中这个请求的所有数据
	@Override
	public void abort() {
		outputStream.reset();
	}
	
	//返回请求的数据
	public byte[] getData(){
		if(outputStream.size() == 0){
			return null;
		}else{
			return outputStream.toByteArray();
		}
	}

}


package cache;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.CacheResponse;
import java.net.URLConnection;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.Map;

import java7_URLConnection.CacheControl;

public class MyCacheResponse extends CacheResponse{
	private MyCacheRequest myCacheRequest = null;//请求的数据
	private Map<String,List<String>> headers = null;//请求的数据的首部信息
	private CacheControl control;//请求的数据的缓存策略
	private Date expires;//请求的数据的过期时间
	
	public MyCacheResponse(MyCacheRequest myCacheRequest, URLConnection conn,
			Map<String,List<String>> headers,CacheControl control){
		this.headers = headers;//获取所有首部信息的键值对形式
		this.myCacheRequest = myCacheRequest;
		this.control = control;
		this.expires = new Date(conn.getExpiration());
	}

	@Override
	public Map<String, List<String>> getHeaders() throws IOException {
		return headers;
	}

	@Override
	public InputStream getBody() throws IOException {
		return new ByteArrayInputStream(myCacheRequest.getData());
	}
	
	//返回缓存的数据协议信息
	public CacheControl getControl() {
		return control;
	}
	
	//缓存是否过期
	public boolean isExpires(){
		Date now = new Date();
		if(control.getMaxAge().before(now)){
			return true;
		}else if(expires != null && control.getMaxAge() != null){
			return expires.before(now);
		}else{
			return false;
		}
	}

}


package cache;

import java.io.IOException;
import java.net.CacheRequest;
import java.net.CacheResponse;
import java.net.ResponseCache;
import java.net.URI;
import java.net.URLConnection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import java7_URLConnection.CacheControl;

public class MyResponseCache extends ResponseCache{
	//维护一个Map用以缓存所有的URI请求
	private Map<URI,MyCacheResponse> responses = new ConcurrentHashMap<URI, MyCacheResponse>();
	private int maxEntries;
	
	public MyResponseCache(){
		this(100);
	}
	
	public MyResponseCache(int maxEntries){
		this.maxEntries = maxEntries;
	}

	@Override
	public CacheResponse get(URI uri, String rqstMethod,
			Map<String, List<String>> rqstHeaders) throws IOException {
		if("GET".equals(rqstMethod)){
			MyCacheResponse responseCache = responses.get(uri);
			//检查过期时间
			if(responseCache != null && responseCache.isExpires()){
				responses.remove(uri);
				responseCache = null;
			}
			return responseCache;
		}else{
			return null;
		}
	}

	@Override
	public CacheRequest put(URI uri, URLConnection conn) throws IOException {
		CacheControl control = new CacheControl(conn.getHeaderField("Cache-Control"));
		//如果需要缓存的uri超过100则不允许缓存
		if(responses.size() >= maxEntries){
			return null;
		}
		//判断是否需要缓存
		if(control.isNoStore()){
			return null;
		}else if(!conn.getHeaderField(0).startsWith("GET")){//只缓存get请求
			return null;
		}
		
		//从服务器中读取需要缓存的信息
		MyCacheRequest cacheRequest = new MyCacheRequest();
		//将信息保存到MyCacheResponse中,请求的数据,请求头,缓存策略
		MyCacheResponse cacheResponse = new MyCacheResponse(cacheRequest, conn,
				Collections.unmodifiableMap(conn.getHeaderFields()), control);
		//缓存该信息
		responses.put(uri, cacheResponse);
		return cacheRequest;
	}

}



java要求一次只能有一个URL缓存。要安装或改变缓存,需要使用静态方法ResponseCache.setDefault()和ResponseCache.getDefault():
public static ResponseCache getDefault()
public static void setDefault(ResponseCache responseCache )
这些方法会在设置同一个java虚拟机中运行的所有程序所使用的缓存。例如,在下面这行代码中会在应用中安装:
ResponseCache.getDefault(new MyResponseCache):
一旦安装了类似示例的缓存,HTTP URLConnection就会一直使用这个缓存。
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值