AOP是面向切面编程的思想,在Android中也有类似的Hook,内部实现应该都是基于Java动态代理机制,详见Thinking in Java动态代理。
利用AOP我们可以在项目里便捷的实现一些类似请求拦截与日志打印管理等功能。像Android里我们可以Hook onClick做一个事件点击统计。
依赖:
implementation('org.springframework.boot:spring-boot-starter-aop')
image.png
我们使用@Aspect注解,声明这是一个切面处理类,并且使用@Component注解,将处理类注入springboot中使用
切面里我们通过execution语法进行对应切入点的生命:
最前面的是切入函数的权限类型(public,protected,private......),
接着是切入函数的返回类型:示例代码我们用则表示匹配所有的返回类型。
然后是切面路径,在示例里我们在example后面采用了..,这里意味着匹配example目录下的所有子目录。
接着是切面类,在示例内,我们采用表明匹配所有的类
然后是切面的具体方法,示例里我们写的是findPerson这个函数,如果想要匹配所有方法那么用*替代
最后是方法参数这里我们用..表示匹配所有参数,也可以具体的进行匹配,如(int,String)
所以execution(public * com.example..*.findPerson(..)表示的意思是,匹配com.example包下所有的目录中所有的类里的findPerson的方法,只要符合规则的findPerson运行,那么选择了它作为切点的处理函数就会执行
@Aspect
@Component
public class HttpAspect {
private final static Logger logger= LoggerFactory.getLogger(HttpAspect.class);
//使用@Pointcut注解,提取出一个公用切面(excecution)出来,供其余使用
@Pointcut("execution(public * com.example..*.findPerson(..))")
public void logPointBoth(){}
@Before("logPointBoth()")
public void logBeforeByBothPoint(){
logger.info("切在方法前");
}
@After("logPointBoth()")
public void logAfterByBothPoint(){
logger.info("切在方法后");
}
@Before("execution(public * com.example..*.findPerson(..))")
public void logBefore(JoinPoint joinPoint){
ServletRequestAttributes requestAttributes= (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request=requestAttributes.getRequest();
logger.info("url={}",request.getRequestURI());
logger.info("method={}",request.getMethod());
logger.info("ip={}",request.getRemoteAddr());
Signature signature=joinPoint.getSignature();
//类方法
logger.info("class_method={}",signature.getDeclaringTypeName()+"."+signature.getName());
//参数
logger.info("args={}",joinPoint.getArgs());
}
@After("execution(public * com.example..*.findPerson(..))")
public void logAfter(){
logger.info("切在方法后");
}
@AfterReturning(returning ="result",pointcut ="logPointBoth()")
public void logAfterReturning(Object result){
logger.info("输出返回结果:"+result);
}
}
网友评论