代理
UML
步骤
- 被代理类与代理类均实现同一接口
- 代理类中有被代理类对象,构造等时候可以传进去
- 通过代理类调用方法
优点
- 易扩展:可以在不对被代理类修改的前提下,进行功能扩展,比如对调用方法日志功能等功能
- 松耦合:将调用者与实体类中间增加了代理层,进行了解耦
- 安全性:可以选择性将部分方法放入代理类,隐藏了被代理类的细节,如果直接使用被代理类,则使用者知道所有的public方法
缺点
- 增加了类的数量,每次想做个功能,都需要重新写个代理类
- 通过代理类调用被代理类方法,多了一层调用
实战
package javase.proxy;
interface Actor {
void act();
}
class Comedian implements Actor {
@Override
public void act() {
System.out.println("Comedian begin");
System.out.println("show comedy!");
System.out.println("Comedian end");
}
}
class Broker implements Actor{
private Actor actor;
public Broker(Actor actor) {
this.actor = actor;
}
@Override
public void act() {
System.out.println("商量片酬");
System.out.println("签订合同");
actor.act();
System.out.println("请客,期待下次合作");
}
}
public class StaticProxy {
public static void main(String[] args) {
Actor actor = new Comedian();
Actor proxy = new Broker(actor);
proxy.act();
}
}
动态代理
运行时动态生成代理类,不用提前手动写,降低工作量
but:我不是还是要写个InvocationHandler吗???
实现动态代理
package javase.proxy;
import java.lang.reflect.*;
class MyInvocation implements InvocationHandler {
private Actor actor;
public MyInvocation(Actor actor) {
this.actor = actor;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
method.invoke(actor, args);
return null;
}
}
public class DynamicProxy {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
// 通过Proxy类的静态方法获取指定类加载器和接口的类,此类实际为生成的代理类的Class对象
Class proxyClass = Proxy.getProxyClass(Comedian.class.getClassLoader(), new Class[] {Actor.class});
// 通过Class生成对应类型的构造器
Constructor cons = proxyClass.getConstructor(new Class[] {InvocationHandler.class});
// 创建具体喜剧明星
Actor actor = new Comedian();
// 创建具体的处理器,将具体喜剧明星注册进去
InvocationHandler iv = new MyInvocation(actor);
// 通过构造器创建具体的代理类对象
Actor proxy = (Actor)cons.newInstance(iv);
// 通过代理类调用act()方法
proxy.act();
}
}
动态代理原理剖析
Proxy类
- 构造函数
protected Proxy(InvocationHandler h) {
Objects.requireNonNull(h);
this.h = h;
}
- getProxyClass(ClassLoader loader, Class<?>... interfaces)
根据类加载器与接口,生成对应代理类的Class对象,根据后面反编译可知,生成的代理类继承了Proxy类,同时实现了interfaces - newProxyInstance
顺便传入InvocationHandler,直接拿到代理类的对象,不需要通过Class对象,获取参数为InvocationHandler的Constructor方法,然后构造对象,再生成代理类对象
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
- isProxyClass(Class<?> cl):判断是否为动态生成的代理Class对象
- getInvocationHandler(Object proxy):获取InvocationHandler对象
生成的代理类
package javase.proxy;
import sun.misc.ProxyGenerator;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Proxy;
public class PrintProxy {
public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException, FileNotFoundException {
InvocationHandler iv = new MyInvocation(new Comedian());
Class c = Proxy.getProxyClass(Comedian.class.getClassLoader(), new Class[] {Actor.class});
Constructor cons = c.getConstructor(InvocationHandler.class);
Actor proxyObject = (Actor) cons.newInstance(new Object[] {iv});
proxyObject.act();
System.out.println(proxyObject.getClass().getName());
byte[] data = ProxyGenerator.generateProxyClass("javase.proxy.$Proxy0", new Class[] {Actor.class});
FileOutputStream fos = new FileOutputStream("D:/proxy.class");
try {
fos.write(data);
fos.flush();
fos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
反编译后
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by Fernflower decompiler)
//
package javase.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements Actor {
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 act() 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("javase.proxy.Actor").getMethod("act");
m0 = Class.forName("java.lang.Object").getMethod("hashCode");
} catch (NoSuchMethodException var2) {
throw new NoSuchMethodError(var2.getMessage());
} catch (ClassNotFoundException var3) {
throw new NoClassDefFoundError(var3.getMessage());
}
}
}
继承关系
- extend Proxy
- implements Interfaces
构造函数
- 接受InvocationHandler,内部调用父类即Proxy的构造函数
public $Proxy0(InvocationHandler var1) throws {
super(var1);
}
act()函数调用
- 生成的Proxy类加载时,执行static语句块,通过反射拿到act方法
- 调用时候,将对象、方法、参数传递给InvocationHandler进行调用
实现动态代理的两种方式
JDK:必须实现接口,否则无法生成代理类
CGlib:不需要实现接口,更通用
// todo