动态代理的理解

动态代理的理解

什么是代理?

代理主要实现被代理类的增强处理,在不修改源码的基础上,对原有代码进行一个封装,进一步实现某些增强功能。

代理分为静态代理和动态代理

静态代理:

代理类实现被代理类的接口,在代理类中实例化被代理类,生成一个被代理类对象,重写方法A以实现增强功能,同时在代理类的方法A中,实际是调用了被代理类对象的方法A实现的。

静态代理有一个缺点,即,如果有很多被代理类,则需要生成对应多的代理类对象,难以实现。于是就有了动态代理:

动态代理:

静态代理的过程:被代理类Class→被代理类对象→代理类→代理类对象

假如此时有很多被代理类,而我们主要是为了避免写过多代理类,那么现在的考虑方向为,如何不写代理类,而直接获得代理对象?

不通过类来产生实例,想到可以通过反射来实现。创建实例,需要提供Class对象,如何去获取class对象呢?

这里搁置一个问题,为什么不能直接从被代理类中获取实例化代理对象所需要的信息?

我们知道代理类和被代理类实现同一个接口,因此可以从这个接口中获得相关信息

具体的可以通过两种方法:

​ 1.Proxy类的getProxyClass();然后调用其Constructor对象来进行实例化

​ 2.Proxy类的newProxyInstance();

具体如下:

首先,依旧是之前的接口类和被代理类。我们创建一个PersonInterface接口,其中声明一个say()方法,并用Student来实现并重写say()方法:

public interface PersonInterface {
    public void say();
}
public class Student implements PersonInterface{
    @Override
    public void say(){
        System.out.println("start Student.say()");
        System.out.println("imStudent");
        System.out.println("end Student.say()");
    }
}

say()中打印的语句为了后面显示其中的调用结构

随后不创建代理类,而是创建一个handler类。handler类的作用就是进行动态代理调度的。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class ProxyHandler01 implements InvocationHandler {
//    这里的object为待传入的被代理类对象
    Object object;
    public ProxyHandler01(Object object){
        this.object = object;
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("start ProxyHandler's invoke");
        System.out.println(method.getName());
        method.invoke(object,args);
        System.out.println("end ProxyHandler's invoke");
        return null;
    }

}

先暂时不管这个handler中的invoke()方法的参数,先看一下main中动态代理是如何实现的:

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;


public class Test {
    public static void main(String args[]){
//        System.getProperties().setProperty("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

        PersonInterface st = new Student();
        InvocationHandler ph = new ProxyHandler01(st);

        PersonInterface proxyStudent = (PersonInterface) Proxy.newProxyInstance(
            st.getClass().getClassLoader(),
            st.getClass().getInterfaces(), 
            ph);
        System.out.println("start proxyStudent.say()");
        proxyStudent.say();
        System.out.println("end proxyStudent.say()");

    }
}

首先创建一个Strudent对象st并声明为PersonInterface;

再创建一个hander对象,并声明为InvocationHandler,同时将st作为参数传入构造函数中,进入handler对象中,st作为handler对象的一个Field存在;

(这里之所以都用接口声明是为体现同一接口下相同的特质;)

然后调用Proxy的newProxyInstance()创建代理实例,其中第一个参数st.getClass().getClassLoader()获取了Student类的类加载器,第二个参数st.getClass().getInterfaces()返回Student类所实现的接口列表,第三个参数ph为一个handler实例,而这个handler实例中封装了st对象。

因此可以认为,Proxy.newProxyInstance()方法通过被代理类加载器,接口信息,st实例对象创建了一个代理实例proxyStudent,调用其say()方法,可以看到输出结果为:

/** 输出结果:
 * start proxyStudent.say()
 * start ProxyHandler's invoke
 * start student.say()
 * imStudent
 * end student.say()
 * end ProxyHandler's invoke
 * end proxyStudent.say()
 */

说明,proxyStudent.say()中嵌套了一个handler.invoke()中嵌套了Student.say(),

handler.invoke()相当于proxyStudent.say和Student.say中间的桥梁

handler.invoke内部实际上是调用method.invoke实现的,

handler.invoke的参数为(object,method,object[]),其中这个object就是传入的Student实例st,object[]是接口列表,而这个method对象就是st的say方法,可见代理类实例化所需要的信息都封装在其中了。

调用代理对象proxyStudent的say()方法,内部会调用ph的invoke()方法,而invoke的方法传入method参数调用st的say方法,以此完成代理功能。由于其中的st的say方法嵌套在invoke中,因此可以在invoke中进行编写增强功能代码。

在这里插入图片描述

如果此时还有另一个被代理类,只需在main方法中new一个该被代理类对象,然后传参到newProxyInstance中即可实例化对应的代理类。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值