仿JDK的动态代理模式

代理模式 : 给某一对象提供代理对象,并由代理对象控制具体对象的引用.

一、代理模式涉及的角色:

(1)抽象主题角色:声明了代理主题和真实主题的公共接口,使任何需要真实主题的地方都能用代理主题代替.

(2)真实代理对象:定义了代理角色所代表的具体对象.

(3)Proxy产生代理主题角色的类,根据不同的主题接口,动态产生加载相应的RealProxy并实现主题接口所定义的抽象方法

(4)InvocationHandler用户自定义需要为真实代理对象代理的处理逻辑

二、动态代理设计模式基本UML类图



接下来附上具体的实现代码附注解


抽象主题类,被代理的目标

package com.hust.edu.dynProxy;
/**
 * 在静态代理中,要对多个类进行代理,就要创建多个代理类,并且随着类的增加,创建的代理类将更多,造成类的数目膨胀,逻辑重复,不维护
 * 
 * 因此,利用Java反射原理,更加优雅的实现代理的一种模式,就是动态代理,让你可以在不修改源码的情况下,增强一些方法,实现代码扩展
 * 
 * Spring框架就是利用这里原理实现AOP编程模式(有兴趣可以研究下)
 * 
 */
/**
 * 抽象主题类,被代理的目标
 */
public interface ISubject {
	
	public void excute();
}

具体主题对象


package com.hust.edu.dynProxy;

/**
 * 具体主题对象
 */
public class RealSubject implements ISubject{

	@Override
	public void excute() {
		System.out.println("do my work.......");
	}
}


InvocationHandler 抽象接口

package com.hust.edu.dynProxy;

import java.lang.reflect.Method;

/**
 * InvocationHandler 抽象接口
 */
public interface InvocationHandler {
	 public void invoke(Object o, Method m);  
}


InvocationHandler 抽象基类

package com.hust.edu.dynProxy;

import java.lang.reflect.Method;

/**
 * InvocationHandler 抽象基类,主要目标是实现多种业务的重叠代理
 * 
 */
public abstract class AbInvocationHandler implements InvocationHandler{

	protected Object target;  
	
	public AbInvocationHandler(Object taObject){
		this.target = taObject;
	}
	
	public void superInvoke(Object object, Method method) {
		try {
			/** 如果目标对象还是InvocationHandler 继续调用InvocationHandler的invoke **/
			if (target instanceof InvocationHandler) {
				((InvocationHandler) target).invoke(object, method);
			} else {
				method.invoke(target);
			}
		} catch (Exception e) {
		}
	}
}


代理实现处理 实现类InvocationHandler的子类

package com.hust.edu.dynProxy;

import java.lang.reflect.Method;
import java.util.Date;

/**
 * 实现目标对象函数的处理时间代理逻辑
 */
public class TimeHandler extends AbInvocationHandler {

	public TimeHandler(Object taObject) {
		super(taObject);
	}
	public void invoke(Object object, Method method) {
		long start = System.currentTimeMillis();  
	    System.out.println("starttime : " + new Date(start));
		superInvoke(object, method);
		long end = System.currentTimeMillis();
		/** 输出目标函数的运行时间 **/
        System.out.println("endtime : " + new Date(end));  	
	}
}


package com.hust.edu.dynProxy;

import java.lang.reflect.Method;

/**
 * 实现事务处理日志代理逻辑
 */
public class TransactionHandler extends AbInvocationHandler {

	public TransactionHandler(Object taObject) {
		super(taObject);
	}
	
	public void invoke(Object object, Method method) {
		System.out.println("Transaction Start");
		superInvoke(object, method);
		System.out.println("Transaction Commit");  
	}
}


动态产生代理类

package com.hust.edu.dynProxy;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;

public class Proxy {
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static Object newProxyInstance(Class infce, InvocationHandler h) throws Exception {
		String methodStr = "";
		String rt = "\r\n";
		Method[] methods = infce.getMethods();

		/**
		 * 这一大段拼字符串的逻辑主要目的是拼接处代理类的java源代码 ,其实这也是动态的核心思想,就是将原来手动创建代理类的过程,改成程序自动生成
		 * 步骤: 
		 * 
		 * 1. 拼接出实现抽象主题方法的函数体 
		 * 
		 * 2. 拼接处类的定义、实现的接口和构造函数 
		 * 
		 * 3. 将拼接的Java代码写入本地文件
		 **/
		for (Method m : methods) {
			methodStr += "@Override" + rt +
					"public void " + m.getName() + "() {" + rt +
					"    try {" + rt +
					"    Method md = " + infce.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
					"    h.invoke(this, md);" + rt +
					"    }catch(Exception e) {e.printStackTrace();}" + rt +

					"}";
		}

		String src =
				"package com.hust.edu.dynProxy;" + rt +
						"import java.lang.reflect.Method;" + rt +
						"public class $Proxy1 implements " + infce.getName() + "{" + rt +
						"    public $Proxy1(InvocationHandler h) {" + rt +
						"        this.h = h;" + rt +
						"    }" + rt +

						"    com.hust.edu.dynProxy.InvocationHandler h;" + rt +

						methodStr +
						"}";
		String fileName = "E:/Test/com/hust/edu/dynProxy/$Proxy1.java";
		File f = new File(fileName);
		FileWriter fw = new FileWriter(f);
		fw.write(src);
		fw.flush();
		fw.close();

		/** 将字符串代码编译成.class字节码,保存在本地 **/
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
		Iterable units = fileMgr.getJavaFileObjects(fileName);
		CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
		t.call();
		fileMgr.close();

		/** 从本地.class文件中加载,产生代理对象 **/
		URL[] urls = new URL[] { new URL("file:/" + "E:/Test/") };
		@SuppressWarnings("resource")
		URLClassLoader ul = new URLClassLoader(urls);
		Class mc = ul.loadClass("com.hust.edu.dynProxy.$Proxy1");
		/** 调用构造函数,创建代理类实例对象 **/
		Constructor ctr = mc.getConstructor(InvocationHandler.class);
		Object m = ctr.newInstance(h);

		return m;
	}
}


客户端:

package com.hust.edu.dynProxy;

public class Client {
	public static void main(String args[]) throws Exception{
	    RealSubject real = new RealSubject();  
	    InvocationHandler h0 = new TimeHandler(real);  
	    //实现叠加的代理h0、分别前后被h1、h2 代理执行  
	    InvocationHandler h1 = new TransactionHandler(h0);  
	    ISubject u = (ISubject) Proxy.newProxyInstance(ISubject.class, h1);  
	    u.excute();
	}
}

运行效果:


由图可以看出对目标类实现了两次包裹的效果


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值