代理模式三大角色
抽象接口:声明了真实对象和代理对象的公共接口
代理对象:包含真实对象,用户访问的是代理对象,代理对象再访问真实对象
真实对象:提供真正的能力
静态代理的问题
静态代理一般是一对一的形式,如果要新增真实对象类型,那么需要修改代理对象,违反了设计模式中的开闭原则
动态代理
在运行时创建代理对象,新增真实对象,只需要设置真实对象,然后动态创建代理对象即可。
例子
public interface IFactory {
void sale();
}
public class AFactory implements IFactory {
@Override
public void sale() {
System.out.println("生产玩具");
}
}
public class BFactory implements IFactory {
@Override
public void sale() {
System.out.println("生产餐具");
}
}
public class Company implements InvocationHandler {
//真实对象
private IFactory factory;
public void setFactory(IFactory factory) {
this.factory = factory;
}
//动态代理
public Object getProxyInstance() {
return Proxy.newProxyInstance(
factory.getClass().getClassLoader(), factory.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return method.invoke(factory, args);
}
}
使用
public static void main(String[] args) {
AFactory aFactory = new AFactory();
BFactory bFactory = new BFactory();
Company company = new Company();
// company.setFactory(aFactory);
company.setFactory(bFactory);
//创建一个动态代理对象
IFactory factory = (IFactory) company.getProxyInstance();
factory.sale();
}
动态代理原理
Proxy.newInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h),内部调用
getProxyClass0(loader,ints),动态创建一个Class对象,然后通过反射拿到Constructor,调用constructor.newInstance(h),传入的就是InvocationHandle对象。
getProxyClass0,可以通过ProxyGenerator的generateProxyClass方法创建一个byte数组,我们可以通过反射创建出byte数组,然后写到文件中,然后使用jd-gui工具,查看该class字节码内容。
代理对象会继承Proxy类,实现自定义接口,如:IFactory,构造方法中需要传入InvocationHandler对象,当我们调用sale()的时候,实际调用的是this.h.invoke(proxy, m3,null)。
生成代理对象的class文件
public static void generateClassFile(Class clazz,String proxyName) throws Exception {
/*ProxyGenerator.generateProxyClass(
proxyName, interfaces, accessFlags);*/
Class proxyGeneratorClazz = Class.forName("java.lang.reflect.ProxyGenerator");
Method generateProxyClassMethod= proxyGeneratorClazz.getDeclaredMethod(
"generateProxyClass", String.class, Class[].class);
generateProxyClassMethod.setAccessible(true);
byte[] proxyClassFile = (byte[]) generateProxyClassMethod.invoke(
null, proxyName, new Class[]{clazz});
String paths = clazz.getResource(".").getPath();
System.out.println(paths);
FileOutputStream out = null;
try {
out = new FileOutputStream(paths+proxyName+".class");
out.write(proxyClassFile);
out.flush();
} catch (Exception e) {
e.printStackTrace();
}finally {
try {
out.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
代理对象class具体内容
import com.example.myapplication.proxy.IFactory;
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 IFactory {
private static Method m1;
private static Method m2;
private static Method m3;
private static Method m0;
public $Proxy0(InvocationHandler paramInvocationHandler) {
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject) {
try {
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final String toString() {
try {
return (String)this.h.invoke(this, m2, null);
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void sale() {
try {
this.h.invoke(this, m3, null);
return;
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final int hashCode() {
try {
return ((Integer)this.h.invoke(this, m0, null)).intValue();
} catch (Error|RuntimeException error) {
throw null;
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
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]);
m3 = Class.forName("com.example.myapplication.proxy.IFactory").getMethod("sale", new Class[0]);
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
return;
} catch (NoSuchMethodException noSuchMethodException) {
throw new NoSuchMethodError(noSuchMethodException.getMessage());
} catch (ClassNotFoundException classNotFoundException) {
throw new NoClassDefFoundError(classNotFoundException.getMessage());
}
}
}
使用
IFactory factory = (IFactory) company.getProxyInstance();
ProxyUtils.generateClassFile(IFactory.class, factory.getClass().getSimpleName())