本文是《轻量级 Java Web 框架架构设计》的系列博文。
目前在 Smart 中实现一个 Service,也许您会这样写:
@Bean
public class CustomerServiceImpl extends BaseService implements CustomerService {
@Override
public List<Customer> getCustomerList() {
return DataSet.selectList(Customer.class, null, null);
}
@Override
public boolean deleteCustomer(long id) {
return DataSet.delete(Customer.class, "id = ?", id);
}
@Override
public Customer getCustomer(long id) {
return DataSet.select(Customer.class, "id = ?", id);
}
@Override
public boolean updateCustomer(long id, Map<String, Object> fieldMap) {
return DataSet.update(Customer.class, fieldMap, "id = ?", id);
}
@Override
public boolean createCustomer(Map<String, Object> fieldMap) {
return DataSet.insert(Customer.class, fieldMap);
}
}
上面这个实现类,完成了简单的 CRUD 操作,每个方法中都调用了 DataSet API 来实现。
当然,这只是一个简单的示例,却能够反映出一个非常明显的问题 —— 性能!
因为每次调用 DataSet 其实底层都进行了数据库操作,众所周知,数据库操作是一种 I/O 操作,而 I/O 操作往往却是整个应用的性能瓶颈之一。
那么如何来提高性能呢?首先能够想到的就是减少 I/O 访问,也就是这里提到的数据库访问了。
那么怎样才能减小数据库访问呢?使用 Cache 或许是一种很好的选择吧。
大家熟知的 Cache 开源项目,例如:Ehcache、OScache 等,或者还有一些分布式 Cache,例如:Memcached、Redis 等。这些都是一些很好的解决方案,Smart 当然不会排斥这些方案,只要我们通过 Plugin 的方式,满足一定的开发规范,即可编写 Smart Plugin。
Smart Plugin 其实说白了没什么高深的东西,只要您会用 Maven,就可以开发。但您必须要满足以下规范:
- 包名统一为:com.smart.plugin.xxx,其中 xxx 表示 Plugin 的名称。
- Maven 的 Group ID 为 com.smart.plugin,并且 Artifact ID 为 smart-xxx。
- 依赖于 smart-framework,即 Smart 框架。
好!我们下面就开发一个简单的 Smart Cache Plugin,让它来提升以上示例中所遇到的性能问题。
第一步:定义一个 Cache 接口
public interface Cache<K, V> {
// 从 Cache 中获取数据
V get(K key);
// 将数据放入 Cache 中
void put(K key, V value);
// 从 Cache 中移除数据
boolean remove(K key);
// 清空 Cache
void clear();
}
在 Cache 接口中提供一系列对 Cache 的常用操作,请参见方法上的代码注释。
第二步:定义一个 CacheManager 接口。
public interface CacheManager {
// 创建 Cache
void createCache(String cacheName);
// 获取 Cache
<K, V> Cache<K, V> getCache(String cacheName);
// 获取所有 Cache 名
Iterable<String> getCacheNames();
// 销毁指定 Cache
void destroyCache(String cacheName);
// 销毁所有 Cache
void destroyCacheAll();
}
CacheManager 接口可对外提供 Cache,并对 Cache 的生命周期进行管理。
第三步:定义一个 CacheException 类
public class CacheException extends RuntimeException {
public CacheException() {
super();
}
public CacheException(String message) {
super(message);
}
public CacheException(String message, Throwable cause) {
super(message, cause);
}
public CacheException(Throwable cause) {
super(cause);
}
}
CacheException 只是一个简单的 RuntimeException,在以上接口的相关实现类中会使用该异常类。
第四步:实现 Cache 接口public class DefaultCache<K, V> implements Cache<K, V> {
// 定义一个 Data Map,用于存放该 Cache 中所有的数据
private final Map<K, V> dataMap = new ConcurrentHashMap<K, V>();
@Override
public V get(K key) {
if (key == null) {
throw new NullPointerException("错误:参数 key 不能为空!");
}
return dataMap.get(key);
}
@Override
public void put(K key, V value) {
if (key == null) {
throw new NullPointerException("错误:参数 key 不能为空!");
}
if (value == null) {
throw new NullPointerException("错误:参数 value 不能为空!");
}
dataMap.put(key, value);
}
@Override
public boolean remove(K key) {
if (key == null) {
throw new NullPointerException("错误:参数 key 不能为空!");
}
return dataMap.remove(key) != null;
}
@Override
public void clear() {
dataMap.clear();
}
}
在 Cache 中最核心的就是一个 Map,而且这个 Map 是具备并发控制的,为了保证线程之间的共享互斥,所以用到了 JDK 1.5 中的 java.util.concurrent.ConcurrentHashMap。
第五步:实现 CacheManager 接口
public class DefaultCacheManager implements CacheManager {
// 定义一个 Cache Map,用于存放该 Cache Manager 中所有的 Cache
private final Map<String, Cache> cacheMap = new ConcurrentHashMap<String, Cache>();
// 构造 Cache Manager,可同时创建若干 Cache
public DefaultCacheManager(String... cacheNames) {
if (cacheNames == null) {
throw new NullPointerException("错误:参数 cacheNames 不能为空!");
}
for (String cacheName : cacheNames) {
createCache(cacheName);
}
}
@Override
public void createCache(String cacheName) {
if (cacheName == null) {
throw new NullPointerException("错误:参数 cacheName 不能为空!");
}
if (cacheMap.containsKey(cacheName)) {
throw new CacheException("错误:同名的 Cache 已存在,无法创建!");
}
Cache cache = new DefaultCache();
cacheMap.put(cacheName, cache);
}
@Override
@SuppressWarnings("unchecked")
public <K, V> Cache<K, V> getCache(String cacheName) {
if (cacheName == null) {
throw new NullPointerException("错误:参数 cacheName 不能为空!");
}
return cacheMap.get(cacheName);
}
@Override
public Iterable<String> getCacheNames() {
return cacheMap.keySet();
}
@Override
public void destroyCache(String cacheName) {
if (cacheName == null) {
throw new NullPointerException("错误:参数 cacheName 不能为空!");
}
Cache cache = getCache(cacheName);
if (cache != null) {
cache.clear();
}
}
@Override
public void destroyCacheAll() {
for (String cacheName : getCacheNames()) {
destroyCache(cacheName);
}
}
}
同样用一个 ConcurrentHashMap 管理所有的 Cache,通过一个 cacheName 作为 Map 的 key,Cache 实例是 Map 的 value。
第六步:使用 Cache
@Bean
public class CustomerServiceCacheImpl extends BaseService implements CustomerService {
private final CacheManager cacheManager;
private final Cache<String, List<Customer>> customerListCache;
private final Cache<Long, Customer> customerCache;
public CustomerServiceCacheImpl() {
cacheManager = new DefaultCacheManager("customer_list_cache", "customer_cache");
customerListCache = cacheManager.getCache("customer_list_cache");
customerCache = cacheManager.getCache("customer_cache");
}
@Override
public List<Customer> getCustomerList() {
List<Customer> customerList = customerListCache.get("customer_list");
if (customerList == null) {
customerList = DataSet.selectList(Customer.class, null, null);
if (CollectionUtil.isNotEmpty(customerList)) {
customerListCache.put("customer_list", customerList);
}
}
return customerList;
}
@Override
public boolean deleteCustomer(long id) {
boolean result = DataSet.delete(Customer.class, "id = ?", id);
if (result) {
customerListCache.clear();
customerCache.remove(id);
}
return result;
}
@Override
public Customer getCustomer(long id) {
Customer customer = customerCache.get(id);
if (customer == null) {
customer = DataSet.select(Customer.class, "id = ?", id);
if (customer != null) {
customerCache.put(id, customer);
}
}
return customer;
}
@Override
public boolean updateCustomer(long id, Map<String, Object> fieldMap) {
boolean result = DataSet.update(Customer.class, fieldMap, "id = ?", id);
if (result) {
cacheManager.destroyCacheAll();
}
return result;
}
@Override
public boolean createCustomer(Map<String, Object> fieldMap) {
boolean result = DataSet.insert(Customer.class, fieldMap);
if (result) {
cacheManager.destroyCacheAll();
}
return result;
}
}
在 CustomerServiceCacheImpl 中,创建了一个 cacheManager,通过它可创建 customerListCache 与 customerCache 这两个 Cache,推荐在构造器中创建所有成员变量,当然也可以直接在成员变量定义的同时进行创建。
在业务方法中,使用了 Cache 接口,当需要获取数据时,首先可从 Cache 中获取,如果有就直接返回,如果没有就从数据库中获取,获取过后再将结果放入 Cache 中。此外,当数据有更新时,可移除或销毁 Cache。
当然,这只是一个简单的 Cache 实现,并非完备,也并非优雅。所以剩下的就需要大家多提提建议了,如何去让它变得更好。
期待您的留言!
来源:oschina
链接:https://my.oschina.net/u/223750/blog/173260