责任链:
在java web开发中Filter是我们常用的一种技术。并且它的过滤顺序是一种堆栈式的。如下
上图中的执行顺序为FilterA ---> FilterB---->FilterC ----->FilterB -----> FilterA.
其中FilterA,FilterB,FilterC分别实现Filter接口中的doFilter方法,还需要另外一个类FilterChain并实现Filter接口。FilterChain中的与其他3中不同的是,他还包含一个addFiltter方法,用来添加FilterA,FilterB,FilterC。从而是FilterChain FilterA FilterB和FilterC形成一个链,这其中关键的是每个Filter中的doFilter方法都要调用另外的一个Filter,以使他们形成一个堆栈式的Filter链。这时候客户端调用FilterChain的doFilter方法也就形成了链的调用。
代理模式:
静态代理:
静态代理即先把要被代理的类的代理类写好,从而在不改变被代理类源码的情况下,只是由客户端调用的被代理类转而调用代理类的一种模式。
那么在不改变被代理类的情况下,如何才能让客户端调用的代码改变的尽可能的小的呢。这使我们想到了多态即父类引用指向子类对象。这具体有两种方法,一种是采用继承的方式,另外一种是采用组合的方式。、
继承:即代理类继承被代理类,由代理类重写被代理类的方法。但是继承的方式不灵活,并且各个代理类之间不能灵活的组合。
组合:代理类和被代理类实现一个共同的刚发接口,代理类持有被代理类的引用,并在代理类的方法中写代理的业务逻辑并调用被代理类的方法。
动态代理:
动态代理即动态的生产代理类而不是像上面那样要手动的继承或者是手动的实现接口来完成。即通过一个方法可以对任意的接口实现代理。
以下是从网络上转过来的,不过不知道源码是如何提取出来的,不过,从这段源码可以很清楚的看清楚jdk中动态代理的原理;
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 Manager {
private static Method m1;
private static Method m0;
private static Method m3;
private static Method m2;
static {
try {
m1 = Class.forName("java.lang.Object").getMethod("equals",
new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode",
new Class[0]);
m3 = Class.forName("com.ml.test.Manager").getMethod("modify",
new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString",
new Class[0]);
} catch (NoSuchMethodException nosuchmethodexception) {
throw new NoSuchMethodError(nosuchmethodexception.getMessage());
} catch (ClassNotFoundException classnotfoundexception) {
throw new NoClassDefFoundError(classnotfoundexception.getMessage());
}
}
public $Proxy0(InvocationHandler invocationhandler) {
super(invocationhandler);
}
@Override
public final boolean equals(Object obj) {
try {
return ((Boolean) super.h.invoke(this, m1, new Object[] { obj }))
.booleanValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final int hashCode() {
try {
return ((Integer) super.h.invoke(this, m0, null)).intValue();
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
public final void modify() {
try {
super.h.invoke(this, m3, null);
return;
} catch (Error e) {
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
@Override
public final String toString() {
try {
return (String) super.h.invoke(this, m2, null);
} catch (Throwable throwable) {
throw new UndeclaredThrowableException(throwable);
}
}
}
接着把得到的$Proxy0实例强制转换成Manager.
当执行managerProxy.modify()方法时,就调用了$Proxy0类中的modify()方法.
在modify方法中,调用父类Proxy中的h的invoke()方法.
即InvocationHandler.invoke();
下面结合jdk动态代理的用法进行说明,jdk api用法:
InvocationHandler handler = new MyInvocationHandler(...);
Foo f = (Foo) Proxy.newProxyInstance(Foo.class.getClassLoader(), new Class[] { Foo.class }, handler);通过api和源码可以看出Proxy.newProxyInstance生成了代理类。代理类的业务逻辑封装在了InvocationHandler的invoke方法中。并且可以看出在生成的源码中代理类和被代理类实现了共同的接口,这也就是说jdk中的动态代理只能代理那些实现了接口的被代理类。
那么是如何生成代理类的呢,sun公司对此并没有开源,我也没有详细的追究。不过到是有一种思路:1,根据反射将代理的业务逻辑单元全部生成字符串;2,再调用java中的动态源码编译api,将源代码生成字节码,在使用时动态加载,并放在内存中缓存代理类。通过这种方式或许能较高效率的生成代理类。另外除了jdk当中的动态代理实现外,还有cjlib中的实现方式,即通过动态的修改被代理类的字节码来达到生成代理类的目的,当然这种方式不要求被代理类要实现接口。