Java动态代理详解

代理是一种设计模式,JDK的代理设计模式应用有Java动态代理。

动态代理是一种思想,委托类的方法实现通过代理类来完成。代理类和委托类实现同一个接口,即让他们实现相同的方法(因为代理类是为委托类服务的,所以必须实现委托类的方法,然后再可以在委托类前后新增加一些方法)

代理设计模式有三种角色:委托类接口,委托类实现,代理类

 

以上模型,代码实现:

定义接口

 

package com.gc.impl;

public interface Subject {
	public void action();
}

 

 

委托类实现接口

package com.gc.acion;

import com.gc.impl.Subject;

public class RealSubject implements Subject {

	@Override
	public void action() {
		System.out.println("RealSubject Action Method");
	}

}

 

代理类实现接口,代理实现委托类的方法并且可以在前后加上一些逻辑。

 

package com.gc.acion;

import com.gc.impl.Subject;

public class SubjectProxy implements Subject{

	Subject subject;
	
	public SubjectProxy(Subject subject){
		this.subject = subject;
	}
	
	@Override
	public void action() {
		//before逻辑
		System.out.println("before RealSubject Method");
		//实现委托类的方法
		subject.action();
		//after逻辑
		System.out.println("after RealSubject Method");
	}
}

 

 

 


这种编程的好处在于,对于before和after方法的公共实现不必在每一个实现类里加,只需要在公共方法里加。但是还有一个缺点,因为实现的是某一个具体的接口,所以接口不同时,每一个接口都需要实现一遍,代码也是冗余的。所以在JDK的实现中用了Java动态代理机制。

 

 

 

JDK的Java动态代理机制:

一般是4个角色:委托类接口,委托类实现,代理类实现和调用操作者。

两个重要的类和接口:

代理类是Proxy(类):java.lang.reflect.Proxy

调用操作者InvocationHandle(接口):java.lang.reflect.InvocationHandle

将所有的触发(invoke)真实类实现方法的动作交给调用操作者,而非代理实现类亲自去实现。

看一下Proxy源码:

重点介绍几种方法:

1、这是Proxy的带参构造方法,绑定一个调用操作者。给内部的h赋值了一个InvocationHandler 

 

protected Proxy(InvocationHandler arg0) {
		Objects.requireNonNull(arg0);
		this.h = arg0;
	}

 

 

 

 

 

2、ClassLoader 是类装载器,interfaces是所有真实类锁拥有的全部接口数组,返回得到一个代理类Class

 

public static Class<?> getProxyClass(ClassLoader arg, Class[]  interfaces)
			throws IllegalArgumentException {
		Class[] arg1 = (Class[]) arg0.clone();
		SecurityManager arg2 = System.getSecurityManager();
		if (arg2 != null) {
			checkProxyAccess(Reflection.getCallerClass(), arg, arg1);
		}


		return getProxyClass0(arg, arg1);
	}

 

 

 

 

 

3、传入类加载器ClassLoader, 委托类所拥有的全部接口数组Class[] interface,调用操作者InvocationHandler,返回得到一个对象,一个代理类对象,相当于上文例子中的Proxy(before、service()、after)

 

public static Object newProxyInstance(ClassLoader arg, Class<?>[] arg0,
			InvocationHandler arg1) throws IllegalArgumentException {
		Objects.requireNonNull(arg1);
		Class[] arg2 = (Class[]) arg0.clone();
		SecurityManager arg3 = System.getSecurityManager();
		if (arg3 != null) {
			checkProxyAccess(Reflection.getCallerClass(), arg, arg2);
		}


		Class arg4 = getProxyClass0(arg, arg2);


		try {
			if (arg3 != null) {
				checkNewProxyPermission(Reflection.getCallerClass(), arg4);
			}


			final Constructor arg5 = arg4.getConstructor(constructorParams);
			if (!Modifier.isPublic(arg4.getModifiers())) {
				AccessController.doPrivileged(new PrivilegedAction() {
					public Void run() {
						arg5.setAccessible(true);
						return null;
					}
				});
			}


			return arg5.newInstance(new Object[] { arg1 });
		} catch (InstantiationException | IllegalAccessException arg7) {
			throw new InternalError(arg7.toString(), arg7);
		} catch (InvocationTargetException arg8) {
			Throwable arg6 = arg8.getCause();
			if (arg6 instanceof RuntimeException) {
				throw (RuntimeException) arg6;
			} else {
				throw new InternalError(arg6.toString(), arg6);
			}
		} catch (NoSuchMethodException arg9) {
			throw new InternalError(arg9.toString(), arg9);
		}
	}


4、传入一个代理类对象,得到一个InvocationHandler调用操作者

 

 

public static InvocationHandler getInvocationHandler(Object arg)
			throws IllegalArgumentException {
		if (!isProxyClass(arg.getClass())) {
			throw new IllegalArgumentException("not a proxy instance");
		} else {
			Proxy arg0 = (Proxy) arg;
			InvocationHandler arg1 = arg0.h;
			if (System.getSecurityManager() != null) {
				Class arg2 = arg1.getClass();
				Class arg3 = Reflection.getCallerClass();
				if (ReflectUtil.needsPackageAccessCheck(arg3.getClassLoader(),
						arg2.getClassLoader())) {
					ReflectUtil.checkPackageAccess(arg2);
				}
			}


			return arg1;
		}
	}


动态代理类是class一种在运行时才生成的class,在生成它是必须提供一组interface给它,然后Dynamic Proxy就实现了这些interface。因为动态Proxy实现了这些接口,所以可以把Dynamic Proxy实例当成是这些interface中的任一一个来使用。

 

当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。因为在有了调用操作类之后,代理类本身就没有必要去亲自实现了。

 

看一下InvocationHandler的源码,该接口只定义有一个方法:

public interface InvocationHandler {
	Object invoke(Object arg0, Method arg1, Object[] arg2) throws Throwable;
}

 

在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,如上例中的action(),args为该方法的参数数组。

invoke中文翻译为触发,即调用操作者代替代理类统一触发真实类的实现方法。

前面说到创建Proxy实例的时候,要绑定三个参数(ClassLoader,interface数组,InvocationHandle)

就是Proxy中实现的所有真实类的接口都交给它绑定的InvacationHandle类去触发真实类的实现动作。Proxy自己只负责调用。

 

看一个动态代理的实例:

 

package com.gc.impl;

public interface Subject {
	public void action();
	public void hello(String s);
}

 

package com.gc.acion;

import com.gc.impl.Subject;

public class RealSubject implements Subject {

	@Override
	public void action() {
		System.out.println("RealSubject Action Method");
	}

	@Override
	public void hello(String s) {
		System.out.println("RealSubject Action Method Include Args:"+s);
	}

}

 

package com.gc.acion;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

import com.gc.impl.Subject;


public class DynamicProxy implements InvocationHandler{

	//要代理的真实对象
	private Object subject;
	
	//用构造方法给要代理的真实对象赋值
	public DynamicProxy(Subject subject){
		this.subject = subject;
	}
	
	@Override
	public Object invoke(Object object, Method method, Object[] arg2)
			throws Throwable {
		//before逻辑
		System.out.println("before RealSubject Method");
		//实现委托类subject的method方法,method方法中可能传有参数为arg2
		method.invoke(subject, arg2);
		//after逻辑
		System.out.println("after RealSubject Method");
		
		return null;
	}
}

 

package com.gc.acion;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

import com.gc.impl.Subject;

public class TestDynamicProxy {
	public static void main(String[] args) {
		//创建一个真实对象
		Subject realsub = new RealSubject();
		//将真实对象绑定到Dynamic Proxy上,同时也通过构造函数给DynamicProxy中的真实对象赋值
		InvocationHandler handler = new DynamicProxy(realsub);
		//创建代理类对象
		Subject subject = (Subject)Proxy.newProxyInstance
				(handler.getClass().getClassLoader(), //InvocationHandler类加载
				realsub.getClass().getInterfaces(), //真实对象的类接口数组,即动态代理类实现了真实类的所有接口
				handler);//绑定调用操作者,把对真实类的实现方法的触发都交给InvocationHalder
		//代理类对象调用了真实类的实现方法,关于这些方法的触发都交给了InvocationHandler(即会实现DynamicProxy的invoke)
		subject.action();//对应method.invoke(subject, "");真实对象,方法
		subject.hello("你好");//对应method.invoke(subject, arg2);真实对象,方法和参数
		
		//总结:Proxy.newProxyInstance代理类对象负责调用,InvocationHandler调用操作者负责触发。
	}
}

 

 

 

 

 

 

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值