由于系统需求需要对各个接口进行key-value缓存(以参数为key,返回的对象为value),当然对于这种情况首先考虑到的是使用aop,前段时间看过aspectj的一些介绍,借此机会正好加以应用和体会一下,aspectj是AOP最早成熟的java实现,它稍微扩展了一下java语言,增加了一些keyword等,具体的aspectj的基本语法见[ur=http://today.java.net/pub/a/today/2003/12/26/ch3AspectJSyntaxBasics.html]这里[/url],进行缓存的框架使用较成熟的ehcache.
下面开始进行配置
首先是ehcache的配置文件
<?xml version="1.0" encoding="UTF-8"?>
<ehcache>
<diskStore path="/home/workspace/gzshine/trunk/ehcache"/>
<cache name="DEFAULT_CACHE"
maxElementsInMemory="10000"
eternal="false"
timeToIdleSeconds="3600"
timeToLiveSeconds="3600"
overflowToDisk="true"
/>
</ehcache>
这个的DEFAULT_CACHE是默认配置,最大的缓存数为10000,时间为一个小时
接下来的是spring下的配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd">
<!-- ############## aspectj 4 ehcache ############# -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
<bean id = "methodCacheAspectJ" class="com.***.shine.aspectj.MethodCacheAspectJ" >
<property name="cache">
<ref local="methodCache" />
</property>
</bean>
<bean id="cacheManager"
class="org.springframework.cache.ehcache.EhCacheManagerFactoryBean">
<property name="configLocation">
<value>classpath:ehcache.xml</value>
</property>
</bean>
<!-- 定义ehCache的工厂,并设置所使用的Cache name -->
<bean id="methodCache"
class="org.springframework.cache.ehcache.EhCacheFactoryBean">
<property name="cacheManager">
<ref local="cacheManager" />
</property>
<property name="cacheName">
<value>DEFAULT_CACHE</value>
</property>
</bean>
<aop:aspectj-autoproxy proxy-target-class="true"/>
是为aspectj在所有class下开启自动动态代理
<bean id="cacheManager">指定刚刚的ehcache配置文件
接下来编写一个自定义的annotation
package com.***.shine.cache;
import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface MethodCache {
int second() default 0;
}
<bean id = "methodCacheAspectJ">是一个aspectj进行Pointcuts和Advice的类需注入methodCache
package com.***.shine.aspectj;
@Aspect
public class MethodCacheAspectJ {
Log logger = LogFactory.getLog(MethodCacheAspectJ.class);
private Cache cache;
/**
* 设置缓存名
*/
public void setCache(Cache cache) {
this.cache = cache;
}
@Pointcut("@annotation(com.***.shine.cache.MethodCache)")
public void methodCachePointcut(){
}
@Around("methodCachePointcut()")
public Object methodCacheHold(ProceedingJoinPoint joinPoint) throws Throwable{
String targetName = joinPoint.getTarget().getClass().getName();
String methodName = joinPoint.getSignature().getName();
Object[] arguments = joinPoint.getArgs();
Object result = null;
String cacheKey = getCacheKey(targetName, methodName, arguments);
Element element = cache.get(cacheKey);
if (element == null) {
try{
result = joinPoint.proceed();
}catch(Exception e){
logger.info(e);
}
if(result!=null){
try{
element = new Element(cacheKey, (Serializable) result);
Class targetClass = Class.forName(targetName);
Method[] method = targetClass.getMethods();
int second = 0;
for(Method m:method){
if (m.getName().equals(methodName)) {
Class[] tmpCs = m.getParameterTypes();
if(tmpCs.length==arguments.length){
MethodCache methodCache = m.getAnnotation(MethodCache.class);
second = methodCache.second();
break;
}
}
}
if(second>0){ // annotation没有设second值则使用ehcache.xml中自定义值
element.setTimeToIdle(second);
element.setTimeToLive(second);
}
cache.put(element);
}catch(Exception e){
logger.info("!!!!!!!!!"+cacheKey+"!!!!!!!!!未能执行方法缓存"+e);
}
}
}
return element.getValue();
}
private String getCacheKey(String targetName, String methodName,
Object[] arguments) {
StringBuffer sb = new StringBuffer();
sb.append(targetName).append(".").append(methodName);
if ((arguments != null) && (arguments.length != 0)) {
for (int i = 0; i < arguments.length; i++) {
if (arguments[i] instanceof Date) {
sb.append(".").append(
DateUtil.datetoString((Date) arguments[i]));
} else {
sb.append(".").append(arguments[i]);
}
}
}
return sb.toString();
}
}
@Pointcut("@annotation(com.netease.shine.cache.MethodCache)")
对有应用com.netease.shine.cache.MethodCache进行注解的方法进行横切面拦截
@Around("methodCachePointcut()")
并在Advice中处理这个Pointcut,这里的的Advice使用的是Around(环绕通知)
String cacheKey = getCacheKey(targetName, methodName, arguments);
接下来使用类型,方法名,参数为key进入缓存处理
Element element = cache.get(cacheKey);
当然如果在cache队列中取得非null对象则直接返回该对象
MethodCache methodCache = m.getAnnotation(MethodCache.class);
second = methodCache.second();
取得second的值(缓存的时间,如在@annotation中无重写只为int second() default 0)
element.setTimeToIdle(second);
element.setTimeToLive(second);
如果非零则重新设置缓存时间
@MethodCache(second=300)
public List<Sort> getSort(int type,int parentid){
System.out.println("!!!!!!!!!!!!!没缓存到");
Row row = new Row();
row.put("type", type);
row.put("parentid", parentid);
return (List<Sort>)gz_Template.queryForList("sort.getSort", row);
}
最后需要将@MethodCache要缓存方法的实现类
分享到:
相关推荐
最后,我们可以在需要缓存结果的业务方法上使用自定义的`@CacheResult`注解。例如: ```java @Service public class UserService { @CacheResult public User getUserById(Long id) { // 这里的查询会被缓存,...
Spring Boot 中使用自定义两级缓存的方法 在 Spring Boot 应用程序中,缓存机制是非常重要的,它可以大大提高应用程序的性能和效率。缓存机制可以将经常访问的数据存储在内存中,以便快速地访问和检索数据。但是,...
以上代码展示了如何在Spring Boot项目中使用AOP和自定义注解实现接口幂等性。在实际应用中,可能还需要考虑更多的细节,例如异常处理、并发控制、分布式环境下的锁机制等。通过这种方式,我们可以有效地防止表单重复...
Spring Cache 提供了高度的灵活性和扩展性,可以通过SpEL表达式定义缓存key和condition,支持AspectJ切面实现方法级别的缓存,并且允许自定义缓存key生成策略和缓存管理者。 **总结** Spring Cache 为开发者提供了...
5. 支持自定义key和自定义缓存管理者,具有相当的灵活性和扩展性。 Spring Boot Cache的实现原理: 1. 自动配置类:CacheAutoConfiguration,用于自动配置缓存。 2. 属性配置:CacheProperties,用于配置缓存的...
3. **使用AspectJ库**:AspectJ是一个强大的AOP库,支持在Java和Android中进行编译时和加载时织入。在Android项目中,可以使用Android Gradle插件的AspectJ plugin来编译时织入切面。 4. **使用第三方库**:像`...
5. **Mapper Annotation**: 另一种映射方式,直接在 Java 接口上使用注解来指定 SQL 语句。 接下来,我们关注一下标签中的“源码”和“工具”。了解 MyBatis 源码可以帮助开发者更深入地理解其工作原理,提升问题...
`myCache`是自定义的缓存区域,你可以根据需求创建多个。 然后,我们需要在Spring MVC的Controller中启用缓存注解。在Controller类或方法上使用`@Cacheable`或`@CacheEvict`注解来控制缓存的行为。例如: ```java ...
而CGLIB代理则是在运行时动态生成一个目标类的子类来实现,当目标对象没有实现接口时,Spring会选择使用CGLIB。 AOP的核心概念包括切面(Aspect)、通知(Advice)、连接点(Join Point)、切点(Pointcut)、织入...
17.4.5 使用Hibernate二级缓存 17.5 对持久层进行测试 17.5.1 配置Unitils测试环境 17.5.2 准备测试数据库及测试数据 17.5.3 编写DAO测试基类 17.5.4 编写BoardDao测试用例 17.6 服务层开发 17.6.1 UserService的...
17.4.5 使用Hibernate二级缓存 17.5 对持久层进行测试 17.5.1 配置Unitils测试环境 17.5.2 准备测试数据库及测试数据 17.5.3 编写DAO测试基类 17.5.4 编写BoardDao测试用例 17.6 服务层开发 17.6.1 UserService的...
- 模型层:Hibernate的核心在于将Java对象与数据库表进行映射,其模型层包括了Entity(实体类)和Hibernate Annotation(注解),通过@Entity和@Table等注解来定义数据表映射。 - Session工厂:SessionFactory是...
`@Around`通知允许自定义方法调用的整个生命周期,可以在执行前后进行自定义操作,并决定是否继续执行原方法。 **7. 异常通知** `@AfterThrowing`可以捕获并处理方法抛出的异常。 **8. 配合Spring其他功能** ...
在Spring Boot中,我们可以通过实现`org.aspectj.lang.annotation.Before`注解来定义前置通知。例如,可以在用户登录时检查其账号状态,确保账号未被锁定。 2、后置返回通知(After Returning Advice):当方法正常...
2. **方式二:使用命名空间`<context:annotation-config/>`** - 这种方式会自动注册多个注解处理器,包括`AutowiredAnnotationBeanPostProcessor`、`CommonAnnotationBeanPostProcessor`、`...
import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; @Aspect public class FortressInterceptor { @Around("execution(* com.example.service.*.*(..))") public Object ...