来,带你手撕一个AOP

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

内容简介:本文主要讲的是如何使用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》,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对 码农网 的支持!

查看所有标签

猜你喜欢:

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

The Master Switch

The Master Switch

Tim Wu / Knopf / 2010-11-2 / USD 27.95

In this age of an open Internet, it is easy to forget that every American information industry, beginning with the telephone, has eventually been taken captive by some ruthless monopoly or cartel. Wit......一起来看看 《The Master Switch》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

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

Base64 编码/解码

MD5 加密
MD5 加密

MD5 加密工具