【Spring 深入学习】AOP的前世今生之代理模式

8 篇文章 0 订阅

AOP的前世今生之代理模式

1. 概述

什么是代理模式呢???

在不修改原有代码 或是 无法修改原有代码的情况下,增强对象功能,替代原来的对象去完成功能,从而达成了拓展的目的。

先给大家看下 JavaScript中实现方式

直接代理window.open函数,在调用window.open之前之后做一些事情

const open = window.open;
window.open = function(...args) {
	// before todo
	open.call(null, ...args);
	// after todo
}

接下来我们看下Java中是如何实现的???

  • JDK 动态代理

    JDK Proxy 动态代理面向接口的动态代理 一定要有接口和实现类的存在 代理对象增强的是实现类 在实现接口的方法重写的方法生成的代理对象只能转换成 接口的不能转换成 被代理类

  • gclib 动态代理

    面向父类进行动态代理

2. JDK 动态代理

接口定义

public interface Animal {
    void eat();
    void say();
}

实现类定义

public class Cat implements Animal {
    @Override
    public void eat() {
        System.out.println("猫要吃饭了");
    }

    @Override
    public void say() {
        System.out.println("有一个动物 开始说话了");
    }
}

接下来我们有一个需求,我要代理eat方法,但是不代理say方法。在执行eat方法之前之后 都要执行对应的逻辑。

public class TestJdkProxy {

    @Test
    public void testJdkProxy() {
        Animal cat = new Cat();
        /**
         * ClassLoader loader => 通过实例获取Class。 再通过Class来获取对应的loader
         * Class<?>[] interfaces => 通过实例获取Class。 再通过Class来获取定义的接口
         * InvocationHandler h
         */
        Animal animal = (Animal) Proxy.newProxyInstance(cat.getClass().getClassLoader(), cat.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                /**
                 * proxy 被代理的对象
                 * method 代理的方法
                 * args 代理传递的参数
                 */
                Object o;
                if (method.getName() == "eat") {
                    System.out.println("start ----------------");
                    o = method.invoke(cat, args);
                    System.out.println("end   ----------------");
                } else {
                    o = method.invoke(cat, args);
                }
                return o;
            }
        });

        animal.eat();
        animal.say();
    }
}
  1. 通过代码Proxy.newProxyInstance 来获取代理后的实例,我们后续调用方法eat, say 都是基于代理对象的
  2. 需要获取getClassLoader, getInterfaces 我们都可以通过实例.getClass() 来获取
  3. 最重要的就是要实现接口InvocationHandler. 我们一切行为都是基于接口中invoke的方法。

其实JDK 动态代理核心在于:代理实现类,所以我们在接口中所有需要重写的方法都会被代理,然后我们调用的方法就是代理的方法(其实就是方法invoke)

3. gclib 动态代理

gclib动态代理 是基于父类来进行动态代理的。其实就是在运行时生成子类,继承提供的父类。 而我们其实我们手动调用的方法是子类的方法,调用时调用父类方法,从而实现代理。

代码实现逻辑

public class TestCgLib {

    @Test
    public void testCglib() {
        Person person = new Person();

        // 1. 获取Enhancer 对象
        Enhancer enhancer = new Enhancer();
        // 2. 设置父类字节码
        enhancer.setSuperclass(person.getClass());
        // 3. 获取MethodInterceptor对象 用于定义增强规则
        MethodInterceptor methodInterceptor = new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                /**
                 * Object o 生成之后的代理对象
                 * Method method 父类中原本要执行的方法
                 * Object[] objects 传递的参数对象
                 * MethodProxy methodProxy 生成的代理的子类
                 */
                Object res;
                if ("eat".equals(method.getName())) {
                    System.out.println("准备开始吃饭...");
                    res = methodProxy.invokeSuper(o, objects);
                    System.out.println("已经吃饭结束...");
                } else {
                    res = methodProxy.invokeSuper(o, objects);
                }
                return res;
            }
        };
        // 4. 设置执行代理回调函数
        enhancer.setCallback(methodInterceptor);
        // 5. 获取代理对象
        Person person1 = (Person) enhancer.create();
        person1.eat();
        person1.say();
    }
}

4. 结论

代理模式是学习AOP的基础,所以理解代理模式的作业方式还是很重要的。Demo源码位置

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值