欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java SE 066 Java动态代理模式详解

程序员文章站 2022-06-09 20:53:20
...

(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,,Proxy0, 这个类是在运行期间动态生成的一个类,也就是说我们生成的实例是Proxy0这个类的一个实例
(5)那么生成的这个类,它有哪些特点呢?
(a)它实现了realSubject.getClass().getInterfaces() ,这些接口.即realSubject所实现的那些接口。
(b)realSubject实现了哪些接口呢?
实现了Subject接口,生成的那个类($Proxy0)就实现了realSubject实现的接口,因此就可以强制转换为接口类型。因此语句中的强制转换是没问题的。