关于aop对目标方法性能影响的一些记录
今天记录一下自己对aop的一个理解误区,实际上是给过去初入java的自己一个交代
数年之前我刚入坑java的时候,公司对日志的打印把控的比较严格,因为项目比较大,大量的日志经常会导致系统整体运行速度不能满足业务需求。
那么我的问题来了:logger不是说是使用aop实现的么,aop不是说完全不会影响原有程序的运行的么(所以永远都不要猜一个菜鸟心里在想什么),所以我问了一下当时我身边的大佬。他当时给我的回答是:日志打印虽然不会影响程序的运行,但是大量的日志输出会占用大量的io,从而拖慢系统运行速度,emmmm也不算错
目前暂时还没有研究logger的源代码,也不知道是否如网上所说是使用aop实现的,但是只是针对aop倒是可以试上一试,借用一下之前的代码java自定义注解并结合aop实现权限控制
package com.yinyuecheng.jioencryption.aop;
import com.google.gson.Gson;
import com.yinyuecheng.jioencryption.DiyIntegerface.RoleValid;
import com.yinyuecheng.jioencryption.common.RoleValidEnum;
import com.yinyuecheng.jioencryption.common.UserInfo;
import com.yinyuecheng.jioencryption.exception.AuthorityException;
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.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpSession;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.concurrent.ConcurrentHashMap;
@Aspect
@Component
public class RoleValidAround {
@Autowired
HttpSession httpSession;
private static Gson gson = new Gson();
private Logger logger = LoggerFactory.getLogger(RoleValidAround.class);
@Pointcut("@annotation(com.yinyuecheng.jioencryption.DiyIntegerface.RoleValid)")
public void RoleValidAroundPointCut(){}
@Around("RoleValidAroundPointCut()")
public Object validAround(ProceedingJoinPoint joinPoint) throws IllegalAccessException, InstantiationException {
//获取传入目标方法的参数
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
System.out.println("第" + (i+1) + "个参数为:" + args[i]);
}
System.out.println("被代理的对象:" + joinPoint.getTarget());
System.out.println("代理对象自己:" + joinPoint.getThis());
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
Method method = methodSignature.getMethod();
RoleValid roleValid = method.getAnnotation(RoleValid.class);
RoleValidEnum limitPower = roleValid.role();
//UserInfo userInfo = gson.fromJson(gson.toJson(httpSession.getAttribute("userInfo")),UserInfo.class);
Object[] objs = joinPoint.getArgs();
Class [] paramClasses = method.getParameterTypes();
UserInfo userInfo = null;
for(int i=0;i<paramClasses.length;i++){
if(paramClasses[i].newInstance() instanceof UserInfo){
userInfo = gson.fromJson(gson.toJson(objs[i]),UserInfo.class);
}
}
if(userInfo==null){
System.out.println("无可检索的权限信息,请检查入参是否规范");
return null;
}
String user = userInfo.getPower();
/*ConcurrentHashMap map = gson.fromJson(gson.toJson(objs[0]),ConcurrentHashMap.class);
String user = (String)map.get("power");*/
RoleValidEnum userPower = RoleValidEnum.getPower(user);
logger.info("~~~~~~~~~~limitPower:{},~~~~~~~~~~~userPower:{}",limitPower,userPower);
if(RoleValidEnum.hasPower(userPower,limitPower)){
Object result = null ;
try {
result = joinPoint.proceed();
return result;
}catch(Throwable e){
return new AuthorityException(500000,"system error");
}
}else{
logger.info("~~~~~~~~~~~~~~~~~have no power");
return null;
}
}
}
目标类
@Override
@RoleValid(role=RoleValidEnum.VIP3)
public void doVip3(String test,Vip3Param param){
logger.info("ip3 办事~~~~~~~~~~~~~~~~~~~~~~~~~~~");
}
测试类
@Test
public void testForbid() throws Exception {
Vip3Param param = new Vip3Param();
param.setPower(RoleValidEnum.VIP4.getMsg());
basicInfoService.doVip3("test",param);
}
run起来
2019-06-06 16:27:36 036 [main] INFO com.yinyuecheng.jioencryption.aop.RoleValidAround - ~~~~~~~~~~limitPower:VIP3,~~~~~~~~~~~userPower:VIP4
2019-06-06 16:27:36 036 [main] INFO c.y.j.service.impl.BasicInfoServiceImpl - ip3 办事~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-06-06 16:27:36 036 [Thread-2] INFO o.s.scheduling.concurrent.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
震惊,aop类和目标类在一个线程里面跑(main线程 ,其实这个才最正常),这说明aop里面做的事情需要的消耗要完全算在整个程序的运行消耗里面,下面我们把aop里面加个线程休眠,更直观的看下aop对目标方法执行效率的影响
logger.info("~~~~~~~~~~limitPower:{},~~~~~~~~~~~userPower:{}",limitPower,userPower);
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
再跑一次
2019-06-06 17:04:52 052 [main] INFO com.yinyuecheng.jioencryption.aop.RoleValidAround - ~~~~~~~~~~limitPower:VIP3,~~~~~~~~~~~userPower:VIP4
2019-06-06 17:04:55 055 [main] INFO c.y.j.service.impl.BasicInfoServiceImpl - ip3 办事~~~~~~~~~~~~~~~~~~~~~~~~~~~
2019-06-06 17:04:55 055 [Thread-2] INFO o.s.scheduling.concurrent.ThreadPoolTaskExecutor - Shutting down ExecutorService 'applicationTaskExecutor'
很明显的看到执行时间被后置了三秒,所以aop实际上跟(从程序逻辑上来讲)在方法里面加上对应逻辑是一样的(但实际上动态代理也肯定是有资源消耗的)。
end