##一文彻底搞懂java动态代理
为什么要使用代理
代理模式,是设计模式的一种,旨在增强某个类的功能。
现代编程,提倡高内聚低耦合。当想对已有模块增加功能时,要尽可能不动或者少动原代码。代理模式,提供了很好的解决方案。通过静态代理或动态代理,生成一个新的类,与被代理类产生关联,从而实现被代理类的功能增强。
代理的基本思想
1、代理类与被代理类实现同一个接口,或继承同一个父类;
2、代理类实现被代理类的功能;
3、代理类实现增强功能;
4、执行代理类。
静态代理
public interface ParentInterface
{
void doSome();
}
public class TargetClass implements ParentInterface
{
@Override
public void doSome(){
System.out.println("I'm original object!");
}
}
public class ProxyClass implements ParentInterface
{
TargetClass targetClass = new TargetClass();
@Override
public void doSome(){
targetClass.doSome();
System.out.println("I hava more functions!");
}
}
动态代理
工作原理:
1、通过反射技术(JDK动态代理)、字节码技术,实现被代理类的所有接口和父类,动态生成目标类的代理类;
2、在代理类中增强目标类的功能;
3、动态加载代理对象,执行目标方法。
JDK动态代理
基本原理:
引入jdk的java.lang.reflect包,创建代理类,实现java.lang.reflect.InvocationHandler接口,重写invoke方法。
代理类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkProxyClass<T> implements InvocationHandler {
private T target;
public JdkProxyClass(T target) {
this.target = target;
}
/**
* 获取被代理接口实例对象
* @param
* @return
*/
public <T>T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("this is my function");
Object result = method.invoke(target, args);
System.out.println("my function done");
return result;
}
}
测试类
public class JdkProxyTest {
public static void main(String[] args) {
// 保存生成的代理类的字节码文件
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// jdk动态代理测试
ParentInterface subject = new JdkProxyClass<>(new TargetClass()).getProxy();
subject.doSome();
}
}
这里设置了sun.misc.ProxyGenerator.saveGeneratedFiles为true,我们可以在 根目录下查看生成的字节码文件。
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 jdkProxy.ParentInterface;
public final class $Proxy0 extends Proxy implements ParentInterface {
private static Method m1;
private static Method m2;
private static Method m3;
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})).booleanValue();
} catch (RuntimeException | Error var3) {
throw var3;
} catch (Throwable var4) {
throw new UndeclaredThrowableException(var4);
}
}
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 void doSome() throws {
try {
super.h.invoke(this, m3, (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)).intValue();
} 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"));
m2 = Class.forName("java.lang.Object").getMethod("toString");
m3 = Class.forName("jdkProxy.ParentInterface").getMethod("doSome");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
工作流程:
1、在代理类中调用 java.lang.reflect.Proxy 的 newProxyInstance 方法,创建字节码文件;
参数为:目标对象的类加载器,目标对象的所有接口,当前代理类实例this。
2、使用ClassLoader将字节码文件加载到JVM;
3、创建动态代理实例对象,并返回;
4、调用动态代理实例的方法;
5、动态代理实例调用代理类的invoke方法;该方法中调用了目标类的方法和增强方法。
CGLib
采用底层的字节码技术,全称 code generation libarary 。创建一个子类,实现需要代理的类;在子类中采用拦截方法,拦截父类方法,并织入横切代码。
public class TargetInterceptor implements MethodInterceptor {
/**
- Cglib 动态代理的处理方法
- */
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
// 方法调用返回值
Object result = null;
System.out.println("方法开始");
result = methodProxy.invokeSuper(o,objects);
System.out.println("方法结束");
return result;
}
public CglibTarget getProxy(){
// Enhancer 为 Cglib中的字节码增强器,将目标类和动态处理类传入此增强器,调用增强器的create方法返回代理对象
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(CglibTarget.class);
enhancer.setCallback(this);
return (CglibTarget)enhancer.create();
}
}