SpringBoot2.x下AOP增强日志管理+AOP切入点表达式
发布日期:2021-06-29 21:37:16 浏览次数:3 分类:技术文章

本文共 6433 字,大约阅读时间需要 21 分钟。

导入AOP依赖:

org.springframework.boot
spring-boot-starter-aop

AOP日志管理增强指定包代码

package com.dl.blog.config;import org.aspectj.lang.JoinPoint;import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.*;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.core.annotation.Order;import org.springframework.stereotype.Component;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import org.springframework.context.annotation.EnableAspectJAutoProxy;import javax.servlet.http.HttpServletRequest;import java.util.Arrays;/** * 即使用jdk默认代理模式,AspectJ代理模式是CGLIB代理模式 * 如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP * 如果目标对象实现了接口,可以强制使用CGLIB实现AOP (此例子我们就是强制使用cglib实现aop) * 如果目标对象没有实现了接口,必须采用CGLIB库,spring会自动在JDK动态代理和CGLIB之间转换 */@Order(1)//使用@Order注解指定切面的优先级,值越小优先级越高。@Aspect@EnableAspectJAutoProxy//开启AspectJ 自动代理模式,如果不填proxyTargetClass=true,默认为false,@Componentpublic class LoggerAspectConfig {
private final Logger logger= LoggerFactory.getLogger(this.getClass()); //定义切入点表达式和切面类,此切入点对应含义为: //法一、(execution)选择方法 返回值任意 包名为com.dl.blog.controller 类名任意 方法名任意 参数任意 /**法二、@Pointcut("@annotation(* com.dl.blog.config.MyLogger)") * MyLogger:自定义注解所在全类名,然后在需要日志的类上加上@MyLogger注解就好了 */ @Pointcut("execution(* com.dl.blog.controller.*.*(..))") public void aspect(){
} /** * 配置前置通知 * @param joinPoint 切面对象,可用于获取当前被代理类 */ @Before("aspect()") public void before(JoinPoint joinPoint){
ServletRequestAttributes attributes=(ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); HttpServletRequest request=attributes.getRequest(); String url=request.getRequestURL().toString(); String ip=request.getRemoteAddr(); String className = joinPoint.getTarget().getClass().getName(); String method = joinPoint.getSignature().getName(); String classMethod=className+"."+method; Object[] args=joinPoint.getArgs();//请求参数 RequestAspect requestAspect=new RequestAspect(url,ip,classMethod,args);// logger.info(className + "." + method + "(" + StringUtils.join(joinPoint.getArgs(), ",") + ")"); logger.info("Request:{}",requestAspect); } /** * 后置最终通知,final增强,不管是抛出异常或者正常退出都会执行 */ @After("aspect()") public void after(){
logger.info("------------------doAfter------------------"); } /** * 后置异常通知 * @param joinPoint */ @AfterThrowing("aspect()") public void throwss(JoinPoint joinPoint){
String className = joinPoint.getTarget().getClass().getName(); String method = joinPoint.getSignature().getName(); String classMethod=className+"."+method; logger.info("{}方法执行异常!!!",classMethod); } //处理完请求返回内容 @AfterReturning(returning = "result",pointcut = "aspect()") public void doAfterReturn(Object result){
logger.info("Result:{}",result); } /** * 环绕通知,环绕增强,相当于MethodInterceptor * @param pjp * @return */ @Around("aspect()") public Object arround(ProceedingJoinPoint pjp) {
try {
Object o = pjp.proceed(); return o; } catch (Throwable e) {
e.printStackTrace(); return null; } } //返回结果内部类 private class RequestAspect{
private String url; private String ip; private String classMethod; private Object[] args; public RequestAspect(String url, String ip, String classMethod, Object[] args) {
this.url = url; this.ip = ip; this.classMethod = classMethod; this.args = args; } public RequestAspect() {
} @Override public String toString() {
return "RequestAspect{" + "url='" + url + '\'' + ", ip='" + ip + '\'' + ", classMethod='" + classMethod + '\'' + ", args=" + Arrays.toString(args) + '}'; } }}

如果我们想对一个包下的类进行AOP增强,但要排除其中一些类的时候我们可以对切入点表达式进行改进,例如:

@Pointcut("execution(* *..*Action*.*(..)) && !execution(* com.audaque.tjfxpt.web.sjcx.LogAction.*(..))")//表示想要对返回值任意 任意包及其子包下的包含Action的类的任意方法参数任意 的类进行增强,并且排除对com.audaque.tjfxpt.web.sjcx包下的LogAction类进行增强。

相关说明:

AOP中扫描指定注解相关说明
(1)@annotation:用来拦截所有被某个注解修饰的方法
(2)@within:用来拦截所有被某个注解修饰的类
(3)within:用来指定扫描的包的范围

增强指定注解标识的类或方法

@Aspect@Component@Order(10)public class BidAuthorityProxy {
/** * 扫描指定包下的类中使用@EnableRoleAuthority注解修饰的类 */ @Around("@within(com.core.annotation.EnableRoleAuthority) && within(com.bid..*)") public Object verifyRoleExecuteCommand(ProceedingJoinPoint pjp) throws Throwable {
// 获取当前拦截方法的对象 MethodSignature msig = (MethodSignature) pjp.getSignature(); Method targetMethod = pjp.getTarget().getClass().getDeclaredMethod(msig.getName(), msig.getMethod().getParameterTypes()); // 获取当前方法注解中的值 VerifyRoleAuthority annotation = targetMethod.getAnnotation(VerifyRoleAuthority.class); // 如果类上面没有注解,则获取接口上此方法的注解 if (annotation == null) {
Class
[] inters = pjp.getTarget().getClass().getInterfaces(); for (Class
inter : inters) {
Method targetInterMethod = inter.getDeclaredMethod(msig.getName(), msig.getMethod().getParameterTypes()); annotation = targetInterMethod.getAnnotation(VerifyRoleAuthority.class); if (annotation != null) {
break; } } } // 获取到注解中的值后进行后续自定义逻辑操作 return pjp.proceed();// 执行方法 }}

Aop联盟定义通知类型,具有特定接口,必须实现,从而确定方法名称,AspectJ通知类型:

Aspectj通知类型,只定义类型名称。已知方法格式
Before:前置通知(应用:各种校验)
在方法执行之前执行,如果通知抛出异常,阻止方法执行
AfterReturning:后置通知(应用:常规数据处理)
方法正常返回之后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法返回值。
Around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以组织方法的执行
必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常信息之后执行,如果方法没有抛出异常,无法执行。
after:最终通知(应用:清理现场)
方法执行完毕之后执行,无论方法中是否出现异常

AOP术语:

1、Target(目标类),需要被代理的类
2、Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3、PointCut(切入点):已经被增强的连接点。例如:adduser();
4、Advice(通知/增强):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知,通知分为前置通知、后置通知、异常通知、最终通知、环绕通知(切面要完成的功能) 增强代码。
例如:after,before
5、Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程。
6、Proxy代理类
7、Aspect(切面):是切入点pointcut和通知advice的结合
在这里插入图片描述

转载地址:https://dh-butterfly.blog.csdn.net/article/details/108599694 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:SpringBoot2.0之Mybatis-Generator完整配置+Free Mybatis plugin插件快速切换mapper和xml
下一篇:中文字体的英文名称

发表评论

最新留言

初次前来,多多关照!
[***.217.46.12]2024年04月30日 04时56分41秒