项目的缓存设计主要是这样的,监听数据库中表的改变,如果会发生变动,则对缓存做一些处理,具体实现如下:
(2)缓存监听、管理类设计
以上是缓存设计的核心代码,如果要实现用户的缓存管理需要创建用户缓存管理类,并实现CacheDeal接口:
(1)缓存支持类(实体、辅助类等)的设计
实体缓存注释类 NeedCache
- <SPAN style="FONT-SIZE: 14px">/**
- * 缓存的注释类,如果需要缓存某个类,请在类上添加此注释类,并给出cache的处理类
- *
- * @author liuyang
- *
- */
- @Documented
- @Target(value = ElementType.TYPE)
- @Retention(RetentionPolicy.RUNTIME)
- public @interface NeedCache {
- Class<?> cacheDealClass();
- }</SPAN>
/**
* 缓存的注释类,如果需要缓存某个类,请在类上添加此注释类,并给出cache的处理类
*
* @author liuyang
*
*/
@Documented
@Target(value = ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface NeedCache {
Class<?> cacheDealClass();
}
缓存类 Cache
- <SPAN style="FONT-SIZE: 14px">/**
- * 对象缓存类
- *
- * @author liuyang
- *
- */
- public class Cache {
- private String key;
- private Map<String,String> fieldHashMap;
- private int expiredSeconds;
- private long expiredTime;
- /**
- * 键
- *
- * @return
- */
- public String getKey() {
- return key;
- }
- public void setKey(String key) {
- this.key = key;
- }
- /**
- * 缓存的对象map
- * @return
- */
- public Map<String, String> getFieldHashMap() {
- return fieldHashMap;
- }
- public void setFieldHashMap(Map<String, String> fieldHashMap) {
- this.fieldHashMap = fieldHashMap;
- }
- /**
- * 过期秒数
- *
- * @return
- */
- public int getExpiredSeconds() {
- return expiredSeconds;
- }
- public void setExpiredSeconds(int expiredSeconds) {
- this.expiredSeconds = expiredSeconds;
- }
- /**
- * 过期时间
- *
- * @return
- */
- public long getExpiredTime() {
- return expiredTime;
- }
- public void setExpiredTime(long expiredTime) {
- this.expiredTime = expiredTime;
- }
- }</SPAN>
/**
* 对象缓存类
*
* @author liuyang
*
*/
public class Cache {
private String key;
private Map<String,String> fieldHashMap;
private int expiredSeconds;
private long expiredTime;
/**
* 键
*
* @return
*/
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
/**
* 缓存的对象map
* @return
*/
public Map<String, String> getFieldHashMap() {
return fieldHashMap;
}
public void setFieldHashMap(Map<String, String> fieldHashMap) {
this.fieldHashMap = fieldHashMap;
}
/**
* 过期秒数
*
* @return
*/
public int getExpiredSeconds() {
return expiredSeconds;
}
public void setExpiredSeconds(int expiredSeconds) {
this.expiredSeconds = expiredSeconds;
}
/**
* 过期时间
*
* @return
*/
public long getExpiredTime() {
return expiredTime;
}
public void setExpiredTime(long expiredTime) {
this.expiredTime = expiredTime;
}
}
缓存处理接口类 CacheDeal
- <SPAN style="FONT-SIZE: 14px">/**
- * 缓存处理接口
- *
- * @author liuyang
- *
- */
- public interface CacheDeal {
- /**
- * 添加缓存
- *
- * @param cachedEntity
- */
- void addCache(Object cachedEntity);
- /**
- * 移除缓存
- *
- * @param cachedEntity
- */
- void removeCache(Object cachedEntity);
- /**
- * 更新缓存
- *
- * @param cachedEntity
- */
- void updateCache(Object cachedEntity);
- /**
- * 获取缓存
- *
- * @param key
- * @return
- */
- Cache getCache(String key);
- }</SPAN>
/**
* 缓存处理接口
*
* @author liuyang
*
*/
public interface CacheDeal {
/**
* 添加缓存
*
* @param cachedEntity
*/
void addCache(Object cachedEntity);
/**
* 移除缓存
*
* @param cachedEntity
*/
void removeCache(Object cachedEntity);
/**
* 更新缓存
*
* @param cachedEntity
*/
void updateCache(Object cachedEntity);
/**
* 获取缓存
*
* @param key
* @return
*/
Cache getCache(String key);
}
(2)缓存监听、管理类设计
这里用了hibernate的监听类,创建3个监听类,插入、修改、删除分别继承Ejb3PostInsertEventListener,Ejb3PostUpdateEventListener,Ejb3DeleteInsertEventListener,srping配置文件如下配置:
- <SPAN style="FONT-SIZE: 14px"><!-- Jpa Entity Manager 配置 -->
- <bean id="entityManagerFactory"
- class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
- <property name="dataSource" ref="dataSource" />
- <property name="persistenceUnitName" value="defaultPU" />
- <property name="persistenceUnitManager" ref="persistenceUnitManager"/>
- <property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
- <property name="jpaProperties">
- <props>
- <prop key="hibernate.dialect">${hibernate.dialect}</prop>
- <prop key="hibernate.show_sql">false</prop>
- <prop key="hibernate.format_sql">false</prop>
- <prop key="hibernate.hbm2ddl.auto">update</prop>
- <prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
- <prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.impl.FSDirectoryProvider</prop>
- <prop key="hibernate.search.default.indexBase">./build/indexes</prop>
- <prop key="hibernate.search.lucene_version">LUCENE_35</prop>
- <!-- for hibernate ejb event -->
- <prop key="hibernate.ejb.event.post-insert">
- com.liuyang.infrastructure.cache.listener.ejb.PostInsertEventListener
- </prop>
- <prop key="hibernate.ejb.event.post-update">
- com.liuyang.infrastructure.cache.listener.ejb.PostUpdateEventListener
- </prop>
- <prop key="hibernate.ejb.event.post-delete">
- com.liuyang.infrastructure.cache.listener.ejb.PostDeleteEventListener
- </prop>
- </props>
- </property>
- </bean></SPAN>
<!-- Jpa Entity Manager 配置 -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="defaultPU" />
<property name="persistenceUnitManager" ref="persistenceUnitManager"/>
<property name="jpaVendorAdapter" ref="hibernateJpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.ejb.naming_strategy">org.hibernate.cfg.ImprovedNamingStrategy</prop>
<prop key="hibernate.search.default.directory_provider">org.hibernate.search.store.impl.FSDirectoryProvider</prop>
<prop key="hibernate.search.default.indexBase">./build/indexes</prop>
<prop key="hibernate.search.lucene_version">LUCENE_35</prop>
<!-- for hibernate ejb event -->
<prop key="hibernate.ejb.event.post-insert">
com.liuyang.infrastructure.cache.listener.ejb.PostInsertEventListener
</prop>
<prop key="hibernate.ejb.event.post-update">
com.liuyang.infrastructure.cache.listener.ejb.PostUpdateEventListener
</prop>
<prop key="hibernate.ejb.event.post-delete">
com.liuyang.infrastructure.cache.listener.ejb.PostDeleteEventListener
</prop>
</props>
</property>
</bean>
缓存管理类
- public class CacheManager {
- private static CacheManager instance = null;
- private static CacheDeal cacheDeal = null;
- private static Object cachedEntity = null;
- private CacheManager() {
- }
- public static CacheManager getNewInstance(Object cachedEntity) {
- CacheManager.cacheDeal = getCacheDealObject(cachedEntity.getClass());
- CacheManager.cachedEntity = cachedEntity;
- if (instance == null)
- synchronized (CacheManager.class) {
- if (instance == null) {
- instance = new CacheManager();
- }
- }
- return instance;
- }
- public void addCache() {
- if (isNull())
- return;
- cacheDeal.addCache(cachedEntity);
- }
- public void removeCache() {
- if (isNull())
- return;
- cacheDeal.removeCache(cachedEntity);
- }
- public void updateCache() {
- if (isNull())
- return;
- cacheDeal.updateCache(cachedEntity);
- }
- public Cache getCache(String key) {
- if (isNull())
- return null;
- return cacheDeal.getCache(key);
- }
- private boolean isNull() {
- return cacheDeal == null || cachedEntity == null;
- }
- private static CacheDeal getCacheDealObject(Class<?> cachedClazz) {
- CacheDeal cacheDealObject = null;
- try {
- boolean hasNeedCacheAnnotation = cachedClazz
- .isAnnotationPresent(NeedCache.class);
- if (hasNeedCacheAnnotation) {
- NeedCache needCache = cachedClazz
- .getAnnotation(NeedCache.class);
- cacheDealObject = (CacheDeal) SpringContextHolder
- .getBean(needCache.cacheDealClass());
- }
- } catch (Exception e) {
- LoggerUtil.error(CacheManager.class, cachedClazz + "获取缓存处理类失败", e);
- }
- return cacheDealObject;
- }
- }
public class CacheManager {
private static CacheManager instance = null;
private static CacheDeal cacheDeal = null;
private static Object cachedEntity = null;
private CacheManager() {
}
public static CacheManager getNewInstance(Object cachedEntity) {
CacheManager.cacheDeal = getCacheDealObject(cachedEntity.getClass());
CacheManager.cachedEntity = cachedEntity;
if (instance == null)
synchronized (CacheManager.class) {
if (instance == null) {
instance = new CacheManager();
}
}
return instance;
}
public void addCache() {
if (isNull())
return;
cacheDeal.addCache(cachedEntity);
}
public void removeCache() {
if (isNull())
return;
cacheDeal.removeCache(cachedEntity);
}
public void updateCache() {
if (isNull())
return;
cacheDeal.updateCache(cachedEntity);
}
public Cache getCache(String key) {
if (isNull())
return null;
return cacheDeal.getCache(key);
}
private boolean isNull() {
return cacheDeal == null || cachedEntity == null;
}
private static CacheDeal getCacheDealObject(Class<?> cachedClazz) {
CacheDeal cacheDealObject = null;
try {
boolean hasNeedCacheAnnotation = cachedClazz
.isAnnotationPresent(NeedCache.class);
if (hasNeedCacheAnnotation) {
NeedCache needCache = cachedClazz
.getAnnotation(NeedCache.class);
cacheDealObject = (CacheDeal) SpringContextHolder
.getBean(needCache.cacheDealClass());
}
} catch (Exception e) {
LoggerUtil.error(CacheManager.class, cachedClazz + "获取缓存处理类失败", e);
}
return cacheDealObject;
}
}
- <SPAN style="FONT-SIZE: 14px">public class PostInsertEventListener extends EJB3PostInsertEventListener{
- private static final long serialVersionUID = 7401854577429048855L;
- @Override
- public void onPostInsert(PostInsertEvent event) {
- super.onPostInsert(event);
- CacheManager cacheManager = CacheManager.getNewInstance(event.getEntity());
- cacheManager.addCache();
- }
- }
- </SPAN>
public class PostInsertEventListener extends EJB3PostInsertEventListener{
private static final long serialVersionUID = 7401854577429048855L;
@Override
public void onPostInsert(PostInsertEvent event) {
super.onPostInsert(event);
CacheManager cacheManager = CacheManager.getNewInstance(event.getEntity());
cacheManager.addCache();
}
}
以上是缓存设计的核心代码,如果要实现用户的缓存管理需要创建用户缓存管理类,并实现CacheDeal接口:
需要缓存的用户实体类 UserInfo
- /**
- * 用户类
- *
- * @author liuyang
- *
- */
- @Entity
- @Indexed
- @Table(name = "user_info")
- @NeedCache(cacheDealClass = UserCacheManager.class)//用户缓存管理类
- public class UserInfo extends IdEntity implements Serializable {
- private static final long serialVersionUID = 8046430120913324930L;
- private String loginName;
- private String password;
- private String name;
- private String email;
/**
* 用户类
*
* @author liuyang
*
*/
@Entity
@Indexed
@Table(name = "user_info")
@NeedCache(cacheDealClass = UserCacheManager.class)//用户缓存管理类
public class UserInfo extends IdEntity implements Serializable {
private static final long serialVersionUID = 8046430120913324930L;
private String loginName;
private String password;
private String name;
private String email;
- <SPAN style="WHITE-SPACE: pre"> </SPAN>//getter setter省略
//getter setter省略
- }
}
用户缓存管理类
- /**
- * 用户缓存管理类
- *
- * @author liuyang
- *
- */
- @Component
- public class UserCacheManager implements CacheDeal {
- @Autowired
- private UserRepository userRepository;//数据库user dao
- @Autowired
- private JedisManagerCache jedisManagerCache;//jedis管理类
- @Override
- public void addCache(Object cachedEntity) {
- UserInfo user = (UserInfo) cachedEntity;
- addUserCache(user);
- }
- @Override
- public void removeCache(Object cachedEntity) {
- UserInfo user = (UserInfo) cachedEntity;
- removeUserCache(user);
- }
- @Override
- public void updateCache(Object cachedEntity) {
- UserInfo user = (UserInfo) cachedEntity;
- String userKey = KeyConstants.USER_ + user.getId();
- Map<String, String> userHash = buildUserHash(user);
- jedisManagerCache.saveHash(userKey, userHash);
- }
- @Override
- public Cache getCache(String key) {
- Cache cache = new Cache();
- cache.setKey(key);
- cache.setFieldHashMap(jedisManagerCache.getHashMapByKey(key));
- return cache;
- }
- @Override
- public void init() {
- List<UserInfo> allUserList = getAllUsers();
- for (UserInfo user : allUserList) {
- addUserCache(user);
- }
- }
- /**
- * 新增用户时,添加用户缓存
- *
- * @param user
- */
- private void addUserCache(UserInfo user) {
- Jedis jedis = null;
- Transaction tran = null;
- try {
- jedis = jedisManagerCache.getJedis();
- tran = jedis.multi();
- String userKey = KeyConstants.USER_ + user.getId();
- String userLesseeKey = KeyConstants.USER_LESSEE_
- + user.getLessee().getId();
- Map<String, String> userHash = buildUserHash(user);
- tran.hmset(userKey, userHash);
- tran.sadd(userLesseeKey, user.getId().toString());
- tran.set("user:" + user.getEmail() + ":id", user.getId().toString());
- tran.exec();
- } catch (Exception e) {
- tran.discard();
- LoggerUtil.error(UserCacheManager.class, "添加" + user.getEmail()
- + "缓存失败", e);
- } finally {
- jedisManagerCache.returnResource(jedis);
- }
- }
- /**
- * 移除用户缓存
- *
- * @param user
- */
- private void removeUserCache(UserInfo user) {
- Jedis jedis = null;
- Transaction tran = null;
- try {
- jedis = jedisManagerCache.getJedis();
- tran = jedis.multi();
- String userKey = KeyConstants.USER_ + user.getId();
- String userLesseeKey = KeyConstants.USER_LESSEE_
- + user.getLessee().getId();
- tran.del(userKey);
- tran.srem(userLesseeKey, user.getId().toString());
- tran.del("user:" + user.getEmail() + ":id");
- tran.exec();
- } catch (Exception e) {
- tran.discard();
- LoggerUtil.error(UserCacheManager.class, "删除" + user.getEmail()
- + "缓存失败", e);
- } finally {
- jedisManagerCache.returnResource(jedis);
- }
- }
- /**
- * 构建用户hashmap
- *
- * @param user
- * @return
- */
- private Map<String, String> buildUserHash(UserInfo user) {
- Map<String, String> userHash = new HashMap<String, String>();
- userHash.put("login_name", user.getLoginName());
- userHash.put("name", user.getName());
- userHash.put("email", user.getEmail());
- if (null != user.getUserGroup())
- userHash.put("user_group_name", user.getUserGroup().getName());
- return userHash;
- }
- }
/**
* 用户缓存管理类
*
* @author liuyang
*
*/
@Component
public class UserCacheManager implements CacheDeal {
@Autowired
private UserRepository userRepository;//数据库user dao
@Autowired
private JedisManagerCache jedisManagerCache;//jedis管理类
@Override
public void addCache(Object cachedEntity) {
UserInfo user = (UserInfo) cachedEntity;
addUserCache(user);
}
@Override
public void removeCache(Object cachedEntity) {
UserInfo user = (UserInfo) cachedEntity;
removeUserCache(user);
}
@Override
public void updateCache(Object cachedEntity) {
UserInfo user = (UserInfo) cachedEntity;
String userKey = KeyConstants.USER_ + user.getId();
Map<String, String> userHash = buildUserHash(user);
jedisManagerCache.saveHash(userKey, userHash);
}
@Override
public Cache getCache(String key) {
Cache cache = new Cache();
cache.setKey(key);
cache.setFieldHashMap(jedisManagerCache.getHashMapByKey(key));
return cache;
}
@Override
public void init() {
List<UserInfo> allUserList = getAllUsers();
for (UserInfo user : allUserList) {
addUserCache(user);
}
}
/**
* 新增用户时,添加用户缓存
*
* @param user
*/
private void addUserCache(UserInfo user) {
Jedis jedis = null;
Transaction tran = null;
try {
jedis = jedisManagerCache.getJedis();
tran = jedis.multi();
String userKey = KeyConstants.USER_ + user.getId();
String userLesseeKey = KeyConstants.USER_LESSEE_
+ user.getLessee().getId();
Map<String, String> userHash = buildUserHash(user);
tran.hmset(userKey, userHash);
tran.sadd(userLesseeKey, user.getId().toString());
tran.set("user:" + user.getEmail() + ":id", user.getId().toString());
tran.exec();
} catch (Exception e) {
tran.discard();
LoggerUtil.error(UserCacheManager.class, "添加" + user.getEmail()
+ "缓存失败", e);
} finally {
jedisManagerCache.returnResource(jedis);
}
}
/**
* 移除用户缓存
*
* @param user
*/
private void removeUserCache(UserInfo user) {
Jedis jedis = null;
Transaction tran = null;
try {
jedis = jedisManagerCache.getJedis();
tran = jedis.multi();
String userKey = KeyConstants.USER_ + user.getId();
String userLesseeKey = KeyConstants.USER_LESSEE_
+ user.getLessee().getId();
tran.del(userKey);
tran.srem(userLesseeKey, user.getId().toString());
tran.del("user:" + user.getEmail() + ":id");
tran.exec();
} catch (Exception e) {
tran.discard();
LoggerUtil.error(UserCacheManager.class, "删除" + user.getEmail()
+ "缓存失败", e);
} finally {
jedisManagerCache.returnResource(jedis);
}
}
/**
* 构建用户hashmap
*
* @param user
* @return
*/
private Map<String, String> buildUserHash(UserInfo user) {
Map<String, String> userHash = new HashMap<String, String>();
userHash.put("login_name", user.getLoginName());
userHash.put("name", user.getName());
userHash.put("email", user.getEmail());
if (null != user.getUserGroup())
userHash.put("user_group_name", user.getUserGroup().getName());
return userHash;
}
}
(3)添加服务器启动时,写入缓存功能
我们肯定会遇到,在服务器启动时,去写入很多缓存,这样,在服务器运行中,就可以直接调用缓存了,下面就是这个功能的设计:
让上面的UserCacheManager在多实现一个接口InitializeCache
- /**
- * 缓存数据初始化接口,如果某个实体的缓存数据需要在服务器启动时初始化请实现此接口
- *
- * @author liuyang
- *
- */
- public interface InitializeCache {
- void init();
- }
/**
* 缓存数据初始化接口,如果某个实体的缓存数据需要在服务器启动时初始化请实现此接口
*
* @author liuyang
*
*/
public interface InitializeCache {
void init();
}
- @Component
- public class UserCacheManager implements CacheDeal, InitializeCache {
- //前面的省略
- @Override
- public void init() {
- List<UserInfo> allUserList = getAllUsers();
- for (UserInfo user : allUserList) {
- addUserCache(user);
- }
- }
- }
@Component
public class UserCacheManager implements CacheDeal, InitializeCache {
//前面的省略
@Override
public void init() {
List<UserInfo> allUserList = getAllUsers();
for (UserInfo user : allUserList) {
addUserCache(user);
}
}
}
- public class InitializeCahceManager {
- private List<String> cachedEntityClazzNameList = new ArrayList<String>();
- public void setCachedEntityClazzNameList(
- List<String> cachedEntityClazzNameList) {
- this.cachedEntityClazzNameList = cachedEntityClazzNameList;
- }
- public void init() {
- try {
- for (String clazzName : cachedEntityClazzNameList) {
- Class<?> clazz = Class.forName(clazzName);
- boolean hasNeedCacheAnnotation = clazz
- .isAnnotationPresent(NeedCache.class);
- if (hasNeedCacheAnnotation) {
- NeedCache needCache = clazz.getAnnotation(NeedCache.class);
- InitializeCache initObject = (InitializeCache) SpringContextHolder
- .getBean(needCache.cacheDealClass());
- initObject.init();
- }
- }
- } catch (Exception e) {
- LoggerUtil.error(InitializeCahceManager.class, "初始化缓存失败", e);
- }
- }
- }
public class InitializeCahceManager {
private List<String> cachedEntityClazzNameList = new ArrayList<String>();
public void setCachedEntityClazzNameList(
List<String> cachedEntityClazzNameList) {
this.cachedEntityClazzNameList = cachedEntityClazzNameList;
}
public void init() {
try {
for (String clazzName : cachedEntityClazzNameList) {
Class<?> clazz = Class.forName(clazzName);
boolean hasNeedCacheAnnotation = clazz
.isAnnotationPresent(NeedCache.class);
if (hasNeedCacheAnnotation) {
NeedCache needCache = clazz.getAnnotation(NeedCache.class);
InitializeCache initObject = (InitializeCache) SpringContextHolder
.getBean(needCache.cacheDealClass());
initObject.init();
}
}
} catch (Exception e) {
LoggerUtil.error(InitializeCahceManager.class, "初始化缓存失败", e);
}
}
}
- <!-- 初始化缓存管理类
- 如果需要缓存实体,添加实现类,实现cacheDeal、InitializeCache接口,然后在实体上加needclass的注释,
- 并把需要缓存的实体加入到下面的集合
- -->
- <bean id="initializeCacheManager" class="com.liuyang.infrastructure.cache.InitializeCahceManager">
- <property name="cachedEntityClazzNameList">
- <list>
- <value>com.liuyang.security.model.UserInfo</value>
- </list>
- </property>
- </bean>
<!-- 初始化缓存管理类
如果需要缓存实体,添加实现类,实现cacheDeal、InitializeCache接口,然后在实体上加needclass的注释,
并把需要缓存的实体加入到下面的集合
-->
<bean id="initializeCacheManager" class="com.liuyang.infrastructure.cache.InitializeCahceManager">
<property name="cachedEntityClazzNameList">
<list>
<value>com.liuyang.security.model.UserInfo</value>
</list>
</property>
</bean>
list是需要初始化数据的实体类,下面的serlvet需要加入到web.xml中服务器启动时运行,就大功告成了,启动试试看
- @SuppressWarnings("serial")
- public class InitializeCacheServlet extends HttpServlet {
- @Override
- public void init() throws ServletException {
- super.init();
- InitializeCahceManager manager = SpringContextHolder
- .getBean(InitializeCahceManager.class);
- manager.init();
- }
- }