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

(1)一个人只要自己不放弃自己,整个世界也不会放弃你.
(2)天生我才必有大用
(3)不能忍受学习之苦就一定要忍受生活之苦,这是多么痛苦而深刻的领悟.
(4)做难事必有所得
(5)精神乃真正的刀锋
(6)战胜对手有两次,第一次在内心中.
(7)编写实属不易,若喜欢或者对你有帮助记得点赞+关注或者收藏哦~

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

文章目录

  • Java SE 066 Java动态代理模式详解
    • 1.动态代理
      • 1.1Java动态代理类
        • 1.1.1 InvocationHandler接口
          • 1.1.1.1invoke方法
          • 1.1.1.2调用处理器
        • 1.1.2 Proxy动态代理类
    • 2.动态代理类
      • 2.1Proxy
      • 2.2所谓Dynamic Proxy是这样一种class
    • 3.动态代理实践
      • 3.1定义抽象角色类
      • 3.2定义真实角色
      • 3.3定义动态代理类
      • 3.4测试动态代理
    • 4.使用动态代理需要注意的两个地方
      • 4.1一定要实现InvocationHandler接口
      • 4.2newProxyInstance方法

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

你可能感兴趣的:(【01】java基础深入浅出)