一、采用@AspectJ注解来实现
1、在Spring配置文件中启用AspectJ:<aop:aspectj-autoproxy />。同时需要在应用程序的classpath中引入两个AspectJ库:aspectjweaver.jar 和 aspectjrt.jar。
2、定义用到的切面(@Aspect)类:包含切点(@Pointcut)和通知。
注:A可以单独定义切点,然后通过切点的引用来定义通知;也可以使用一个in-place 的切入点表达式直接定义通知。
B通知的参数
3、在Spring配置文件中,配置切面Bean。(切记在配置文件中配置Abject类)
示例:配置部分
<aop:aspectj-autoproxy /> <bean id="logAdviceAspect" class="com.aspects.LogAdviceAspect"> </bean>
Bean部分示例:
@Aspect public class LogAdviceAspect { private static Logger log = Logger.getLogger(LogAdviceAspect.class); @Around("execution(* test.TestStruts.*(..))") public Object doBasicProfilingTime(ProceedingJoinPoint pjp) throws Throwable { log.debug("Takes: start........... "); //org.apache.commons.lang.time.StopWatch StopWatch clock = new StopWatch(); clock.start(); // 计时开始 Object retVal = pjp.proceed(); clock.stop(); // 计时结束 log.debug("Takes:" + clock.getTime() + " ms "); return retVal; } }
二、采用基于模式(schema-based)的方式来实现
1、定义用到的日志或者时间计算类:主要包含相应通知对应的实现方法。
2、在Spring配置文件中,配置步骤1中的Bean。
3、在Spring配置文件中,配置AOP信息。
示例:配置部分
<aop:config> <aop:aspect id="test" ref="timeAdvice"> <aop:pointcut id="idempotentOperation" expression="execution(* test.TestStruts.*(..))" /> <aop:around pointcut-ref="idempotentOperation" method="doBasicProfilingTime" /> </aop:aspect> </aop:config> <bean id="timeAdvice" class="com.aspects.TestAspect"> </bean>
Bean部分示例:
public class TestAspect { protected final Log log = LogFactory.getLog(this.getClass()); public Object doBasicProfilingTime(ProceedingJoinPoint pjp) throws Throwable { //org.apache.commons.lang.time.StopWatch StopWatch clock = new StopWatch(); clock.start(); // 计时开始 Object retVal = pjp.proceed(); clock.stop(); // 计时结束 log.debug("Takes:" + clock.getTime() + " ms "); return retVal; } }
三、采用基于模式(schema-based)和Interceptor的方式来实现
1、定义用到的日志或者时间计算类:该类实现Interceptor接口。
2、在Spring配置文件中,配置步骤1中的Bean。
3、在Spring配置文件中,配置AOP信息。
示例:配置部分
<aop:config> <aop:advisor id="methodTimeLog" advice-ref="methodTimeAdvice" pointcut="execution(* *..service..*(..))" /> </aop:config> <bean id="methodTimeAdvice" class="com.aspects.MethodTimeAdvice" />
Bean部分示例:
public class MethodTimeAdvice implements MethodInterceptor { protected final Log log = LogFactory.getLog(MethodTimeAdvice.class); public Object invoke(MethodInvocation invocation) throws Throwable { // 用 commons-lang 提供的 StopWatch 计时 StopWatch clock = new StopWatch(); clock.start(); // 计时开始 Object result = invocation.proceed(); clock.stop(); // 计时结束 // 方法参数类型,转换成简单类型 Class[] params = invocation.getMethod().getParameterTypes(); String[] simpleParams = new String[params.length]; for (int i = 0; i < params.length; i++) { simpleParams[i] = params[i].getSimpleName(); } log.debug("Takes:" + clock.getTime() + " ms [" + invocation.getThis().getClass().getName() + "." + invocation.getMethod().getName() + "(" + StringUtils.join(simpleParams, ",") + ")] "); return result; } }
注:几种通知需要实现的Interceptor接口分别为:
1、Around通知:org.aopalliance.intercept.MethodInterceptor
2、Before通知:org.springframework.aop.MethodBeforeAdvice
3、AfterReturning通知:org.springframework.aop.AfterReturningAdvice
4、AfterThrowing通知:org.springframework.aop.ThrowsAdvice
附录A:遇到异常
java.lang.NoClassDefFoundError:org/objectweb/asm/commons/EmptyVisitor
解决办法是:
1.去掉类路径上的关于Hibernate的3个lib
asm.jar
asm-attrs.jar
cglib-2.1.3.jar
2.加入Spring中的以下4个lib
asm-2.2.2.jar
asm-commons-2.2.2.jar
asm-util-2.2.2.jar
cglib-nodep-2.1_3.jar
异常分析详见:http://royboy.iteye.com/blog/142449
附录B:常见的切入点(pointcut)定义(参阅:spring2.0-reference_final_zh_cn.chm)
import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Pointcut; @Aspect public class SystemArchitecture { /** * A join point is in the web layer if the method is defined * in a type in the com.xyz.someapp.web package or any sub-package * under that. */ @Pointcut("within(com.xyz.someapp.web..*)") public void inWebLayer() {} /** * A join point is in the service layer if the method is defined * in a type in the com.xyz.someapp.service package or any sub-package * under that. */ @Pointcut("within(com.xyz.someapp.service..*)") public void inServiceLayer() {} /** * A join point is in the data access layer if the method is defined * in a type in the com.xyz.someapp.dao package or any sub-package * under that. */ @Pointcut("within(com.xyz.someapp.dao..*)") public void inDataAccessLayer() {} /** * A business service is the execution of any method defined on a service * interface. This definition assumes that interfaces are placed in the * "service" package, and that implementation types are in sub-packages. * * If you group service interfaces by functional area (for example, * in packages com.xyz.someapp.abc.service and com.xyz.def.service) then * the pointcut expression "execution(* com.xyz.someapp..service.*.*(..))" * could be used instead. */ @Pointcut("execution(* com.xyz.someapp.service.*.*(..))") public void businessService() {} /** * A data access operation is the execution of any method defined on a * dao interface. This definition assumes that interfaces are placed in the * "dao" package, and that implementation types are in sub-packages. */ @Pointcut("execution(* com.xyz.someapp.dao.*.*(..))") public void dataAccessOperation() {} }
常见切入点表达式的例子:
1、任意公共方法的执行:execution(public * *(..))
2、任何一个以“set”开始的方法的执行:execution(* set*(..))
3、AccountService
接口的任意方法的执行:
execution(* com.xyz.service.AccountService.*(..))
4、定义在service包里的任意方法的执行:execution(* com.xyz.service.*.*(..))
5、定义在service包或者子包里的任意方法的执行:
execution(* com.xyz.service..*.*(..))
6、在service包里的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service.*)
7、在service包或者子包里的任意连接点(在Spring AOP中只是方法执行):
within(com.xyz.service..*)