【java】结合工厂设计模式,利用反射实现动态代理设计

9 篇文章 0 订阅
6 篇文章 0 订阅

关键字:InvocationHandler(接口)、Proxy(类)、reflect;

如果有N个接口需要使用代理类来完成一些辅助的操作,而这些辅助功能又很相似,此时希望有一个代理类,能满足N多不同接口的代理处理,而不是具体针对某一个接口,这样就需要使用动态代理来实现。

要实现动态代理的类,必须实现java.lang.reflect.InvocationHandler接口(其中只包含有一个invoke()方法),并需要java.lang.reflect.Proxy类中的newProxyInstance()方法来实现真实业务与代理对象的绑定。

新增了一个工厂类来完成接口的虚拟代理对象的实例化工作,客户端需要传入的是代理类和真是业务类的名称。

简单的功能(以打印为例)实现如下:

package com.java.demo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

interface ISubject{	//核心接口
	public void eat(String food,int amount);
}

class RealSubject implements ISubject{	//真实业务
	@Override
	public void eat(String food,int amount) {
		System.out.println("我要吃"+amount+"份量的"+food+"!");
	}
	public void fun() {
		System.out.println("其他工作");
	}
}

interface IWork{	//核心接口
	public void wash();
}
class RealWork implements IWork{	//真实业务
	@Override
	public void wash() {
		System.out.println("开始洗澡!");
	}
}
class RealWorkOther implements IWork{	//真实业务
	@Override
	public void wash() {
		System.out.println("开始洗碗!");
	}
}

class ProxySubject implements InvocationHandler{//动态代理类
	private Object target;	//(真实业务)需要绑定任意接口对象,用Object描述
	public ProxySubject() {}
	public void prepare() {
		System.out.println("【PoxySubject】准备工作!");
	}
	public void clear() {
		System.out.println("【PoxySubject】清理工作!");
	}
	
	/**
	 * 实现真实对象的绑定处理,同时返回代理对象
	 * @param target 需要被绑定的真实对象
	 * @return 返回代理对象
	 */
	public Object bind(Object target) {
		this.target = target;	//必须手动保存真实主题对象
		return Proxy.newProxyInstance(this.target.getClass().getClassLoader(),this.target.getClass().getInterfaces(),this);
	}
	
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("【proxyclass】"+proxy.getClass());	//仅作观察用
		System.out.println("【method】"+method);	//仅作观察用
		System.out.println("【arg】"+Arrays.toString(args));	//仅作观察用
		System.out.println("-------------------------------------------------------------------");
		prepare();
		Object result = method.invoke(this.target,args);
		clear();
		return result;
	}
}

class Factory{	//工厂类
	private Factory() {}
	/**
	 * 产生被代理类(接口)的虚拟实例化代理对象
	 * @param proxySubjectName 代理类名字
	 * @param realObjectName 真实业务类名字
	 * @return 被代理接口的虚拟代理类实例化对象
	 */
	public static Object getInstance(String proxySubjectName,String realObjectName){
		Object rInstance,pInstance,resultInstance = null;
		Method bindMethod = null;
		try {
			rInstance = Class.forName(realObjectName).newInstance();
			Class<?> p = Class.forName(proxySubjectName);
			pInstance = p.newInstance();
			bindMethod = p.getMethod("bind", Object.class);
			//反射调用bind()方法,实现真实对象的绑定处理,同时返回代理对象
			resultInstance = bindMethod.invoke(pInstance, rInstance);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return resultInstance;
	} 
}

public class TestDemo {
	public static void main(String[] args){
		ISubject subject = (ISubject) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealSubject");
		subject.eat("苹果", 21);
		System.out.println("===============================分割线===============================");
		IWork work = (IWork) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealWork");
		work.wash();
		System.out.println("===============================分割线===============================");
		IWork work2 = (IWork) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealWorkOther");
		work2.wash();
	}
}

运行结果为:

为了观察加入如下代码:

ISubject subject = (ISubject) Factory.getInstance("com.java.demo.ProxySubject", "com.java.demo.RealSubject");
System.out.println(subject.getClass());

输出结果:

class com.java.demo.$Proxy0


一些问题:

  • 同一核心接口,不同真实业务子类,所生成的虚拟代理对象属于同一个类(如:ISubject的为$Proxy0,IWork的为$Proxy1),虚拟代理类命名规则:$+Proxy+数字,此类存在于JVM中,可用代码写入到磁盘中观察;
  • 实现的InvocationHandler接口的invoke()方法中接收的Object Proxy,是Proxy类newProxyInstance()自动生成的虚拟代理类对象(???),那么invoke()方法又是何时被接收参数并被调用的呢?

回答:

因为学习才入门还不够深入,看源码时有些被绕的有点懵,通过查看网络资料大概了解到:

原文链接点击打开链接

https://blog.csdn.net/wang_1997/article/details/52450549

以下为摘要:

Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)做了以下几件事. 
根据参数loader和interfaces调用方法 getProxyClass(loader, interfaces)创建代理类$Proxy0.$Proxy0类 实现了interfaces的接口,并继承了Proxy类. 

实例化$Proxy0并在构造方法中把DynamicSubject传过去,接着$Proxy0调用父类Proxy的构造器,为h赋值。

  1. class Proxy{    
  2.     InvocationHandler h=null;    
  3.     protected Proxy(InvocationHandler h) {    
  4.         this.h = h;    
  5.     }    
  6.     ...    
  7. }  

接着把得到的$Proxy0实例强制转换成Subject,并将引用赋给subject。当执行subject.request()(request()代表的是在客户端调用的那个方法)方法时,就调用了$Proxy0类中的request()方法,进而调用父类Proxy中的h的invoke()方法.即InvocationHandler.invoke()。

  1. public final class $Proxy0 extends Proxy implements Subject {    
  2.     private static Method m1;    
  3.     private static Method m0;    
  4.     private static Method m3;    
  5.     private static Method m2;    
  6.     
  7.     static {    
  8.         try {    
  9.             m1 = Class.forName("java.lang.Object").getMethod("equals",    
  10.                     new Class[] { Class.forName("java.lang.Object") });    
  11.     
  12.             m0 = Class.forName("java.lang.Object").getMethod("hashCode",    
  13.                     new Class[0]);    
  14.     
  15.             m3 = Class.forName("***.RealSubject").getMethod("request",    
  16.                     new Class[0]);    
  17.     
  18.             m2 = Class.forName("java.lang.Object").getMethod("toString",    
  19.                     new Class[0]);    
  20.     
  21.         } catch (NoSuchMethodException nosuchmethodexception) {    
  22.             throw new NoSuchMethodError(nosuchmethodexception.getMessage());    
  23.         } catch (ClassNotFoundException classnotfoundexception) {    
  24.             throw new NoClassDefFoundError(classnotfoundexception.getMessage());    
  25.         }    
  26.     } //static    
  27.     
  28.     public $Proxy0(InvocationHandler invocationhandler) {    
  29.         super(invocationhandler);    
  30.     }    
  31.     
  32.     @Override    
  33.     public final boolean equals(Object obj) {    
  34.         try {    
  35.             return ((Boolean) super.h.invoke(this, m1, new Object[] { obj })) .booleanValue();    
  36.         } catch (Throwable throwable) {    
  37.             throw new UndeclaredThrowableException(throwable);    
  38.         }    
  39.     }    
  40.     
  41.     @Override    
  42.     public final int hashCode() {    
  43.         try {    
  44.             return ((Integer) super.h.invoke(this, m0, null)).intValue();    
  45.         } catch (Throwable throwable) {    
  46.             throw new UndeclaredThrowableException(throwable);    
  47.         }    
  48.     }    
  49.     
  50.     public final void request() {    
  51.         try {    
  52.             super.h.invoke(this, m3, null);    
  53.             return;    
  54.         } catch (Error e) {    
  55.         } catch (Throwable throwable) {    
  56.             throw new UndeclaredThrowableException(throwable);    
  57.         }    
  58.     }    
  59.     
  60.     @Override    
  61.     public final String toString() {    
  62.         try {    
  63.             return (String) super.h.invoke(this, m2, null);    
  64.         } catch (Throwable throwable) {    
  65.             throw new UndeclaredThrowableException(throwable);    
  66.         }    
  67.     }    
  68. }    
从$Proxy0的源码可以看出,动态代理类不仅代理了显示定义的接口中的方法,而且还代理了java的根类Object中的继承而来的equals()、hashcode()、toString()这三个方法,并且仅此三个方法。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值