动态代理其实是面向切面编程AOP。实现有两种,一个是Java SDK提供的,另外一个是第三方库提供,比如cglib
Java SDK
下面是Java SDK提供的代理
静态代理
package aop;
public class SimpleStaticProxyDemo {
static interface IService {
public void sayHello();
}
static class RealService implements IService {
@Override
public void sayHello() {
System.out.println(" hello");
}
}
static class TraceProxy implements IService {
private IService realService;
public TraceProxy(IService realService) {
this.realService = realService;
}
@Override
public void sayHello() {
System.out.println(" entering sayHello");
this.realService.sayHello();
System.out.println(" leaving sayHello");
}
}
public static void main(String[] args) {
IService realService = new RealService();
IService proxyService = new TraceProxy(realService);
proxyService.sayHello();
}
}
动态代理
package dynamic.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyDemo {
static interface IService {
public void sayHello();
}
static class RealService implements IService {
@Override
public void sayHello() {
System.out.println(" hello");
}
}
static class SimpleInvocationHandler implements InvocationHandler {
private Object realObj;
public SimpleInvocationHandler(Object realObj) {
this.realObj = realObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" entering " + method.getName());
Object result = method.invoke(realObj, args);
System.out.println(" leaving " + method.getName());
return result;
}
}
public static void main(String[] args) {
//保留$Proxy0.class文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
IService realService = new RealService();
IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(),
new Class<?>[] { IService.class }, new SimpleInvocationHandler(realService));
//输出代理类对象
System.out.println("Proxy : "+ proxyService.getClass().getName());
System.out.println("Proxy super : "+ proxyService.getClass().getSuperclass().getName());
System.out.println("Proxy interfaces : "+ proxyService.getClass().getInterfaces()[0].getName());
/*
//等同效果,注意加上异常处理
//throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException
Class<?> proxyCls = Proxy.getProxyClass(IService.class.getClassLoader(), new Class<?>[] { IService.class });
Constructor<?> ctor = proxyCls.getConstructor(new Class<?>[] { InvocationHandler.class });
InvocationHandler handler = new SimpleInvocationHandler(realService);
IService proxyService = (IService) ctor.newInstance(handler);
*/
//手动生成。然后在路径下创建$Proxy0.class文件。根目录下建,还要包和文件夹对应
//System.out.println("$Proxy0.class全名: "+Proxy.getProxyClass(IService.class.getClassLoader(), IService.class));
proxyService.sayHello();
}
}
IService proxyService = (IService) Proxy.newProxyInstance(IService.class.getClassLoader(), new Class<?>[] { IService.class }, new SimpleInvocationHandler(realService));
这一句等同于下面代码。
Class<?> proxyCls = Proxy.getProxyClass(IService.class.getClassLoader(), new Class<?>[] { IService.class });
Constructor<?> ctor = proxyCls.getConstructor(new Class<?>[] { InvocationHandler.class });
InvocationHandler handler = new SimpleInvocationHandler(realService);
IService proxyService = (IService) ctor.newInstance(handler);
看一下原函数
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();//复制对象,与原来完全独立
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
new Class<?>[] { InvocationHandler.class }是新建类对象。
这里先找到构造类,再newInstance。
通过反射创建新的类示例,有两种方式:
- Class.newInstance()
只能够调用无参的构造函数,调用默认的构造函数。
要求被调用的构造函数是可见的,必须是public类型的。 - Constructor.newInstance()
可以根据传入的参数,调用任意构造构造函数。
可以调用私有的构造函数(Constructor .setAccessible(true))。
注意到这里proxyService.sayHello();
好像没看到proxyService怎么加载sayHello方法进去就突然有这个方法执行呢?这个可以看下编译出来的$Proxy0.class文件
package ProxyDemo;
import ProxyDemo.ProxyDemo.IService;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
final class $Proxy0 extends Proxy implements IService {
private static Method m1;
private static Method m3;
private static Method m2;
private static Method m0;
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
public final boolean equals(Object var1) throws {
try {
return (Boolean)super.h.invoke(this, m1, new Object[]{var1});
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
public final void sayHello() throws {
try {
super.h.invoke(this, m3, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final String toString() throws {
try {
return (String)super.h.invoke(this, m2, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
public final int hashCode() throws {
try {
return (Integer)super.h.invoke(this, m0, (Object[])null);
} catch (RuntimeException | Error var2) {
throw var2;
} catch (Throwable var3) {
throw new UndeclaredThrowableException(var3);
}
}
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals", Class.forName("java.lang.Object"));
m3 = Class.forName("ProxyDemo.ProxyDemo$IService").getMethod("sayHello");
m2 = Class.forName("java.lang.Object").getMethod("toString");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
通用型
package generalProxyDemo;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class GeneralProxyDemo {
static interface IServiceA {
public void sayHello();
}
static class ServiceAImpl implements IServiceA {
@Override
public void sayHello() {
System.out.println(" hello");
}
}
static interface IServiceB {
public void fly();
}
static class ServiceBImpl implements IServiceB {
@Override
public void fly() {
System.out.println(" flying");
}
}
static class SimpleInvocationHandler implements InvocationHandler {
private Object realObj;
public SimpleInvocationHandler(Object realObj) {
this.realObj = realObj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(" entering " + realObj.getClass().getSimpleName() + "::" + method.getName());
Object result = method.invoke(realObj, args);
System.out.println(" leaving " + realObj.getClass().getSimpleName() + "::" + method.getName());
return result;
}
}
@SuppressWarnings("unchecked")
private static <T> T getProxy(Class<T> intf, T realObj) {
return (T) Proxy.newProxyInstance(intf.getClassLoader(), new Class<?>[] { intf },
new SimpleInvocationHandler(realObj));
}
public static void main(String[] args) throws Exception {
IServiceA a = new ServiceAImpl();
IServiceA aProxy = getProxy(IServiceA.class, a);
aProxy.sayHello();
IServiceB b = new ServiceBImpl();
IServiceB bProxy = getProxy(IServiceB.class, b);
bProxy.fly();
}
}
第三方库
Cglib
package simpleCGLibDemo;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class SimpleCGLibDemo {
static class RealService {
public void sayHello() {
System.out.println(" hello");
}
}
static class SimpleInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println(" entering " + method.getName());
Object result = proxy.invokeSuper(object, args);
System.out.println(" leaving " + method.getName());
return result;
}
}
private static <T> T getProxy(Class<T> cls) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(cls);
enhancer.setCallback(new SimpleInterceptor());
return (T) enhancer.create();
}
public static void main(String[] args) throws Exception {
RealService proxyService = getProxy(RealService.class);
proxyService.sayHello();
}
}
我这里用的是cglib编译库是:cglib_3.2.5.jar和asm_5.2.jar
cglib 的特点是不需要有接口都可以代理。它是通过生成子类的形式来代理,所以父类如果有final那些方法就代理不了。Java sdk的代理是需要有接口才能代理。