1. 需求 背景
性能调优阶段,需要找出执行时间比较长的方法,针对这些方法进行调优。
2. 可行方案
一种是传统的在每个方法前后获取System.currentMis(),然后得到方法的执行时间。
这种方式的缺点是方法多会写很多耦合代码,而且不可重用,测试完需要删掉。
另一种使用AOP监控方法的前后点,监控方法的执行时间,比较优雅且无侵入。
可行的方案之一是使用 Around Advice, 环绕通知可在方法执行前后做一些操作。
AOP,面向切面编程,Aspect Oriented Programming, 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。
3. AOP
jar librarys requires:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
service层,写n多个方法,随便设置些方法执行时间
package com.example.demo.service;
import org.springframework.stereotype.Service;
@Service
public class aopService {
public String getMethod1(){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "方法1休眠1秒";
}
public String getMethod2(){
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "方法2休眠2秒";
}
public String getMethod3(){
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "方法3休眠3秒";
}
public String getMethod4(){
try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
return "方法4休眠4秒";
}
}
接下来创建切面AOP实现类
连接点point,第一个*表示方法返回任意值,然后是包.类.方法,第二个*代表类中的任意方法,括号中两点表示方法的参数任意,这里描述的是切入点为service包下的aopService类中的所有方法,类也可以用*号代替表示包下的所有类
package com.example.demo.aop;
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.springframework.stereotype.Component;
import org.springframework.util.StopWatch;
@Aspect
@Component
public class timeAop {
private final static String POINT = "execution (* com.example.demo.service.aopService.*(..))";
@Pointcut(POINT)
public void recordLog(){}
@Around("recordLog()")
public Object around(ProceedingJoinPoint pjp) throws Throwable{
StopWatch stopWatch = new StopWatch();
stopWatch.start();
Object obj = pjp.proceed(pjp.getArgs());
stopWatch.stop();
long cost = stopWatch.getTotalTimeMillis();
MethodSignature signature = (MethodSignature) pjp.getSignature();
String methodName = signature.getDeclaringTypeName() + "." + signature.getName();
System.out.println("----------- 执行" + methodName + "方法, 用时: " + cost + "ms -----------");
return obj;
}
}
最后controller层调用
package com.example.demo.controller;
import com.example.demo.service.aopService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class aopController {
@Autowired
public aopService service;
@RequestMapping("/getAop")
public String getAop(){
String s1 = service.getMethod1();
String s2 = service.getMethod2();
String s3 = service.getMethod3();
String s4 = service.getMethod4();
return s1+s2+s3+s4;
}
}
控制台输出打印了
----------- 执行com.example.demo.service.aopService.getMethod1方法, 用时: 1005ms -----------
----------- 执行com.example.demo.service.aopService.getMethod2方法, 用时: 2000ms -----------
----------- 执行com.example.demo.service.aopService.getMethod3方法, 用时: 3000ms -----------
----------- 执行com.example.demo.service.aopService.getMethod4方法, 用时: 4000ms -----------