来,带你手撕一个AOP

栏目: Java · 发布时间: 5年前

内容简介:本文主要讲的是如何使用JDK中提供了一个该代理对象的实现类实现了interfaces所指定的系列接口,执行代理对象的每个方法时都会被替换执行

本文主要讲的是如何使用 JDK动态代理 实现简单的AOP。AOP是啥?如果你想在某些方法执行前后插入一些通用的处理,你可以考虑AOP。

预备知识

Proxy

JDK中提供了一个 Proxy 类用于创建动态代理对象的静态方法,如果在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态代理类。 Proxy 提供了下面的方法来创建动态代理实例:

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)

该代理对象的实现类实现了interfaces所指定的系列接口,执行代理对象的每个方法时都会被替换执行 InvocationHandler 对象的 invoke 方法

InvocationHandler

InvocationHandler是一个接口,在创建动态代理实例的时候需要把一个 InvocationHandler 的实现类传进去,那么执行代理对象的每个方法时就会被替换成执行InvocationHandler实现类中的invoke方法,至于这个invoke方法要怎么实现,就由用户自己决定。

反射中Method的invoke()

java.lang.reflect.Method 包中有一个方法

public Object invoke(Object obj, Object... args)

该方法可以实现对象方法的调用,它是 Method 类的实例方法,该方法中的参数 obj 是调用方法的对象, args 是用于方法调用的参数。

实现过程

Pig接口,就定义了两个方法

public interface Pig {

    void info();

    void run();
}
复制代码

Pig的实现类,我们要做的就是在这两个方法执行的前后插入自己一些额外的操作

public class FatPig implements Pig {

    @Override
    public void info() {
        System.out.println("我是一头小肥猪!");
    }

    @Override
    public void run() {
        System.out.println("我要跑步啦!");
    }
}
复制代码

LogUtils,需要在代理对象方法执行前后调用的方法

public class LogUtils {

    public void before() {
        System.out.println("==== 方法开始执行 ====");
    }

    public void after() {
        System.out.println("==== 方法执行结束 ====");
    }

}
复制代码

PigInvocationHandler,该类实现了InvocationHandler接口。我们定义了一个Object类型的实例变量,因为我们需要在invoke方法中调用被代理对象的实现类的对应的方法。在invoke方法中,有两个关键的参数: method 代表正在执行的方法, args 代表调用目标方法时传入的实参。然后我们就可以在执行代理对象的方法前后自由插入自己的方法了。

public class PigInvocationHandler implements InvocationHandler {

    // 需要被代理的对象
    private Object target;

    public void setTarget(Object target) {
        this.target = target;
    }

    // 执行动态代理对象的所有方法时,都会被替换成执行如下的invoke方法
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        LogUtils logUtils = new LogUtils();
        // 执行logUtils对象中的before方法
        logUtils.before();
        // 以target作为主调来执行method方法
        Object result = method.invoke(target, args);
        // 执行logUtils对象中的after方法
        logUtils.after();
        return result;
    }
}
复制代码

测试类

public class MyProxyFactory {

    // 为指定的target生成动态代理对象
    public static Object getProxy(Object target) {
        PigInvocationHandler handler = new PigInvocationHandler();
        // 为handler设置target对象
        handler.setTarget(target);
        // 创建并返回一个动态代理
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);
    }

    public static void main(String[] args) throws Exception {
        // 创建一个原始的FatPig对象,作为target
        Pig target = new FatPig();
        // 以指定的target来创建动态代理对象
        Pig pig = (Pig) MyProxyFactory.getProxy(target);
        pig.info();
        pig.run();
    }
}
复制代码

运行结果:

==== 方法开始执行 ====

我是一头小肥猪!

==== 方法执行结束 ====

==== 方法开始执行 ====

我要跑步啦!

==== 方法执行结束 ====

上面实现了简单的AOP功能,我们可以在invoke方法里面加上更多的判断,使得功能更加强大,例如可以根据method参数指定某些方法前后执行特殊的处理。


以上所述就是小编给大家介绍的《来,带你手撕一个AOP》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

软件测试的艺术

软件测试的艺术

梅尔斯 / 机械工业出版社 / 2006年01月 / 22.0

《软件测试的艺术》(原书第2版)成功、有效地进行软件测试的实用策略和技术:    基本的测试原理和策略      验收测试    程序检查和走查         安装测试    代码检查            模块(单元)测试    错误列表            测试规划与控制    同行评分            独立测试机构    黑盒、白盒测试    ......一起来看看 《软件测试的艺术》 这本书的介绍吧!

Base64 编码/解码
Base64 编码/解码

Base64 编码/解码

正则表达式在线测试
正则表达式在线测试

正则表达式在线测试

HEX CMYK 转换工具
HEX CMYK 转换工具

HEX CMYK 互转工具