一.概述
动态:jvm通过Proxy.newInstance动态生成代理类;
代理:通过代理类可实现对目标类方法的执行时间/过滤机制/日志代理等额外的代理操作;
二.实现
1.声明一个接口
public interface IUserService {
void setName(String name);
int setAge(int age);
}
2.然后,利用动态代理去生成一个代理对象,去调用setName,setAge方法:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
public class Test {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
IUserService userService = (IUserService) Proxy.newProxyInstance(IUserService.class.getClassLoader(),
new Class[]{IUserService.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("method = " + method.getName() +" , args = " + Arrays.toString(args));
return null;
}
});
System.out.println(userService.getClass());
userService.setName("yalong");
//userService.setAge(12);
}
}
当我们去调研userService.setName方法,你会发现InvocationHandler的invoke方法调用了,并且输出了相关信息。也就是说,通过调用生成的代理类的方法,最终都会调用InvocationHandler的invoke方法,invoke的方法三个入参分别执行代理类的实例 所要执行的方法 和 方法的入参,invoke方法的返回值即代理类所调用方法的返回值。(调用userService.setAge(12)要报错,invoke方法返回null,null类型不能转为int)
三.原理
通过加入代码
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
可用jd-gui查看编译时生成的代理类:
package com.sun.proxy;
import com.proxy.IUserService;
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 IUserService
{
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final void setName(String paramString)
{
try
{
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String toString()
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int setAge(int paramInt)
{
try
{
return ((Integer)this.h.invoke(this, m4, new Object[] { Integer.valueOf(paramInt) })).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final int hashCode()
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m3 = Class.forName("com.proxy.IUserService").getMethod("setName", new Class[] { Class.forName("java.lang.String") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m4 = Class.forName("com.proxy.IUserService").getMethod("setAge", new Class[] { Integer.TYPE });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
}
可以看到,实际上为我们生成一个实现了IUserSevice的类,我们调用其setName方法,实际上就是调用了
try
{
this.h.invoke(this, m3, new Object[] { paramString });
return;
}
m3即为我们的setName方法,静态块中初始化的。剩下是我们传入的参数
那我们看this.h是什么:
就是我们自己创建代理类的入参InvocationHandler对象。