使用自定义annotation接口进行aspectj动态缓存

本文介绍如何通过AspectJ和Ehcache实现方法级别的缓存功能。利用Spring AOP配置,结合自定义注解MethodCache,实现了基于参数的缓存策略,有效减少了重复查询。

由于系统需求需要对各个接口进行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要缓存方法的实现类

 

内容概要:文章以“智能网页数据标注工具”为例,深入探讨了谷歌浏览器扩展在毕业设计中的实战应用。通过开发具备实体识别、情感分类等功能的浏览器扩展,学生能够融合前端开发、自然语言处理(NLP)、本地存储与模型推理等技术,实现高效的网页数据标注系统。文中详细解析了扩展的技术架构,涵盖Manifest V3配置、内容脚本与Service Worker协作、TensorFlow.js模型在浏览器端的轻量化部署与推理流程,并提供了核心代码实现,包括文本选择、标注工具栏动态生成、高亮显示及模型预测功能。同时展望了多模态标注、主动学习与边缘计算协同等未来发展方向。; 适合人群:具备前端开发基础、熟悉JavaScript和浏览器机制,有一定AI模型应用经验的计算机相关专业本科生或研究生,尤其适合将浏览器扩展与人工智能结合进行毕业设计的学生。; 使用场景及目标:①掌握浏览器扩展开发全流程,理解内容脚本、Service Worker与弹出页的通信机制;②实现在浏览器端运行轻量级AI模型(如NER、情感分析)的技术方案;③构建可用于真实场景的数据标注工具,提升标注效率并探索主动学习、协同标注等智能化功能。; 阅读建议:建议结合代码实例搭建开发环境,逐步实现标注功能并集成本地模型推理。重点关注模型轻量化、内存管理与DOM操作的稳定性,在实践中理解浏览器扩展的安全机制与性能优化策略。
基于Gin+GORM+Casbin+Vue.js的权限管理系统是一个采用前后端分离架构的企业级权限管理解决方案,专为软件工程和计算机科学专业的毕业设计项目开发。该系统基于Go语言构建后端服务,结合Vue.js前端框架,实现了完整的权限控制和管理功能,适用于各类需要精细化权限管理的应用场景。 系统后端采用Gin作为Web框架,提供高性能的HTTP服务;使用GORM作为ORM框架,简化数据库操作;集成Casbin实现灵活的权限控制模型。前端基于vue-element-admin模板开发,提供现代化的用户界面和交互体验。系统采用分层架构和模块化设计,确保代码的可维护性和可扩展性。 主要功能包括用户管理、角色管理、权限管理、菜单管理、操作日志等核心模块。用户管理模块支持用户信息的增删改查和状态管理;角色管理模块允许定义不同角色并分配相应权限;权限管理模块基于Casbin实现细粒度的访问控制;菜单管理模块动态生成前端导航菜单;操作日志模块记录系统关键操作,便于审计和追踪。 技术栈方面,后端使用Go语言开发,结合Gin、GORM、Casbin等成熟框架;前端使用Vue.js、Element UI等现代前端技术;数据库支持MySQL、PostgreSQL等主流关系型数据库;采用RESTful API设计规范,确保前后端通信的标准化。系统还应用了单例模式、工厂模式、依赖注入等设计模式,提升代码质量和可测试性。 该权限管理系统适用于企业管理系统、内部办公平台、多租户SaaS应用等需要复杂权限控制的场景。作为毕业设计项目,它提供了完整的源码和论文文档,帮助学生深入理解前后端分离架构、权限控制原理、现代Web开发技术等关键知识点。系统设计规范,代码结构清晰,注释完整,非常适合作为计算机相关专业的毕业设计参考或实际项目开发的基础框架。 资源包含完整的系统源码、数据库设计文档、部署说明和毕
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值