前言
享元模式(Flyweight Pattern),以共享的方式高效的支持大量的细粒度对象,通过复用内存中已经存在的对象,降低系统创建对象实例的性能损耗。在某些特殊情况下,大量细粒度对象的创建,销毁及存储所造成的资源和性能上的损耗,可能会在系统运行时形成瓶颈,这时我们就可以采用享元模式的思想来解决此类问题。在享元模式中,享元对象是有状态的,分为两种:内蕴状态(Internal State)和外蕴状态(External State);其中,内蕴状态是不变的,而外蕴状态则是变化的。
场景案例
这里列举几个自己使用到的场景案例,主要列举两个,分别如下:
select控件下拉列表,当展示的数据量非常大,在不考虑分页展示的情况下,会导致下拉列表非常长且页面渲染非常慢。问题原因是浏览器端要瞬间初始化并渲染大量的option项;优化方案:当下拉列表展示的数据量大时是有滚动条的,这样其实我们只需创建很少的个option对象实例(比如20),当滚动条拖动的时候,动态的修改option实例的外蕴状态(即显示的数据,内蕴状态则是option的样式是不变的)即可!,从而达到option实例复用的效果。
web开发,一般都喜欢通过ThreadLocal在当前请求的线程上下文中放入请求的Request和Response等,从而实现Request,Response等实例信息的隐式传递。(strut2就是这么搞的),那么这个线程上下文ThreadContext实例,是每次请求进来都创建呢?还是采用享元模式的思想复用该对象?,jvm 频繁gc可是影响耗性能的。
示例代码
针对场景案例2实现的线程上下文管理器示例代码:/** 享元对象:线程上下文 */
public class ThreadContext implements Serializable {
private static final long serialVersionUID = 1L;
private Map<String, Object> data = null;
private HttpServletRequest request = null;
private HttpServletResponse response = null;
public ThreadContext() {
data = new HashMap<String, Object>();
}
public Map<String, Object> getData() {
return data;
}
public void setData(Map<String, Object> data) {
this.data = data;
}
public HttpServletRequest getRequest() {
return request;
}
public ThreadContext setRequest(HttpServletRequest request) {
this.request = request;
return this;
}
public HttpServletResponse getResponse() {
return response;
}
public ThreadContext setResponse(HttpServletResponse response) {
this.response = response;
return this;
}
public Object getValue(String key) {
return data.get(key);
}
public ThreadContext setValue(String key, Object value) {
if (StringUtils.isEmpty(key)) { throw new IllegalArgumentException("key is blank"); }
data.put(key, value);
return this;
}
public HttpSession getSession() {
return request.getSession();
}
// 清除享元对象的外蕴状态
public void clear() {
data.clear();
request = null;
response = null;
}
}
/** 享元对象管理器:线程上下文管理器 */
public class ThreadContextManager {
private static ThreadLocal<ThreadContext> contextMap = new ThreadLocal<ThreadContext>();
/** 从当前线程中获取上下文context*/
public static ThreadContext getThreadContext() {
return contextMap.get();
}
/** 获取初始化的线程上下文*/
public static ThreadContext getInitThreadContext() {
ThreadContext threadContext = contextMap.get();
// 享元模式:达到对对象的复用,降低对象的创建及销毁所带来的开销
if (threadContext != null) {
threadContext.clear();// 清除对象的外蕴状态
} else {
// 优先从当前线程取,如果设置过则复用该对象,没有则创建
threadContext = new ThreadContext();
contextMap.set(threadContext);
}
return threadContext;
}
}
// client 测试:
// 功能描述:框架级过滤器
public class ApplicationFilter implements Filter {
public void init(FilterConfig filterConfig) throws ServletException {
}
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException,
ServletException {
// 设置线程上下文并重新设置该对象的外蕴状态
ThreadContextManager.getInitThreadContext().setRequest((HttpServletRequest) request)
.setResponse((HttpServletResponse) response);
chain.doFilter(request, response);
}
public void destroy() {
}
}