Java 动态代理
准备:maven依赖
cglib
cglib
3.2.5
javassist
javassist
3.12.1.GA
junit
junit
3.8.1
test
1,jdk方式实现
jdk方式的动态代理需要通过实现接口来实现,因此,先创建一个简单的接口及实现类:
接口:
package per.ym.proxy.jdk;
public interface BookStore {
String add(String bookName);
String delete(String bookName);
}
实现类:
package per.ym.proxy.jdk;
public class BookStoreImpl implements BookStore {
public String add(String bookName) {
System.out.println("增加书籍:" + bookName);
return bookName;
}
public String delete(String bookName) {
System.out.println("删除书籍:" + bookName);
return bookName;
}
}
创建代理类工厂:
package per.ym.proxy.jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class BookStoreJdkProxyFactory implements InvocationHandler{
private BookStore bookStroe;
public BookStoreJdkProxyFactory(BookStore bookStore) {
this.bookStroe = bookStore;
}
public BookStore getProxy() {
return (BookStore) Proxy.newProxyInstance(bookStroe.getClass().getClassLoader(),
bookStroe.getClass().getInterfaces(), this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("调用方法:" + method.getName());
String bookName = (String) method.invoke(bookStroe, args);
System.out.println("方法:" + method.getName() + " 执行完成");
return bookName;
}
}
测试类:
package per.ym.proxy.jdk;
public class TestMain {
public static void main(String[] args) {
//将生成的代理类保存到文件中
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
BookStoreJdkProxyFactory factory = new BookStoreJdkProxyFactory(new BookStoreImpl());
BookStore proxy = factory.getProxy();
proxy.add("thinking in java");
proxy.delete("spring in action");
}
}
测试结果:
调用方法:add
增加书籍:thinking in java
方法:add 执行完成
调用方法:delete
删除书籍:spring in action
方法:delete 执行完成
反编译生成的代理类(避免篇幅过大,删除了equals,toString,hashCode方法):
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
import per.ym.proxy.jdk.BookStore;
public final class $Proxy0
extends Proxy
implements BookStore
{
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m4;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler)
{
super(paramInvocationHandler);
}
public final String add(String paramString)
{
try
{
return (String)this.h.invoke(this, m3, new Object[] { paramString });
}
catch (Error|RuntimeException localError)
{
throw localError;
}
catch (Throwable localThrowable)
{
throw new UndeclaredThrowableException(localThrowable);
}
}
public final String delete(String paramString)
{
try
{
return (String)this.h.invoke(this, m4, new Object[] { paramString });
}
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") });
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
m3 = Class.forName("per.ym.proxy.jdk.BookStore").getMethod("add", new Class[] { Class.forName("java.lang.String") });
m4 = Class.forName("per.ym.proxy.jdk.BookStore").getMethod("delete", new Class[] { Class.forName("java.lang.String") });
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());
}
}
}
从以上得,代理类实现了被代理类的接口(因此使用jdk实现的动态代理需要被代理类实现接口),并持有传入的InvocationHandler,当调用代理类的方法时,都会转到InvocationHandler的invoke方法中,并传入自身,被调用方法及参数。
2,Cglib方式实现
Cglib是基于继承实现的代理,因此,被代理类不需要实现,直接使用一个类即可:
被代理类:
package per.ym.proxy.cglib;
public class BookStore {
public String add(String bookName) {
System.out.println("增加书籍:" + bookName);
return bookName;
}
public String delete(String bookName) {
System.out.println("删除书籍:" + bookName);
return bookName;
}
}
创建代理类工厂:
package per.ym.proxy.cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class BookStoreCglibProxyFactory implements MethodInterceptor {
private BookStore bookStore;
public BookStoreCglibProxyFactory(BookStore bookStore) {
this.bookStore = bookStore;
}
public BookStore getProxy() {
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(bookStore.getClass());
//回调方法
enhancer.setCallback(this);
//创建代理
return (BookStore) enhancer.create();
}
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("调用方法:" + method.getName());
String bookName = (String) methodProxy.invokeSuper(obj, args);
System.out.println("方法:" + method.getName() + " 执行完成");
return bookName;
}
}
测试类:
package per.ym.proxy.cglib;
import net.sf.cglib.core.DebuggingClassWriter;
public class TestMain {
public static void main(String[] args) {
//将生成的代理类保存到指定目录下
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D:\\proxy_test");
BookStoreCglibProxyFactory factory = new BookStoreCglibProxyFactory(new BookStore());
BookStore proxy = factory.getProxy();
proxy.add("thinking in java");
proxy.delete("spring in action");
}
}
测试结果:
CGLIB debugging enabled, writing to 'D:\proxy_test'
调用方法:add
增加书籍:thinking in java
方法:add 执行完成
调用方法:delete
删除书籍:spring in action
方法:delete 执行完成
反编译生成的代理类(删除了一些注释的东西):
package per.ym.proxy.cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Factory;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class BookStore$$EnhancerByCGLIB$$847c411a
extends BookStore
implements Factory
{
private boolean CGLIB$BOUND;
public static Object CGLIB$FACTORY_DATA;
private static final ThreadLocal CGLIB$THREAD_CALLBACKS;
private static final Callback[] CGLIB$STATIC_CALLBACKS;
private MethodInterceptor CGLIB$CALLBACK_0;
private static Object CGLIB$CALLBACK_FILTER;
private static final Method CGLIB$add$0$Method;
private static final MethodProxy CGLIB$add$0$Proxy;
private static final Object[] CGLIB$emptyArgs;
private static final Method CGLIB$delete$1$Method;
private static final MethodProxy CGLIB$delete$1$Proxy;
private static final Method CGLIB$equals$2$Method;
private static final MethodProxy CGLIB$equals$2$Proxy;
private static final Method CGLIB$toString$3$Method;
private static final MethodProxy CGLIB$toString$3$Proxy;
private static final Method CGLIB$hashCode$4$Method;
private static final MethodProxy CGLIB$hashCode$4$Proxy;
private static final Method CGLIB$clone$5$Method;
private static final MethodProxy CGLIB$clone$5$Proxy;
final String CGLIB$add$0(String paramString)
{
return super.add(paramString);
}
public final String add(String paramString)
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null) {
return (String)tmp17_14.intercept(this, CGLIB$add$0$Method, new Object[] { paramString }, CGLIB$add$0$Proxy);
}
return super.add(paramString);
}
final String CGLIB$delete$1(String paramString)
{
return super.delete(paramString);
}
public final String delete(String paramString)
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null) {
return (String)tmp17_14.intercept(this, CGLIB$delete$1$Method, new Object[] { paramString }, CGLIB$delete$1$Proxy);
}
return super.delete(paramString);
}
final boolean CGLIB$equals$2(Object paramObject)
{
return super.equals(paramObject);
}
public final boolean equals(Object paramObject)
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
{
Object tmp41_36 = tmp17_14.intercept(this, CGLIB$equals$2$Method, new Object[] { paramObject }, CGLIB$equals$2$Proxy);
tmp41_36;
return tmp41_36 == null ? false : ((Boolean)tmp41_36).booleanValue();
}
return super.equals(paramObject);
}
final String CGLIB$toString$3()
{
return super.toString();
}
public final String toString()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null) {
return (String)tmp17_14.intercept(this, CGLIB$toString$3$Method, CGLIB$emptyArgs, CGLIB$toString$3$Proxy);
}
return super.toString();
}
final int CGLIB$hashCode$4()
{
return super.hashCode();
}
public final int hashCode()
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null)
{
Object tmp36_31 = tmp17_14.intercept(this, CGLIB$hashCode$4$Method, CGLIB$emptyArgs, CGLIB$hashCode$4$Proxy);
tmp36_31;
return tmp36_31 == null ? 0 : ((Number)tmp36_31).intValue();
}
return super.hashCode();
}
final Object CGLIB$clone$5()
throws CloneNotSupportedException
{
return super.clone();
}
protected final Object clone()
throws CloneNotSupportedException
{
MethodInterceptor tmp4_1 = this.CGLIB$CALLBACK_0;
if (tmp4_1 == null)
{
tmp4_1;
CGLIB$BIND_CALLBACKS(this);
}
MethodInterceptor tmp17_14 = this.CGLIB$CALLBACK_0;
if (tmp17_14 != null) {
return tmp17_14.intercept(this, CGLIB$clone$5$Method, CGLIB$emptyArgs, CGLIB$clone$5$Proxy);
}
return super.clone();
}
public BookStore$$EnhancerByCGLIB$$847c411a()
{
CGLIB$BIND_CALLBACKS(this);
}
public static void CGLIB$SET_THREAD_CALLBACKS(Callback[] paramArrayOfCallback)
{
CGLIB$THREAD_CALLBACKS.set(paramArrayOfCallback);
}
public static void CGLIB$SET_STATIC_CALLBACKS(Callback[] paramArrayOfCallback)
{
CGLIB$STATIC_CALLBACKS = paramArrayOfCallback;
}
private static final void CGLIB$BIND_CALLBACKS(Object paramObject)
{
847c411a local847c411a = (847c411a)paramObject;
if (!local847c411a.CGLIB$BOUND)
{
local847c411a.CGLIB$BOUND = true;
Object tmp23_20 = CGLIB$THREAD_CALLBACKS.get();
if (tmp23_20 == null)
{
tmp23_20;
CGLIB$STATIC_CALLBACKS;
}
local847c411a.CGLIB$CALLBACK_0 = (tmp31_28 == null ? tmp31_28 : (MethodInterceptor)((Callback[])tmp23_20)[0]);
}
}
public Object newInstance(Callback[] paramArrayOfCallback)
{
CGLIB$SET_THREAD_CALLBACKS(paramArrayOfCallback);
CGLIB$SET_THREAD_CALLBACKS(null);
return new 847c411a();
}
public Object newInstance(Callback paramCallback)
{
CGLIB$SET_THREAD_CALLBACKS(new Callback[] { paramCallback });
CGLIB$SET_THREAD_CALLBACKS(null);
return new 847c411a();
}
public Callback getCallback(int paramInt)
{
CGLIB$BIND_CALLBACKS(this);
switch (paramInt)
{
case 0:
break;
}
return null;
}
public void setCallback(int paramInt, Callback paramCallback)
{
switch (paramInt)
{
case 0:
this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramCallback);
break;
}
}
public Callback[] getCallbacks()
{
CGLIB$BIND_CALLBACKS(this);
return new Callback[] { this.CGLIB$CALLBACK_0 };
}
public void setCallbacks(Callback[] paramArrayOfCallback)
{
this.CGLIB$CALLBACK_0 = ((MethodInterceptor)paramArrayOfCallback[0]);
}
static {}
}
这个看着就有点难受了,而且还生成了其他的class文件,不过能够看出来生成的代理类是通过继承被代理类实现的,当调用指定方法时会转到回调方法中,并传入自身,被调用方法,方法参数和一个MethodProxy,这个MethodProxy还没仔细去看是什么,不过猜测应该是封装了被调用方法相关的信息,最终也是通过反射调用被代理对象的相应方法,如果猜错了,不负责。
3,Javassist方式实现
javassist可以动态的生成一个class,关于它的更多信息,请到这里去:https://www.jianshu.com/p/43424242846b
被代理类:
package per.ym.proxy.javassist;
public class BookStore {
public String add(String bookName) {
System.out.println("增加书籍:" + bookName);
return bookName;
}
public String delete(String bookName) {
System.out.println("删除书籍:" + bookName);
return bookName;
}
}
创建代理类工厂:
package per.ym.proxy.javassist;
import java.lang.reflect.Method;
import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtField;
import javassist.CtNewMethod;
public class BookStoreJavassistProxyFactory {
public static BookStore getProxy() throws Exception {
ClassPool classPool = ClassPool.getDefault();
//代理类名
String proxyClassName = BookStore.class.getName() + "Proxy";
//创建代理类
CtClass ctClass = classPool.makeClass(proxyClassName);
//设置父类为BookStore
ctClass.setSuperclass(classPool.get(BookStore.class.getName()));
//添加属性bookStore
ctClass.addField(CtField.make("private " + BookStore.class.getName() + " bookStore = new " +
BookStore.class.getName() + "();", ctClass));
//保存整个方法信息
StringBuilder methodSb = new StringBuilder();
//保存方法参数信息
StringBuilder paraSb1 = new StringBuilder();
//保存调用被代理类方法的参数信息
StringBuilder paraSb2 = new StringBuilder();
//保存异常信息
StringBuilder exceptionSb = new StringBuilder();
Method[] methods = BookStore.class.getDeclaredMethods();
for (Method m : methods) {
if (m.getModifiers() == 2) {
continue;
}
methodSb.append(getModifier(m.getModifiers())).append(" ")
.append(m.getReturnType().getName()).append(" ")
.append(m.getName());
Class>[] clazzs = m.getParameterTypes();
paraSb1.append("(");
paraSb2.append("(");
for (int i=0 ; i< clazzs.length ; i++) {
if (paraSb1.length() > 1) {
paraSb1.append(",").append(clazzs[i].getName()).append(" ").append("arg" + i);
paraSb2.append(",").append("arg" + i);
} else {
paraSb1.append(clazzs[i].getName()).append(" ").append("arg" + i);
paraSb2.append("arg" + i);
}
}
paraSb1.append(")");
paraSb2.append(")");
methodSb.append(paraSb1);
clazzs = m.getExceptionTypes();
if (clazzs.length > 0) {
methodSb.append(" throws ");
for (int i=0; i < clazzs.length; i++) {
if (exceptionSb.length() > 0) {
exceptionSb.append(",").append(clazzs[i].getName());
} else {
exceptionSb.append(clazzs[i].getName());
}
}
}
methodSb.append("{")
.append("System.out.println(\"执行方法:" + m.getName() + "\"" + ");")
.append(m.getReturnType().getName() + " result = bookStore." + m.getName() + paraSb2 + ";")
.append("System.out.println(\"方法:" + m.getName() + " 执行完成 \");")
.append("return result;")
.append("}");
//添加方法到生成的代理类中
ctClass.addMethod(CtNewMethod.make(methodSb.toString(), ctClass));
methodSb.delete(0, methodSb.length());
paraSb1.delete(0, paraSb1.length());
paraSb2.delete(0, paraSb2.length());
exceptionSb.delete(0, exceptionSb.length());
}
//保存生成的class信息到文件中
ctClass.writeFile();
//获取代理类class对象
Class clazz = ctClass.toClass();
return clazz.newInstance();
}
private static String getModifier(int modifier) {
switch(modifier) {
case 0:
return "protected";
case 1:
return "public";
case 2:
return "private";
case 4:
return "";
default:
return "public";
}
}
}
测试类:
package per.ym.proxy.javassist;
public class TestMain {
public static void main(String[] args) throws Exception {
BookStore proxy = BookStoreJavassistProxyFactory.getProxy();
proxy.add("thinking in java");
proxy.delete("spring in action");
}
}
测试结果:
执行方法:add
增加书籍:thinking in java
方法:add 执行完成
执行方法:delete
删除书籍:spring in action
方法:delete 执行完成
反编译生成的代理类(格式化后的):
package per.ym.proxy.javassist;
import java.io.PrintStream;
public class BookStoreProxy
extends BookStore
{
private BookStore bookStore = new BookStore();
public String add(String paramString)
{
System.out.println("执行方法: add");
String str = this.bookStore.add(paramString);
System.out.println("方法: add 执行完成 ");
return str;
}
public String delete(String paramString)
{
System.out.println("执行方法:delete");
String str = this.bookStore.delete(paramString);
System.out.println("方法:delete 执行完成 ");
return str;
}
}
不知道为啥方法参数名是paramString,而不是我设置的arg0?