Java SE 066 Java动态代理模式详解
(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~
Java SE 066 Java动态代理模式详解
文章目录
1.动态代理
1.1Java动态代理类
Java动态代理类位于java.lang.reflect包下,一般主要涉及到以下两个类:
1.1.1 InvocationHandler接口
1.1.1.1invoke方法
Interface InvocationHandler:该接口中定义了一个方法
public Object invoke(Object obj,Method method,Object[] args)
在实际使用时,
(a)第一个参数obj一般指代理类,
(b)method是被代理的方法,如上例中的request()方法。
(c)args为该方法的参数数组。这个抽象方法在代理类中动态实现。
1.1.1.2调用处理器
每一个代理实例都会有一个与之关联的调用处理器,当我们调用某一个代理实例的某一个方法的时候,这个方法调用就会被编码,并且被派发到它的调用处理器的invoke方法上。
参数1:obj表示invoke方法是调用哪一个代理实例的方法。
参数2: method对应于代理实例上的接口方法。
参数3:args表示接口方法所需要接收的参数数组。
1.1.2 Proxy动态代理类
作用类似于上例中的ProxySubject,其中主要包含以下内容:
(1)用于创建动态代理类,它是动态代理类的父类。也就是说我们自己创建的动态代理类是Proxy类的一个子类。
(2)每一个代理实例都会有一个与之关联的InvocationHandler实例,这个实例是存在代理这个对象内部的,这样的话才能实现关联。
(3)protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。
(4)static Class getProxyClass(Classloader loader,Class[] interface)
2.动态代理类
2.1Proxy
(1)protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。
(2)static Class getProxyClass(ClassLoader loader,Class[] interfaces),获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。
(3)static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的Subject接口中声明的方法),即返回一个包装过的真实对象。
(4)newProxyInstance()方法生成的是一个代理对象,这个代理对象可以模拟真实对象的操作。还可以增加自己的一些额外的一些操作。
2.2所谓Dynamic Proxy是这样一种class
(1)它是运行时生成的class,在生成时必须提供一个interface,也就是说这些class是在运行时创建出来的,而并不是事先定义好的
(2)然后该class就宣称它实现了这些interface。
(3)你当然可以把该class的实例当作这些interface中的任何一个使用。
public class Test implements A,B,C{
public static main(String[] args){
A a = new Test();
B b = new Test();
C c = new Test();
}
}
多态的思想,Test类实现了一些接口,根据多态,可以把类(Test)的实例a 当作接口A,B,C中的任何一个使用。
(4)当然,Dynamic Proxy其实就是一个Proxy,它不会为你做任何实值性的工作。在生成它的实例时,你必须提供一个handler,,由它接管实际工作。
(5)在使用动态代理类的时,必须实现InvocationHandler接口
3.动态代理实践
3.1定义抽象角色类
public interface Subject {
public void request();
}
3.2定义真实角色
package com.javase.dynamicproxy;
/**
* 真实角色
* @author x_xiongjie
*
*/
public class RealSubject implements Subject{
@Override
public void request() {
System.out.println("From real subject");
}
}
3.3定义动态代理类
package com.javase.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 动态代理类
* @author x_xiongjie
* 该代理类的内部属性是Object类型,实际使用的时候通过该类的构造方法传递进来一个对象,此外,该类还实现了
* invoke方法,该方法中的method.invoke其实就是调用被代理对象的将要执行的方法,方法参数是sub,
* 表示该方法从属于sub,通过动态代理类,我们可以在执行真实对象的方法前后加入自己的一些额外方法。
*
*/
public class DynamicSubject implements InvocationHandler {
/**
* 真实角色的一个引用 因为这是一个动态代理,它可以代理任意的一个对象,并不仅仅代理RealSubject,
* 因此在这里直接写RealSubject很受限制。若传一个Object,则会变得比较通用了。
*/
private Object sub;
public DynamicSubject(Object obj){
this.sub = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("before calling: " + method);
method.invoke(sub, args);
System.out.println("after calling: " + method );
return null;
}
}
3.4测试动态代理
package com.javase.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
RealSubject realSubject = new RealSubject();
InvocationHandler invocationHandler = new DynamicSubject(realSubject);
Class<?> clasType = invocationHandler.getClass();
Subject subject = (Subject)Proxy.newProxyInstance(clasType.getClassLoader(),realSubject.getClass().getInterfaces() , invocationHandler);
subject.request();
System.out.println(subject.getClass());
}
}
4.使用动态代理需要注意的两个地方
4.1一定要实现InvocationHandler接口
(1)一定要实现InvocationHandler接口
(2)这个干嘛用的呢,是用于传给Proxy,作为Proxy.newInstance()这个方法的最后一个参数。
(3)当我通过它在运行时生成一个实例的时候,那么实例调request方法,就转移给invocationHandler去接管了,就转而去执行代理类中的invoke方法,由invoke方法真正的去完成实际的事情。
4.2newProxyInstance方法
(Subject)Proxy.newProxyInstance(clasType.getClassLoader(),realSubject.getClass().getInterfaces() , invocationHandler);
(1)newProxyInstance方法的说明是,生成一个代理的实例。
(2)代理实例是什么,就是代理对象。
(3)有对象,什么可以称为对象,类可以称作对象,没有类哪来对象呢,我们所生成的这个对象,就是最终强制转化的这个对象(Subject),这个对象它既不是RealSubject实例,也不是DynamicSubject实例。
(4)是哪个类呢,是Proxy0这个类的一个实例
(5)那么生成的这个类,它有哪些特点呢?
(a)它实现了realSubject.getClass().getInterfaces() ,这些接口.即realSubject所实现的那些接口。
(b)realSubject实现了哪些接口呢?
实现了Subject接口,生成的那个类($Proxy0)就实现了realSubject实现的接口,因此就可以强制转换为接口类型。因此语句中的强制转换是没问题的。