一、开启spring的aop功能
开启注解切面
applicationContext.xml添加aop命名空间,并添加:
<!-- 强制CGLIB代理 -->
<aop:aspectj-autoproxy proxy-target-class="true"/>
二、自定义注解
1、建立包com.study.base.annotation
2、新增TimeCount.java
package com.study.base.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* com.study.base.annotation 时间统计注解
* 在需要时间统计的方法上添加该注解,并提供时间统计handler类
* 默认时间统计handler类为DefaultTimeCountHandler
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface TimeCount {
String value() default "com.study.base.component.DefaultTimeCountHandler";
}
三、定义注解处理类
1、建立包com.study.base.component
2、新增DefaultTimeCountHandler.java
package com.study.base.component;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
@Component("com.study.base.component.DefaultTimeCountHandler")
public class DefaultTimeCountHandler {
private static Logger logger = LoggerFactory.getLogger(DefaultTimeCountHandler.class);
public long start() {
logger.info("DefaultTimeCountHandler start");
return System.currentTimeMillis();
}
public long end() {
logger.info("DefaultTimeCountHandler end");
return System.currentTimeMillis();
}
}
四、自定义切面
1、新增CustomTimeAdvice.java
package com.study.base.component;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;
import com.study.base.annotation.TimeCount;
import com.study.base.util.ApplicationContextHolder;
/**
* 自定义切面
* @author User
*
*/
@Aspect //切面声明
@Component //组件声明
@Order(1) //切面执行顺序
public class CustomTimeAdvice {
private static Logger logger = LoggerFactory.getLogger(CustomTimeAdvice.class);
/**
* 切入点为添加了@TimeCount注解的方法
*/
@Pointcut(value = "@annotation(com.study.base.annotation.TimeCount)")
public void pointCut() {
}
/**
* @param point 被切面方法相关属性
* @param timeCount 注解类对象
*/
@Around(value = "pointCut() && @annotation(timeCount)")
public Object timeAround(ProceedingJoinPoint point, TimeCount timeCount) {
//获取被切面方法的方法签名
org.aspectj.lang.Signature funSignature = point.getSignature();
//返回值的类型
Class returnType = ((MethodSignature) funSignature).getReturnType();
//入参
Object[] objects = point.getArgs();
logger.info("被切面方法名: {}", funSignature.getName());
logger.info("返回值类型: {}", returnType.getName());
logger.info("入参: {}", objects);
//业务方法返回值
Object respBean = null;
//签名处理类
DefaultTimeCountHandler defaultTimeCountHandler = null;
//开始时间
long start = 0;
//结束时间
long end = 0;
try {
//从spring上下文中获取签名操作对象
defaultTimeCountHandler = (DefaultTimeCountHandler) ApplicationContextHolder.getBean(timeCount.value());
//===================================前置处理================================
start = defaultTimeCountHandler.start();
logger.info("方法开始时间: {}", start);
//===================================原请求处理================================
try {
respBean = point.proceed();
} catch (Throwable throwable) {
logger.error(throwable.getMessage(), throwable);
}
//===================================后置处理================================
end = defaultTimeCountHandler.end();
logger.info("方法结束时间: {}", end);
} catch (Throwable e) {
logger.error(e.getMessage(), e);
} finally {
//===================================收尾处理================================
logger.info("方法消耗时间: {}", end - start);
}
return respBean;
}
}
五、添加注解并测试
注意:注解要加在public的方法上,如果原来Controller里方法是private要改成public。因为aop切不进private的方法。
@RequestMapping("hello")
@TimeCount
public String hello() {
log.info("hello in...");
log.info("hello out...");
return "hello";
}
测试方法:
@Test
public void testhello() {
testController.hello();
}
测试日志:
2019-08-17 11:01:08.170 [] [] [] [] INFO [main] com.study.base.component.CustomTimeAdvice [49]:被切面方法名: hello
2019-08-17 11:01:08.173 [] [] [] [] INFO [main] com.study.base.component.CustomTimeAdvice [50]:返回值类型: java.lang.String
2019-08-17 11:01:08.173 [] [] [] [] INFO [main] com.study.base.component.CustomTimeAdvice [51]:入参: {}
2019-08-17 11:01:08.173 [] [] [] [] INFO [main] com.study.base.component.DefaultTimeCountHandler [13]:DefaultTimeCountHandler start
2019-08-17 11:01:08.173 [] [] [] [] INFO [main] com.study.base.component.CustomTimeAdvice [68]:方法开始时间: 1566010868173
2019-08-17 11:01:08.190 [] [] [] [] INFO [main] com.study.base.component.DefaultTimeCountHandler [18]:DefaultTimeCountHandler end
2019-08-17 11:01:08.190 [] [] [] [] INFO [main] com.study.base.component.CustomTimeAdvice [79]:方法结束时间: 1566010868190
2019-08-17 11:01:08.191 [] [] [] [] INFO [main] com.study.base.component.CustomTimeAdvice [86]:方法消耗时间: 17
六、其他
注:最新代码上传至https://github.com/csj50/webapp2.git
参考资料:
https://my.oschina.net/u/3217171/blog/3066776/