1.代理模式
为什么使用代理模式?
当处理实际的业务逻辑之前或者之后,想要处理一些别的事。比如吃饭是我真实要做的事情,但是在吃饭之前我必须要做饭,之后必须要洗碗。 做饭洗碗可以让别人代做。
吃饭接口
public interface IChifan {
void chifan();
}
吃饭实现
public class ChifanImpl implements IChifan {
@Override
public void chifan() {
System.out.println("吃饭");
}
}
静态代理类
public class ChifanProxy implements IChifan {
private IChifan realObject;
public ChifanProxy(IChifan realObject) {
this.realObject = realObject;
}
@Override
public void chifan() {
System.out.println("做饭");
realObject.chifan();
System.out.println("洗碗");
}
}
测试
@Test
public void staticProxy() {
new ChifanProxy(new ChifanImpl()).chifan();
}
结果
从上面的例子可以看出,真正由我做的只有吃饭,而做饭洗碗都是别人做的。这体现了单一职责,真实对象的方法中只完成一个业务逻辑,而别的不影响真实业务逻辑的事情都交给代理来做。
PS:个人感觉代理模式和装饰器模式很相似,理解其中一个就好。
如果IChifan接口有若干个方法,每一个前后都要加入新的业务逻辑呢?
如果不止是IChifan接口,其他接口的实现也需要加入新的业务逻辑呢?
2.动态代理
代理模式在编译的时候已经有代理类存在,而动态代理模式的代理类在运行时才计算出来。java中实现动态代理主要需要以下的类/接口。
Proxy类:用来生成代理类。
InvocationHandler接口:当代理类执行方法时,调用该接口的invoke方法。
我们看一下Proxy生成代理类的源码:
@CallerSensitive
public static Object newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
throws IllegalArgumentException
{
Objects.requireNonNull(h);
final Class<?>[] intfs = interfaces.clone();
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
checkProxyAccess(Reflection.getCallerClass(), loader, intfs);
}
/*
* Look up or generate the designated proxy class.
*/
Class<?> cl = getProxyClass0(loader, intfs);
/*
* Invoke its constructor with the designated invocation handler.
*/
try {
if (sm != null) {
checkNewProxyPermission(Reflection.getCallerClass(), cl);
}
final Constructor<?> cons = cl.getConstructor(constructorParams);
final InvocationHandler ih = h;
if (!Modifier.isPublic(cl.getModifiers())) {
AccessController.doPrivileged(new PrivilegedAction<Void>() {
public Void run() {
cons.setAccessible(true);
return null;
}
});
}
return cons.newInstance(new Object[]{h});
} catch (IllegalAccessException|InstantiationException e) {
throw new InternalError(e.toString(), e);
} catch (InvocationTargetException e) {
Throwable t = e.getCause();
if (t instanceof RuntimeException) {
throw (RuntimeException) t;
} else {
throw new InternalError(t.toString(), t);
}
} catch (NoSuchMethodException e) {
throw new InternalError(e.toString(), e);
}
}
解释一下这段代码:
final Class<?>[] intfs = interfaces.clone();
Class<?> cl =getProxyClass0(loader, intfs);
这两句的意思是加载一个由虚拟机计算出来的实现了intfs接口的代理类。
final Constructor<?> cons = cl.getConstructor(constructorParams);
cons.newInstance(new Object[]{h});
生成代理的实例。
private static final Class<?>[] constructorParams =
{InvocationHandler.class };
这也就是说动态生成的代理类必须组合一个InvocationHandler接口才能实例化。如果没有它,代理类将不知道它重写的方法怎么实现。
使用Proxy.newProxyInstance(类加载器,要实现的接口,具体实现)创建代理类实例。
public class ProxyFactory {
/**
* @param 要代理的类
* @return 代理类
*/
//代理
//委托代理完成真实对象的业务逻辑 在代理实际逻辑前后加上代理所要做的业务逻辑
//代理类需要知道:1.代理哪个类 2.要另外做的事
public static Object createProxy(Object o) {
//ClassLoader.getSystemClassLoader()
return Proxy.newProxyInstance(o.getClass().getClassLoader(), o.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("做饭");
//用真实对象来执行业务逻辑
Object methodReturn = null;
methodReturn = method.invoke(o, args);
System.out.println("洗碗");
return methodReturn;
}
});
}
}
测试
@Test
public void dynamicProxy() {
((IChifan)ProxyFactory.createProxy(new ChifanImpl())).chifan();
}
结果
如果有一些类需要代理做这些事情,而另一些需要代理干那些事情,只需要实现多个 InvocationHandler接口即可。