目录
JDK和CGLib动态代理模式
一、JDK动态代理
1.JDK动态代理基本原理
2.JDK执行过程及代码分析
二、CGLib动态代理
1.CGLib动态代理基本原理
2.CGLib过程简述
三、JDK和CGLib动态代理区别
四、动态代理的优点
程序执行时使用java.lang.reflect包中Proxy类与InvocationHandler接口动态地生成一个实现代理接口的匿名代理类及其对象,无论调用代理对象哪个方法,最终都会执行invoke方法。
Test.java:
package com.jd.test;
import com.jd.calculator.CalculatorService;
import com.jd.calculator.ICalculatorService;
import com.jd.calculator.ProxyFactory;
public class Test {
public static void main(String[] args) {
ICalculatorService calculatorService = ProxyFactory.getProxy(new CalculatorService());//动态代理过程从这里开始
int result = calculatorService.add(1, 1);
System.out.println("-->"+result);
result = calculatorService.div(1, 1);
System.out.println("-->"+result);
}
}
ProxyFactory.java:
package com.jd.calculator;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* 代理工厂
*
* @author Wuzixin
*/
public class ProxyFactory {
private static ICalculatorService target;//代理谁
private static InvocationHandler handler = new InvocationHandler() {
/**
* 代理对象要做什么事情
*
* proxy:动态代理对象
* method:接口中定义的抽象方法
* args:抽象方法需要传入的参数列表
*
* @author Wuzixin
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String methodName = method.getName();
System.out.println(target.getClass().getName()+":The "+methodName+" method begins.");
System.out.println(target.getClass().getName()+":Parameters of the "+methodName+" method: ["+args[0]+","+args[1]+"]");
Object result = method.invoke(target, args);
System.out.println(target.getClass().getName()+":Result of the "+methodName+" method:"+result);
System.out.println(target.getClass().getName()+":The "+methodName+" method ends.");
return result;
}
};
/**
* 动态产生代理对象
*
* @author Wuzixin
*/
public static ICalculatorService getProxy(ICalculatorService target) {
ProxyFactory.target = target;
ClassLoader classLoader = target.getClass().getClassLoader();//代理对象由哪一个类加载器负责加载
Class>[] interfaces = target.getClass().getInterfaces();// 代理对象所实现的接口,代理对象与目标对象都要实现的接口
return (ICalculatorService) Proxy.newProxyInstance(classLoader, interfaces, handler);// 创建代理对象
}
}
ICalculatorService.java:
package com.jd.calculator;
public interface ICalculatorService {
int add(int a,int b);
int sub(int a,int b);
int mul(int a,int b);
int div(int a,int b);
}
CalculatorService.java:
package com.jd.calculator;
public class CalculatorService implements ICalculatorService {
@Override
public int add(int a, int b) {
int result = a+b;
return result;
}
@Override
public int sub(int a, int b) {
int result = a-b;
return result;
}
@Override
public int mul(int a, int b) {
int result = a*b;
return result;
}
@Override
public int div(int a, int b) {
int result = a/b;
return result;
}
}
第一步:调用getProxy方法进入ProxyFactory类开始进行动态代理。
第二步:在ProxyFactory类中的getProxy方法创建代理对象,但是这里要注意的是,代理对象和CalculatorService是同级,因为这里获取的目标是接口ICalculatorService,并不是类CalculatorService,这里进行了上转型,因此这里的代理对象也是以接口ICalculatorService创建的代理对象,即代理对象实现了ICalculatorService接口,接下来我们通过反编译验证。
// Decompiled by Jad v1.5.8g. Copyright 2001 Pavel Kouznetsov.
// Jad home page: http://www.kpdus.com/jad.html
// Decompiler options: packimports(3)
package com.sun.proxy;
import com.jd.calculator.ICalculatorService;
import java.lang.reflect.*;
public final class $Proxy0 extends Proxy
implements ICalculatorService
{
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
public final boolean equals(Object obj)
{
try
{
return ((Boolean)super.h.invoke(this, m1, new Object[] {
obj
})).booleanValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString()
{
try
{
return (String)super.h.invoke(this, m2, null);
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int mul(int i, int j)
{
try
{
return ((Integer)super.h.invoke(this, m6, new Object[] {
Integer.valueOf(i), Integer.valueOf(j)
})).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int add(int i, int j)
{
try
{
return ((Integer)super.h.invoke(this, m3, new Object[] {
Integer.valueOf(i), Integer.valueOf(j)
})).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int sub(int i, int j)
{
try
{
return ((Integer)super.h.invoke(this, m5, new Object[] {
Integer.valueOf(i), Integer.valueOf(j)
})).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int div(int i, int j)
{
try
{
return ((Integer)super.h.invoke(this, m4, new Object[] {
Integer.valueOf(i), Integer.valueOf(j)
})).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode()
{
try
{
return ((Integer)super.h.invoke(this, m0, null)).intValue();
}
catch(Error _ex) { }
catch(Throwable throwable)
{
throw new UndeclaredThrowableException(throwable);
}
}
private static Method m1;
private static Method m2;
private static Method m6;
private static Method m3;
private static Method m5;
private static Method m4;
private static Method m0;
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]);
m6 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("mul", new Class[] {
Integer.TYPE, Integer.TYPE
});
m3 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("add", new Class[] {
Integer.TYPE, Integer.TYPE
});
m5 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("sub", new Class[] {
Integer.TYPE, Integer.TYPE
});
m4 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("div", new Class[] {
Integer.TYPE, Integer.TYPE
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
}
上述就是反编译得到的$Proxy0类,我们可以看到只有一个构造方法,继承了Proxy0类,因此在调用构造方法时会调用Proxy0类的构造方法
public $Proxy0(InvocationHandler invocationhandler)
{
super(invocationhandler);
}
@CallerSensitive
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() {
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);
}
}
第三步:刚刚执行了Proxy.newProxyInstance方法,上面是其源码,我们关注下面几行,可以发现创建了一个InvocationHandler实例h,而这里的h便是我们创建的匿名内部类,这样就回到了ProxyFactory.java的匿名内部类当中。
final Constructor> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
我们可以看到反编译的类中重写了接口中那几个方法。
第四步:执行父类Proxy0类的构造方法,把实例h传过去。
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
第五步:回到匿名内部类中,获取了代理对象的类中的方法名,获取如下。
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]);
m6 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("mul", new Class[] {
Integer.TYPE, Integer.TYPE
});
m3 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("add", new Class[] {
Integer.TYPE, Integer.TYPE
});
m5 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("sub", new Class[] {
Integer.TYPE, Integer.TYPE
});
m4 = Class.forName("com.jd.calculator.ICalculatorService").getMethod("div", new Class[] {
Integer.TYPE, Integer.TYPE
});
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
}
catch(NoSuchMethodException nosuchmethodexception)
{
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
}
catch(ClassNotFoundException classnotfoundexception)
{
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
第六步:获取方法后执行方法,最后获得结果。
程序执行时通过ASM(开源的Java字节码编辑库,操作字节码)jar包动态地为被代理类生成一个代理子类,通过该代理子类创建代理对象,由于存在继承关系,所以父类不能使用final修饰。
package com.jd.calculator;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 代理工厂
*
* @author Wuzixin
*/
public class ProxyFactory {
private static Callback callback = new MethodInterceptor() {
/**
* 代理逻辑方法
*
* @param proxy 代理对象
* @param method 方法
* @param args 方法参数
* @param methodProxy 方法代理
*/
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
String methodName = method.getName();
Class> target = method.getDeclaringClass();
System.out.println(target.getName()+":The "+methodName+" method begins.");
System.out.println(target.getName()+":Parameters of the "+methodName+" method: ["+args[0]+","+args[1]+"]");
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println(target.getName()+":Result of the "+methodName+" method:"+result);
System.out.println(target.getName()+":The "+methodName+" method ends.");
return result;
}
};
/**
* 获取CGLib代理对象
*
* @author Wuzixin
*/
public static Object getProxy(Class> clazz) {
Enhancer enhancer = new Enhancer(); // 创建字节码增强器,用来创建动态代理类
enhancer.setSuperclass(clazz); // 指定代理类对应父类
// 设置回调:此时代理类上所有方法的调用都会调用MethodInterceptor接口中intercept()抽象方法
enhancer.setCallback(callback);
// 创建动态代理类对象并返回
return enhancer.create();
}
}
其他的和JDK动态代理基本一样,最重要的是这里的工厂实现有些不同,运用的是Ehancer加强类,并且指定的是代理类父类,用setSuperclass方法,然后创建代理对象,代理对象和CalculatorService不是同级关系,而是继承关系,CalculatorService是父类,代理对象是子类。
1、JDK动态代理基于接口实现,所以实现JDK动态代理,必须先定义接口;CGLib动态代理基于类实现
2、JDK动态代理机制是委托机制,委托hanlder调用原始实现类方法;CGLib则使用继承机制,被代理类和代理类是继承关系,所以代理类是可以赋值给被代理类的,如果被代理类有接口,那么代理类也可以赋值给接口。
1、静态代理在程序执行前需手动创建代理类,如果需要很多代理类,每一个都手动创建不仅浪费时间,而且可能产生大量重复性代码,此时我们就可以采用动态代理。
2、动态代理通过InvocationHandler接口invoke方法或MethodInterceptor接口intercept方法为被代理对象中的方法增加额外功能,这种方式比静态代理中通过代理类逐一为被代理对象中的方法增加额外功能,更加的灵活。