介绍
代理模式分为以下三种角色:
- 抽象主题(Subject):真实主题和代理主题的共同接口。
- 代理类: 通过对真实主题的引用,扩展真实主题。
- 真实主题:实现抽象主题,在代理中被引用。
静态代理
public interface Subject {
void req();
}
public class Proxy implements Subject {
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void req() {
System.out.println("Proxy req before----");
subject.req();
System.out.println("Proxy req after----");
}
}
public class RealSubject implements Subject {
@Override
public void req() {
System.out.println("RealSubject req");
}
}
@Test
public void test() {
Subject subject=new RealSubject();
Subject subject1=new Proxy(subject);
subject1.req();
}
Jdk动态代理
用Jdk的api,动态生成类的代理相比硬编码生成的代理方式更加的灵活。
public class HandlerDemo implements InvocationHandler {
private Object target;
public HandlerDemo(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("invoke method before----");
Object result = method.invoke(target, args);
System.out.println("invoke method after----");
return result;
}
}
@Test
public void test() {
Subject demo = new RealSubject();
HandlerDemo handlerDemo = new HandlerDemo(demo);
Subject o = (Subject) Proxy.newProxyInstance(demo.getClass().getClassLoader(), demo.getClass().getInterfaces(), handlerDemo);
o.req();
}
原理
类在被jvm加载的时候分为五个阶段,加载,验证,准备,解析,初始化。在加载的时候,第一步,通过类的全限定名获取类的二进制字节流,第二步,将类的静态结构加载到运行时数据区的方法区,第三步,生成java.lang.Class对象作为方法区访问这个类的入口。第一步获取类的二进制字节流的时候有很多种方式,比如从网络中获取,本地获取,运行的时候生成。Jdk动态代理就是通过运行时生成类的代理类,加载进jvm中使用的。
生成的代理类分析
public final class $Proxy0 extends Proxy implements Subject {
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});
} 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 req() 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);
} 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("com.ex.proxy.Subject").getMethod("req");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
13行代码super.h.invoke(this, m1, new Object[]{var1})调用父类InvocationHandler invoke()方法执行的是HandlerDemo 类的invoke(),HandlerDemo 类的此行代码Object result = method.invoke(target, args)掉的是最终我们自己方法
cglib代理
Jdk的动态代理代理的是实现接口的类,没有实现接口的类可以用cglib代理。
public class CglibProxy implements MethodInterceptor {
private Object target;
public CglibProxy(Object target) {
this.target = target;
}
public Object getInstance() {
Enhancer en = new Enhancer();
en.setSuperclass(target.getClass());
en.setCallback(this);
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("cglib invoke method before----");
Object result = methodProxy.invokeSuper(target, objects);
System.out.println("cglib invoke method after----");
return result;
}
}
@Test
public void test() {
ProxyDemo proxyDemo = new ProxyDemo();
ProxyDemo instance = (ProxyDemo) new CglibProxy(proxyDemo).getInstance();
instance.req();
}