java动态代理就是动态的为委托类生成代理类,相比静态代理需要预先编写代理类源码,动态代理只需要定义好接口,然后使用反射动态生成指定接口的实现类(代理类)。以下通过一个demo来分析动态代理的实现细节。
步骤1:定义接口并提供接口实现类。
/**
* 打电话服务接口
*/
interface CallService{
public void call();
}
/**
* 发信息服务接口
*/
interface SendMessageService{
public void sendMessage();
}
/**
* 手机服务接口
*/
interface PhoneService extends CallService, SendMessageService{
}
/**
* 服务实现类
*/
class PhoneServiceImpl implements PhoneService{
@Override
public void call() {
System.out.println("call----");
}
@Override
public void sendMessage() {
System.out.println("sendMessage----");
}
}
步骤2:为接口实现类提供代理。
/**
* 代理逻辑
*/
class ServiceHandler implements InvocationHandler{
/**
* 被代理对象
*/
private PhoneService target;
public ServiceHandler(PhoneService target){
this.target = target;
}
/**
* 提供需要被代理执行的逻辑
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log("begin servie----");
Object rtn = method.invoke(target, args);
log("finish servie----");
return rtn;
}
private void log(String info){
System.out.println(new Date() + " : " + info);
}
}
以上两步已经准备好了接口和代理逻辑,接下来就测试代理的执行结果。
public class Demo {
public static void main(String[] args) throws Exception {
//创建被代理的对象
PhoneService target = new PhoneServiceImpl();
ServiceHandler serviceHandler = new ServiceHandler(target);
//创建代理对象
PhoneService proxy = (PhoneService)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), serviceHandler);
//通过代理执行业务逻辑
proxy.call();
proxy.sendMessage();
}
}
以上测试代码的执行结果如下:
Thu Mar 27 21:40:21 CST 2014 : begin servie----
call----
Thu Mar 27 21:40:21 CST 2014 : finish servie----
Thu Mar 27 21:40:21 CST 2014 : begin servie----
sendMessage----
Thu Mar 27 21:40:21 CST 2014 : finish servie----
Demo1演示了为PhoneServiceImpl 提供动态代理类来打印日志服务,涉及到的相关类的关系如下:
InvocationHandler接口定义了invoke(Object proxy, Method method, Object[] args)方法,用户必须实现InvocationHandler接口,实现invoke 方法来提供代理类的处理逻辑。
Proxy类是所有动态生成的代理类的父类,它提供了为接口动态生成代理类及其对象的方法。通过调用Proxy的静态方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)为指定接口interfaces生成名为$ProxyN(N由Proxy的计数器确定)的实现类,该实现类中实现了所有接口定义的方法,方法内部实际是对父类Proxy的InvocationHandler 类型成员h调用invoke方法,Proxy相关源代码如下:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throws IllegalArgumentException{
if (h == null) {
throw new NullPointerException();
}
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, interfaces);
}
/*
* Look up or generate the designated proxy class.
*/
//为所有的接口生成一个实现类,并加载生成Class 对象cl
Class<?> cl = getProxyClass0(loader, interfaces);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
//通过反射获取cl的构造方法,并传入h 构造出代理类实例
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (sm != null && ProxyAccessHelper.needsNewInstanceCheck(cl)) {
// create proxy instance with doPrivilege as the proxy class may
// implement non-public interfaces that requires a special permission
return AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
return newInstance(cons, ih);
}
});
} else {
return newInstance(cons, ih);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString());
}
}
private static Object newInstance(Constructor<?> cons, InvocationHandler h) {
try {
return cons.newInstance(new Object[] {h} );
} catch (IllegalAccessException | InstantiationException e) {
throw new InternalError(e.toString());
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString());
}
}
}
跟踪Proxy源码,获取器动态生成的字节码并将其保存到.class文件,然后用jd-gui 反编译字节码文件可得到如下动态代理类代码:
package com.hsh.dynamicproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
implements PhoneService
{
private static Method m4;
private static Method m1;
private static Method m3;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final void sendMessage()
throws
{
try
{
this.h.invoke(this, m4, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final void call()
throws
{
try
{
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m4 = Class.forName("com.hsh.dynamicproxy.PhoneService").getMethod("sendMessage", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.hsh.dynamicproxy.PhoneService").getMethod("call", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
通过看生成的代理类源码,代理的原理就一目了然了。