ByxAOP——简易AOP框架

Wesley13
• 阅读 473

ByxAOP是一个基于JDK动态代理的简易AOP框架,具有以下功能特性:

  • 对目标对象的特定方法进行拦截和增强
  • 支持灵活的拦截规则和自定义拦截规则
  • 动态实现接口和批量实现接口方法
  • 灵活的对象代理机制

项目地址:github 码云

使用示例

首先来通过一个简单例子快速了解ByxAOP。

假设我们有一个UserDao接口:

public interface UserDao{ int listAll(); int listById(int id); void deleteByName(String name);}

UserDao接口有一个UserDaoImpl实现类:

public class UserDaoImpl implements UserDao{ @Override public int listAll() {  System.out.println("正在执行listAll方法");  return 123; } @Override public int listById(int id) {  System.out.println("正在执行listById方法:id = " + id);  return 456; } @Override public void deleteByName(String name) {  System.out.println("正在执行deleteByName方法:name = " + name); }}

现在我们来完成一个需求:拦截UserDaoImpl中所有以list开头的方法,即listAlllistById方法,拦截过程中打印出目标方法的一些相关信息。使用ByxAOP来完成这个需求,只需要三个步骤:

  • 第一步:创建一个方法拦截器(MethodInterceptor):

    MethodInterceptor interceptor = (signature, targetMethod, params) ->{ System.out.println("开始拦截" + signature.getName() + "方法"); System.out.println("原始参数:" + Arrays.toString(params)); Object ret = targetMethod.invoke(params); System.out.println("原始返回值:" + ret); System.out.println("结束拦截" + signature.getName() + "方法"); return ret;};
    

    MethodInterceptor是ByxAOP中用来表示方法拦截器的核心接口,signature是目标方法签名,targetMethod用于调用目标方法,params是传递给目标方法的参数。在interceptor中,首先打印了拦截开始信息、目标方法的方法名和原始参数,然后调用了目标方法并获取返回值,最后打印了返回值和拦截结束信息。

    关于MethodInterceptor接口及其相关方法和参数的详细介绍,请看下文。

  • 第二步:创建一个方法匹配器(MethodMatcher):

    MethodMatcher matcher = withPattern("list(.*)").andReturnType(int.class);
    

    MethodMatcher的构建使用了一种被称为“流畅接口”的API设计风格,通过链式调用以及特定的命名来达到很好的可读性。withPattern匹配方法名满足指定正则表达式的方法,andReturnType则在上一个匹配器的基础上增加了返回值类型的条件。整个matcher表示匹配所有方法名以list开头且返回值为int类型的方法。

    MethodMatcher接口有很多预定义的实现类,通过组合这些类可以非常灵活地配置拦截规则,请看下文的详细介绍。

  • 第三步:创建AOP代理对象:

    UserDao userDao = proxy(new UserDaoImpl(), interceptor.when(matcher));
    

    proxy方法是AOP类中的一个静态方法,用于创建AOP代理对象。第一个参数传入目标对象(被增强的对象),第二个参数传入方法拦截器。对于目标对象中的每一个方法调用,都会被该方法拦截器拦截。不过请注意,这里我们用interceptor.when(matcher)指定了拦截条件。由于match匹配以list开头且返回值为int类型的方法,所以只有满足这个条件的方法才会被intercept拦截。

到这里,代理对象userDao就被创建出来了,现在让我们来调用一下userDao中的各个方法:

userDao.listAll();System.out.println();userDao.listById(1001);System.out.println();userDao.deleteByName("XiaoMing");

控制台输出如下:

开始拦截listAll方法原始参数:null正在执行listAll方法原始返回值:123结束拦截listAll方法开始拦截listById方法原始参数:[1001]正在执行listById方法:id = 1001原始返回值:456结束拦截listById方法正在执行deleteByName方法:name = XiaoMing

从输出结果可以看到,UserDaoImpl中的listAll方法和listById方法都被增强了,相应的信息也打印出来了,而deleteByName方法没有被增强。

下面将介绍ByxAOP的设计。

MethodInterceptor接口

首先来介绍一下MethodInterceptor接口,它是ByxAOP中的核心接口之一。

MethodInterceptor即方法拦截器,是对方法拦截过程的封装,它的定义如下:

public interface MethodInterceptor{ Object intercept(MethodSignature signature, Invokable targetMethod, Object[] params);}

当目标方法被拦截时,intercept方法将会被调用,同时传入一些目标方法的相关信息。intercept方法的返回值将作为代理方法的返回值。

  • signature是目标方法签名,用于在拦截时获取目标方法的签名信息。

    signatureMethodSignature接口的实现类,MethodSignature接口包含下列方法:

    方法

    说明

    getName

    获取方法名

    getReturnType

    获取返回值类型

    getParameterTypes

    获取参数类型

    getAnnotation

    获取方法的指定注解

    getAnnotation

    获取方法上的指定注解

    getAnnotations

    获取方法上的所有注解

    hasAnnotation

    方法是否被某个注解标注

    getParameterAnnotations

    获取方法参数上的注解

    isPublic

    是否为public方法

    isPrivate

    是否为private方法

    isProtected

    是否为protected方法

  • targetMethod是目标方法调用器,用于在拦截时调用目标方法,向目标方法传递参数,以及获取目标方法的返回值
    .........

点赞
收藏
评论区
推荐文章
blmius blmius
3年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
待兔 待兔
4个月前
手写Java HashMap源码
HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程HashMap的使用教程22
Wesley13 Wesley13
3年前
javaWeb
<fontsize5style"lineheight:32px;letterspacing:1px;"<fontcolorred一</font:拦截器:是在面向切面编程的就是在你的service或者一个方法,前调用一个方法,或者在方法后调用一个方法比如动态代理就是拦截器的简单实现,springmvc的aop中的前置通知和后置通知。
Easter79 Easter79
3年前
Spring的两种代理JDK和CGLIB的区别浅谈
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Easter79 Easter79
3年前
Spring的Aop调用当前类的两种方法
我们知道Spring对于AOP实现有两种方法,如果类是接口实现类,则采用JDK动态代理实现AOP。如果类没有实现接口,则采用cglib生成子类做增强,以实现代理类的目的,其实运行时找到的是这个代理类,而不是原类。所以在一个代理类中调用内部的方法,是不是再走AOP逻辑的,那有什么好的方法可以解决这种问题吗?基于上面的思路有两种解决办法方法一:直接从
Stella981 Stella981
3年前
Spring AOP 两种代理 Cglib、JDK
概念AOP:AOP是OOP(面向对象编程)的一种延续,OOP中继承的思想主要是提高代码的重用率,但是继承不能同个类在多个方法的相同位置出现的相同代码的问题JDK动态代理:AOP的一种实现,仅支持实现了接口的类。性能较好Cglib:AOP的一种实现,支持实现了接口的类和没有实现接口的类。对比JDK动态代理性能较差SpringAOP:结
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Easter79 Easter79
3年前
Spring的两种动态代理:Jdk和Cglib 的区别和实现
一、原理区别:java动态代理是利用反射机制生成一个实现代理接口的匿名类,在调用具体方法前调用InvokeHandler来处理。而cglib动态代理是利用asm开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。1、如果目标对象实现了接口,默认情况下会采用JDK的动态代理实现AOP 2、如果目标对象实现了接口,可以
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_