动态代理个人理解

动态代理个人理解

首先为什么要用动态代理?
  1. 动态代理是设计模式中的代理模式:

    定义:为其它对象提供一种代理以控制对这个对象的访问控制;在某些情况下,客户不想或者不能直接引用另一个对象,这时候代理对象可以在客户端和目标对象之间起到中介的作用。

  2. 动态代理的作用
    主要用来做方法的增强,让你可以在不修改源码(指愿方法)的情况下,增强一些方法,在方法执行前后做任何你想做的事情(甚至根本不去执行这个方法),因为在InvocationHandler的invoke方法中,你可以直接获取正在调用方法对应的Method对象,具体应用的话,比如可以添加调用日志,做事务控制等。

前提条件:

要实现代理,逻辑类必须去实现InvocationHandler接口,(1.建立代理对象和真实对象的关系,2.实现代理逻辑方法,真正的核心都在这个invoke()方法里)。

静态代理与动态代理的区别
静态代理

静态代理类:由程序员创建或者由第三方工具生成,再进行编译;在程序运行之前,代理类的.class文件已经存在了。

静态代理类通常只代理一个类。

静态代理事先知道要代理的是什么。

动态代理

动态代理类:在程序运行时,通过反射机制动态生成。

动态代理类通常代理接口下的所有类。

动态代理事先不知道要代理的是什么,只有在运行的时候才能确定。

动态代理的调用处理程序必须实现InvocationHandler接口,及使用Proxy类中的newProxyInstance方法动态的创建代理类。

Java动态代理只能代理接口,要代理类需要使用第三方的CLIGB等类库。

动态代理实现中的关键点解释

存在一个接口和实现类

public interface Subject {   

  public void doSomething();   

}  

public class RealSubject implements Subject {   

  public void doSomething(){   
   System.out.println( "call doSomething()" );   
  }   

}   

动态代理绑定和代理逻辑实现

public class MyInvocationHandler implements InvocationHandler  {private Object obj;//这是动态代理的好处,被封装的对象是Object类型,接受任意类型的对象  public MyInvocationHandler(){
	}public MyInvocationHandler(Object obj){this.obj = obj;}  

	//建立代理对象和真实对象的代理关系,返回代理对象
	Public Object bind(Object obj){
		This.obj = obj;
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(),obj.getClass().getInterfaces(),this) ;
	}

//参数说明:类加载器和接口用于在Proxy类中获得代理类使用,处理器用于在Proxy类中通过构造方法的形式创建对象时使用。//这个方法不是我们显示的去调用  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{  
​        System.out.println("before calling " + method);  
​        method.invoke(obj, args);  
​        System.out.println("after calling " + method);return null;}  
}  

这里的invoke()方法中的第一个参数,也就是代理实例作用

  1. 可以使用反射获取代理对象的信息(也就是proxy.getClass().getName())。
  2. 可以将代理对象返回以进行连续调用,这就是proxy存在的目的,因为this并不是代理对象。
    补充:Method 类的invoke()方法传参就是1:对象,2:形参(方法可能重构了许多,根据参数指定方法)

客户端:生成代理实例,并调用了doSomething()方法

public class Client {public static void main(String[] args) throws Throwable{  
​        Subject rs=new RealSubject();//这里指定被代理类  
​        InvocationHandler ds=new MyInvocationHandler ();  
​      	Subject proxy = (Subject)ds.bind(rs);//返回代理对象
​        proxy .doSomeThing();  //调用方法}  
}  

上面的bind()方法中Proxy.newProxyInstance()方法最为关键

在此方法中有如下几步

  1. 生成动态代理类,此类命名为$Proxy+数字,在生成这个类时,会先在缓存中查看此类是不是已经存在,存在直接返回,不存在就创建一个,简单说明一下有源码可以看,大概就是这样。

    Class<?> cl = getProxyClass0(loader, intfs);

  2. 创建代理类的实例(对象),通过反射创建一个类的实例有两种方法

    (1) Class.forName(“类名”).newInstance() ;//调用无参构造创建对象

    (2) Class.getConstructor(“参数”).newInstance();//调用有参构造创建对象

    Proxy.newProxyInstance()方法用的是第二种。

return (Object) cons.newInstance(new Object[] { h });//这里就已经创建了一个动态代理类实例。

在客户端中代理类对象有了,就可以直接调用接口中的方法了,这个方法是被重写的,我们来看看那个动态生成的代理类。

public final class $Proxy0 extends Proxy implements Subject{  
    private static Method m1;  
    private static Method m0;  
    private static Method m3;  
    private static Method m2;  
    //静态块
    static {  
        try {       
        m1=Class.forName("java.lang.Object").getMethod("equals",  new Class[] { Class.forName("java.lang.Object") });  

        m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);  

		m3=Class.forName("***.RealSubject").getMethod("doSomething", new Class[0]);  

		m2 = Class.forName("java.lang.Object").getMethod("toString",   new Class[0]);  
        } catch (NoSuchMethodException nosuchmethodexception) {  
            throw new NoSuchMethodError(nosuchmethodexception.getMessage());  
        } catch (ClassNotFoundException classnotfoundexception) {  
            throw new NoClassDefFoundError(classnotfoundexception.getMessage());  
        }  
    }  
	//构造方法
    public $Proxy0(InvocationHandler invocationhandler) {  
        super(invocationhandler);  
    }  
	//重写equal方法
    @Override  
    public final boolean equals(Object obj) {  
        try {  
            return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

	//重写hashcode方法
    @Override  
    public final int hashCode() {  
        try {  
            return ((Integer) super.h.invoke(this, m0, null)).intValue();  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

	//这个是关键部分,动态代理对象中重写接口中的方法
	@Override
    public final void doSomething() {  
        try {  
            super.h.invoke(this, m3, null); 
            return;  
        } catch (Error e) {  
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  

	//重写toString方法
    @Override  
    public final String toString() {  
        try {  
            return (String) super.h.invoke(this, m2, null); 
        } catch (Throwable throwable) {  
            throw new UndeclaredThrowableException(throwable);  
        }  
    }  
}  

这个动态代理类有如下特点,他会重写实现接口中的所有方法,并且重写equals(),hashCode(),toString()仅此三个方法。

接着把得到的 P r o x y 0 实 例 强 制 转 换 成 S u b j e c t , 并 将 引 用 赋 给 s u b j e c t 。 当 执 行 s u b j e c t . d o S o m e t h i n g ( ) 方 法 时 , 就 调 用 了 Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.doSomething()方法时,就调用了 Proxy0Subjectsubjectsubject.doSomething()Proxy0类中的doSomething()方法,进而调用父类Proxy中的h的invoke()方法.即MyInvocationHandler.invoke(),为什么当执行super.h.invoke()方法时,就调用了咱们自己写的那个MyInvocationHandler中的invoke()方法,因为$Proxy0在创建对象时调用的是有参构造,而这个代理类的有参构造中是super(invocationhandler),而这个invocationHandler是在Proxy.newProxyInstance()时就传进来的自己写的那个调用处理器,此时Proxy类中的成员InvocationHandler h,就会被赋值为自己写的那个调用处理器,于是在执行super.h.invoke()方法时,实际就是在执行自己写的那个调用处理器。

一个典型的动态代理创建对象过程可分为以下四个步骤:
  1. 通过实现InvocationHandler接口创建自己的调用处理器 IvocationHandler handler = new InvocationHandlerImpl(…);
  2. 通过为Proxy类指定ClassLoader对象和一组interface创建动态代理类
    Class clazz = Proxy.getProxyClass(classLoader,new Class[]{…});
  3. 通过反射机制获取动态代理类的构造函数,其参数类型是调用处理器接口类型
    Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
  4. 通过构造函数创建代理类实例,此时需将调用处理器对象作为参数被传入
    Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
    为了简化对象创建过程,Proxy类中的newInstance方法封装了2~4,只需两步即可完成代理对象的创建。
    生成的ProxySubject继承Proxy类实现Subject接口,实现的Subject的方法实际调用处理器的invoke方法,而invoke方法利用反射调用的是被代理对象的的方法(Object result=method.invoke(proxied,args))
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值