在Spring中,实现AOP增强不仅可以使用@Aspect注解来实现,还可以通过自定义切面来实现。

下面来看看怎么自定义切面。

切面

切面需要实现PointcutAdvisor接口,一个切面必须包含切点和通知。

package com.morris.spring.advisor;import org.aopalliance.aop.Advice;
import org.springframework.aop.Pointcut;
import org.springframework.aop.support.AbstractPointcutAdvisor;/*** 自定义Advisor*/
public class CustomAdvisor extends AbstractPointcutAdvisor {@Overridepublic Advice getAdvice() {return new CustomAdvice();}@Overridepublic Pointcut getPointcut() {return new CustomPointcut();}
}

切点

切点需要实现Pointcut接口,里面要实现对类的匹配和方法的匹配。

这里不对类进行校验,所以使用Spring内部的ClassFilter.TRUE。

对方法的匹配需要实现MethodMatcher,所以CustomPointcut同时实现了MethodMatcher和Pointcut。

package com.morris.spring.advisor;import org.springframework.aop.ClassFilter;
import org.springframework.aop.MethodMatcher;
import org.springframework.aop.Pointcut;import java.lang.reflect.Method;public class CustomPointcut implements MethodMatcher, Pointcut {// implement from MethodMatcher@Overridepublic boolean matches(Method method, Class<?> targetClass) {if(method.getName().startsWith("insert")) {return true;}return false;}@Overridepublic boolean isRuntime() {return true;}// 如果isRuntime返回true,则会在运行时调用此方法@Overridepublic boolean matches(Method method, Class<?> targetClass, Object... args) {if(null != args && null != args[0] && "morris".equals(args[0])) {System.out.println("matches  args");return true;}return false;}// implement from Pointcut@Overridepublic ClassFilter getClassFilter() {return ClassFilter.TRUE;}@Overridepublic MethodMatcher getMethodMatcher() {return this;}
}

通知

通知主要是对目标方法的增强,这里只是打印。

package com.morris.spring.advisor;import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;public class CustomAdvice implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println(invocation.getMethod().getName()+"-------------------------");return invocation.proceed();}
}

测试类

package com.morris.spring.demo.aop;import com.morris.spring.advisor.CustomAdvisor;
import com.morris.spring.service.UserService;
import com.morris.spring.service.UserServiceImpl;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;/*** 自定义Advisor的使用*/
@Configuration
@EnableAspectJAutoProxy // 开启AOP
public class CustomAspectDemo {public static void main(String[] args) {AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();applicationContext.register(UserServiceImpl.class);applicationContext.register(CustomAdvisor.class); // 自定义切面applicationContext.register(CustomAspectDemo.class); // 开启AOPapplicationContext.refresh();UserService userService = applicationContext.getBean(UserService.class);userService.insert("morris");}
}

运行结果如下:

matches  args
insert-------------------------
UserServiceImpl insert morris

发现通知中的增强代码执行了。

尝试获得目标方法上的注解信息

UserServiceImpl.insert()方法上面加上@Entity注解。

com.morris.spring.service.UserServiceImpl#insert

@Entity
@Override
public void insert(String name) {System.out.println("UserServiceImpl insert " + name);
}

com.morris.spring.advisor.CustomPointcut#matches

@Override
public boolean matches(Method method, Class<?> targetClass) {if(method.isAnnotationPresent(Entity.class)) {return true;}return false;
}

运行结果会发现通知中的增强代码并没有被执行,这是为什么呢?目标方法insert()上面明明有@Entity注解,为什么获取不到呢?

在matches()方法中打上断点,会发现这个方法会被调用两次,第一次会返回true,第二次返回false,为什么两次结果会不一样呢?

先来看一下这两次调用的调用时机:

  1. 第一次调用时,匹配方法,如果匹配上了就会生成代理对象,Method所在的类为com.morris.spring.service.UserServiceImpl。

  2. 第二次调用时,调用代理对象的方法时会再次匹配,因为有的方法不需要代理,Method所在的类为com.morris.spring.service.UserService。

第二次调用时Method是来自于UserService接口,而接口上面的方法是没有注解的,这点也可以从动态代理生成的类中看出:

static {try {...m3 = Class.forName("com.morris.spring.service.UserService").getMethod("insert", Class.forName("java.lang.String"));...} catch (NoSuchMethodException var2) {throw new NoSuchMethodError(var2.getMessage());} catch (ClassNotFoundException var3) {throw new NoClassDefFoundError(var3.getMessage());}
}

而UserService.insert()方法上面并没有@Entity注解,那么要怎么样才能获得注解的信息呢?Spring提供了下面的工具类:

com.morris.spring.advisor.CustomPointcut#matches

public boolean matches(Method method, Class<?> targetClass) {Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);if(specificMethod.isAnnotationPresent(Entity.class)) {return true;}return false;
}

方法参数级别更细粒度的匹配

MethodMatcher还有两个方法:

boolean isRuntime();
boolean matches(Method method, Class<?> targetClass, Object... args);

这两个方法配合使用能在运行时对参数的值进行匹配。

public boolean isRuntime() {return true;
}public boolean matches(Method method, Class<?> targetClass, Object... args) {if(null != args && null != args[0] && "morris".equals(args[0])) {System.out.println("matches  args");return true;}return false;
}

需要满足两个条件这个带方法参数的matches()才会执行(这个方法只会执行一次,真正调用时才会知道参数的具体值):

  1. 不带方法参数的matches()返回true。
  2. isRuntime()返回true。

【spring】自定义AOP切面相关推荐

  1. Spring自定义AOP切面

    切面 切面需要实现PointcutAdvisor接口,包含切点和通知. package com.morris.spring.aop;import org.aopalliance.aop.Advice; ...

  2. Spring MVC AOP切面失效原因与处理

    Spring MVC AOP切面失效原因与处理 问题概述 AOP的两类实现 解决方案 方法一:用Autowired 注入自身的实例 方法二:从Spring上下文获取增强后的实例引用 方法三: 利用Ao ...

  3. Spring中AOP切面编程学习笔记

    注解方式实现aop我们主要分为如下几个步骤: 1.在切面类(为切点服务的类)前用@Aspect注释修饰,声明为一个切面类. 2.用@Pointcut注释声明一个切点,目的是为了告诉切面,谁是它的服务对 ...

  4. [原创]java WEB学习笔记107:Spring学习---AOP切面的优先级,重用切点表达式

    本博客的目的:①总结自己的学习过程,相当于学习笔记 ②将自己的经验分享给大家,相互学习,互相交流,不可商用 内容难免出现问题,欢迎指正,交流,探讨,可以留言,也可以通过以下方式联系. 本人互联网技术爱 ...

  5. spring之AOP切面不生效!!!!!原因在这

    首先配置好切面代码 打印日志 package com.rfca.aop;import com.fasterxml.jackson.databind.ObjectMapper; import org.a ...

  6. Java手写Spring的AOP(切面织入)小Demo--盲僧代理击飞 亚索接大实例

    在学习Spring的过程中总会很迷茫,打个@Aspect注解切面功能就有了,只要脱离了框架感觉自己还是什么都没会,所以自己猜了一下切面的思路,大概写了个小Demo,欢迎交流. 涉及知识:JDK动态代理 ...

  7. Spring的AOP切面编程

    语言苍白无力,我们直接代码说话 package com.example.demo.aspect; import org.springframework.stereotype.Component; @C ...

  8. Spring的AOP实现

    Spring的AOP切面,通过代理的方式来实现切面 静态代理:是使用AspectJ:即在编译阶段生成AOP代理类,也成为编译时增强. 动态代理:使用Spring AOP. 1.使用AspectJ的编译 ...

  9. 【SSM框架系列】Spring 的 AOP(面向切面编程)

    什么是 AOP AOP 为 Aspect Oriented Programming 的缩写,意思为面向切面编程,是通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术. AOP 是 OOP ...

  10. Spring Boot————AOP入门案例及切面优先级设置

    看了这篇文章,如果你还是不会用AOP来写程序,请你打我!! =.=||| 引言 Spring AOP是一个对AOP原理的一种实现方式,另外还有其他的AOP实现如AspectJ等. AOP意为面向切面编 ...

最新文章

  1. c++趣味小程序_工具类小程序10天增长103万全复盘
  2. [luogu 4292][bzoj 1758][WC2010] 重建计划(点分治 + dp + 单调队列优化 + 启发式合并)
  3. BugkuCTF-MISC题zip伪加密
  4. [.NET 三层架构(ADO.NET)+Web Service+多语言]WinForm三层架构重新实现TaskVision,外加WebService提供数据和多语言...
  5. 进程的优先级设置与获取,进程时间
  6. php windows 网络流量,PHP系统流量分析的程序
  7. SAP License:SAP学习笔记
  8. 网络管理员考试案例梳理、真题透解与强化训练
  9. [LeetCode]Count and Say
  10. 【linux】gcc命令
  11. Storm入门之第6章一个实际的例子
  12. 工具分享之NetSetMan
  13. 上学的时候写的文本分割器
  14. 20春季 7-2 The Judger (25 分)
  15. 全排列算法(字典序法、SJT Algorithm 、Heap's Algorithm)
  16. 黑天鹅mobi_破坏我们系统的因素:黑天鹅分类法
  17. win10开机慢怎么解决_win10开机速度变慢的解决方法教程
  18. 使命召唤19发布时间曝光 确定将于10月28号发布
  19. html日历页面节假日_js css+html实现简单的日历
  20. Windows 10 中的存储空间

热门文章

  1. ydui滚动加载:TypeError: Cannot read property '$emit' of undefined
  2. 2021-01-05
  3. Pytorch 残差网络 ResNet
  4. 查看 Visio 是否激活以及激活方法
  5. matlab ctradon函数,Radon变换入门matlab CT原理
  6. 家用计算机的使用说明,AWIND奇机家用无线投屏器使用说明
  7. gmp php study,[技术干货] USP中文翻译连载 | 产品生命周期的包装密封性检查 (1、2之3)...
  8. 惠普(HP) LaserJet Pro M1136 MFP 黑白多功能激光一体机 (打印 复印 扫描)驱动安装记录
  9. JVM之JVM运行时内存结构, JDK1.7 JVM内存结构, JDK1.8 JVM内存结构, JVM堆内存结构
  10. Mac系统, 切换大小写失灵