SpringAOP应用-日志输出耗时统计

一、采用@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接口分别为:

       1Around通知:org.aopalliance.intercept.MethodInterceptor

       2Before通知:org.springframework.aop.MethodBeforeAdvice

       3AfterReturning通知:org.springframework.aop.AfterReturningAdvice

       4AfterThrowing通知: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*(..))

3AccountService 接口的任意方法的执行:

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..*)

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值