定义
为其他对象提供一种代理,以控制对对象的访问,结构型模式。某些情况下,一个对象不适合或者不能直接引用对象,而代理对象可以在客户端和目标对象之间起到个中介的作用。
- 作用:一是保护目标对象,二是增强目标对象;而我们在代码里一般都是为了增强目标对象,像spring中的aop。
静态代理
静态代理.png- 代理主题
/**
* 主题
*/
public interface Subject {
void doSomething();
}
- 真实执行角色
/**
* 真正的执行主题
*/
public class RealSubject implements Subject{
@Override
public void doSomething() {
System.out.println("RealSubject doSomething");
}
}
- 静态代理类
/**
* 静态代理类
*/
public class StaticProxy implements Subject{
private RealSubject realSubject;
private StaticProxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void doSomething() {
System.out.println("proxy doSomething1");
realSubject.doSomething();
System.out.println("proxy doSomething2");
}
}
动态代理
JDK
JDK动态代理.png- JdkProxy
/**
* jdk动态代理,通过代理对象的接口生成代理方法,即被代理者
* 必须有实现的接口
*/
public class JdkProxy implements InvocationHandler {
Object subject;
public Object newProxyInstance(Object subject) {
this.subject = subject;
Class<?> classSbject = subject.getClass();
return Proxy.newProxyInstance(classSbject.getClassLoader(), classSbject.getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(subject, args);
after();
return result;
}
private void before() {
System.out.println("before doSomething");
}
private void after() {
System.out.println("after doSomething");
}
}
- 调用客户端
/**
* 调用jdk动态代理的客户端
*/
public class Client {
public static void main(String[] args) {
JdkProxy jdkProxy = new JdkProxy();
Subject subjectProxyInstance = (Subject) jdkProxy.newProxyInstance(new RealSubject());
subjectProxyInstance.doSomething();
}
}
JDK代理所真正执行的类
-
让我们把断点打在ProxyGenerator.generateProxyClass方法里,并通过System.getProperties().put设置saveGeneratedFiles这个变量为true,我们就可以看到真实生成的代理类是怎么样的了
jdk生成类位置.png
- jdk代理生成的代理类
public final class $Proxy0 extends Proxy implements Subject {
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 doSomething() 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("com.example.proxy.dynamicproxy.jdkproxy.Subject").getMethod("doSomething");
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());
}
}
}
- 对比前面的JdkProxy,我们可以发现,真正执行的方法就是JdkProxy里面的invoke方法
CGLIB
- cglib代理主题
/**
* cglib代理主题
*/
public class CglibSubject {
public void doSomething(String sport) {
System.out.println("do " + sport);
}
}
- cglib动态代理
/**
* cglib动态代理
*/
public class CglibProxy implements MethodInterceptor {
public Object getProxyInstance(Class<?> clazz) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(o, objects);
after();
return result;
}
private void before() {
System.out.println("cglib before doSomething");
}
public void after() {
System.out.println("cglib after doSomething");
}
}
- 客户端
public class Client {
public static void main(String[] args) {
System.setProperty(DebuggingClassWriter.DEBUG_LOCATION_PROPERTY, "D://cglib_proxy_classes");
CglibSubject cglibSubjectProxy = (CglibSubject) new CglibProxy().getProxyInstance(CglibSubject.class);
cglibSubjectProxy.doSomething("basketball");
}
}
通过设置DebuggingClassWriter.DEBUG_LOCATION_PROPERTY,我们可以看到cglib生成的代理类
cglib1.png
我们看这三个类中比较重要的方法
- CglibSubject328a458c.class
public final void doSomething(String var1) {
// 即继承了MethodInterceptor的CglibProxy
MethodInterceptor var10000 = this.CGLIB$CALLBACK_0;
if (var10000 == null) {
CGLIB$BIND_CALLBACKS(this);
var10000 = this.CGLIB$CALLBACK_0;
}
if (var10000 != null) {
// 调用拦截器方法
var10000.intercept(this, CGLIB$doSomething$0$Method, new Object[]{var1}, CGLIB$doSomething$0$Proxy);
} else {
super.doSomething(var1);
}
}
- CglibSubjectf11f64a9
public Object invoke(int var1, Object var2, Object[] var3) throws InvocationTargetException {
//真实被代理的对象
CglibSubject var10000 = (CglibSubject)var2;
int var10001 = var1;
try {
switch(var10001) {
case 0:
// 根据索引选择真实执行的方法,而不是反射
var10000.doSomething((String)var3[0]);
return null;
......
}
- CglibSubject328a458c8d4d8eb1
- 和CglibSubjectf11f64a9一样主要是通过下标执行方法
JDK代理与CGLIB代理比较
- JDK生成代理是靠接口,CGLIB是覆盖方法
- JDK的无法生成extend的方法,CGLIB无法覆盖final的方法
- JDK是靠反射,CGLIB是靠下标找到执行方法,CGLIB这点比JDK高效
代理、装饰、适配比较
- 这三个设计模式从使用上来说比较相像,都是持有一个对象,再在调用持有对象方法时做些额外的事。它们的区别主要在于意图,代理是增强,装饰是扩展,适配是转换。
优缺点
- 优点
- 解耦
- 保护目标
- 增强功能
- 缺点
- 增加类的数量
- 增加复杂度
网友评论