动态代理入门必看

基本介绍

代理

就是让代理角色帮助真实角色完成一件事情。比如说,我叫我们朋友帮我完成博客,那么这个朋友就是代理,朋友不是我,但是和我完成同样的事,并且还可以对这件事加入他的行为逻辑。
不论是什么代理方法,其根本目的就是为了拓展一个类的方法,也就是想要加入自己的行为逻辑。
当然,我们可以直接修改类的方法,但是一旦类的方法多了起来,就会造成代码的冗余,而且极难进行维护。

静态代理

静态代理相当于是多写了一个代理类,在调用的时候调用的是代理类,在代理类中的处理还是原生的处理逻辑,不过在前后添加上需要添加的代码。
其最根本的特征就是这个代理类需要程序员自己写出来。即在编译阶段就确定了代理对象是谁。

实例说明:

我们编写如下的测试案例:

public class StaticProxyTest {  
    @Test  
    public void Test01() {  
        Vehicle proxyForCar = new ProxyForCar(new Car());  
        proxyForCar.run("托马斯");  
        proxyForCar.fly("托马斯");  
    }  
}

编写接口:

public interface Vehicle {  
    public void run(String s);  
  
    public void fly(String s);  
}

解读:

  • 这里编写接口纯粹是为了符合模板设计模式,没有其他的原因;
  • 这样就可以让代理对象调用原类的方法,不会造成原类的浪费。最大限度的保存原类的功能;
    编写实现类:
public class Car implements Vehicle {  
    @Override  
    public void run(String name) {  
        System.out.println(name + "is running");  
    }  
  
    @Override  
    public void fly(String name) {  
        System.out.println(name + "is flying");  
    }  
}

编写代理类:

public class ProxyForCar implements Vehicle {  
    Vehicle vehicle;  
  
    public ProxyForCar(Vehicle vehicle) {  
        this.vehicle = vehicle;  
    }  
  
    @Override  
    public void run(String arg) {  
        System.out.println("before invoke...");  
        vehicle.run(arg);  
        System.out.println("after invoke...");  
    }  
  
    @Override  
    public void fly(String arg) {  
        System.out.println("before invoke...");  
        vehicle.fly(arg);  
        System.out.println("after invoke...");  
    }  
}

以上就是一个简单的静态代理的实现。可以发现缺点是显然的,静态代理无法实现切面编程,一旦我们需要代理一个新的接口方法,就要重新写一个方法,甚至重新写一个代理类,这样的开销成本无疑是很大的。
于是我们引入了动态代理。

动态代理

我们这里将主要介绍基于接口实现的 JDK 的动态代理方式
见名知义,动态即我们不需要在自己写代理类了,而是由 JVM 在运行阶段自动的帮我生成一个代理类,在程序结束的时候自动销毁。优势在于:

  • 可延展性高,便于实现切面编程。可以批量的代理类的方法;
  • 极大的简化了代码工程量;
    接下来,我将简单的演示一下动态代理的实现过程,深入分析我们新开一章单独解决。

实例说明

编写测试案例:

public class DynamicProxyTests {  
    @Test  
    public void Test01() {  
        Car car = new Car();  
        VehicleDynamicProxy vehicleDynamicProxy = new VehicleDynamicProxy(car);  
        Vehicle proxy = vehicleDynamicProxy.getProxy();  
        String fly = proxy.fly(10000);  
        System.out.println("result:\t" + fly);  
    }  
}

编写接口:

public interface Vehicle {  
    public String fly(int height);  
  
    public void run();  
}

实现类 ship :

public class Ship implements Vehicle {  
    @Override  
    public String fly(int height) {  
        System.out.println("wdnmd");  
        return "ship 的高度为" + height;  
    }  
  
    @Override  
    public void run() {  
        System.out.println("ship 在run");  
    }  
}

实现类 Car:

public class Car implements Vehicle{  
    @Override  
    public String fly(int height) {  
        System.out.println("wdnmdCar");  
        return "car 的高度为" + height;  
    }  
  
    @Override  
    public void run() {  
        System.out.println("car 在run");  
    }  
}

动态代理类:

public class VehicleDynamicProxy {  
    /**  
     * 被代理对象  
     */  
    public Vehicle targetVehicle;  
  
    public VehicleDynamicProxy(Vehicle targetVehicle) {  
        this.targetVehicle = targetVehicle;  
    }  
  
    public Vehicle getProxy() {  
        //获取类的加载器  
        ClassLoader classLoader = targetVehicle.getClass().getClassLoader();  
        //获取类的接口数组  
        Class<?>[] interfaces = targetVehicle.getClass().getInterfaces();  
        //调用函数,用来的调用方法  
        InvocationHandler invocationHandler = new InvocationHandler() {  
            @Override  
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {  
                Object result = null;  
                try {  
                    System.out.println("前置通知 before");  
                    //调用被代理对象的方法  
                    result = method.invoke(targetVehicle, args);  
                    System.out.println("返回通知 afterReturning");  
                } catch (Exception e) {  
                    //异常通知 AfterThrowing                    
                    throw new RuntimeException(e);  
                } finally {  
                    //最终通知 After                }  
                return result;  
            }  
        };  
        //此时的proxy对象是实现了Vehicle接口,继承了Proxy类的代理对象  
        Vehicle proxy = (Vehicle) Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);  
        return proxy;  
    }  
}

解读:

  • JVM 何以动态的创建动态数组?从以上的代码可以看出,我们获得了被代理对象的类加载器和接口数组。显然底层是根据反射动态生成代理类,并且创建实例的;
  • 为了实现调用原对象中的方法,在我们调用代理对象的相应方法的时候,一定会利用 InvocationHandler 中进行调用的转发。也就是说,方法的实际调用不在代理对象中,而由 InvocationHandler 转发到了原对象处理;
  • 这样我们就可以在 invoke 方法中实现自己想要拓展的逻辑,在 Spring 中,就有了前置通知,后置通知等切面编程的思想;

总结

  1. 代理:让代理角色帮助真实角色完成任务,如朋友帮忙完成博客。
  2. 代理方法目的:拓展类的方法,加入自己的行为逻辑。
  3. 静态代理:编写代理类,调用时调用代理类,前后添加需要的代码,需要程序员在编译阶段自行编写代理类。
    • 缺点:无法实现切面编程,需要代理新接口方法时需要重新写方法或代理类。
  4. 动态代理:JVM在运行阶段自动生成代理类,程序结束时销毁。
    • 优势:高可延展性,便于实现切面编程,简化代码工程量。
  5. 动态代理实现过程:
    • 获取被代理对象的类加载器和接口数组。
    • 使用InvocationHandler进行调用转发。
    • 实现自己想要拓展的逻辑。

接下来,我们将从源码的角度,详细的看看 JDK 动态代理的机制。
我们再抛出一个问题,那就是为什么在生成代理对象的时候一定要传入接口数组呢?似乎没有接口,我们也可以通过反射,来转发方法的执行。
【源码解析】JDK 动态代理实现 - yelanyanyu - 博客园 (cnblogs.com)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Math210

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值