AOP专题
动态代理与AOP
Gof设计模式的代理模式:实现权限、缓存等代理,也可根据不同业务职责目标设置不同的代理。入下图:
UML类图如下:
以代码为案例:
this.originClass.myMethod ();
代理模式优点:
- 代理模式是非常普遍使用模式,常用来实现不同场景下对象不同的职责。
- 代理模式阻止了无所不能大“类”。
- 代理模式在业务建模和技术架构上有不同应用,技术架构上有:访问代理(Access Proxy)、虚拟代理和远程代理等。
缺点:
- 一个原始类需要一个Proxy类,形成配对,例如Jive中有很多proxy类,琐碎。
- 客户端耦合了具体的Proxy类。如果实现某一功能Proxy类增多,客户端需要修改。
- 动态代理:只需要一个代理类,就可以为所有原始类实现代理功能。
动态代理
一次编码一个代理类,运行时由JVM反射机制产生多个实例。实现编码阶段和运行阶段分离。动态代理利用Java的反射(Reflect)机制,可以在运行时刻将一个对象实例的方法调用分派到另外一个对象实例的调用。动态代理模式可以在运行时刻创建继承某个接口的类型安全的代理对象,而无需在代码编译时编译这些代理类代码。是AOP的良好实现。
如下类图:
顺序图:
下面代码实现一个动态代理:
接口:
interface BaseIF {
public Object myMethod();
}
实现接口的原始类:
public class OriginClass implements BaseIF {
public Object myMethod() {
System.out.println("hello,It is me!");
return "hello,It is me!";
}
}
创建接口实例的工厂:
public class BaseIFFactory {
public BaseIF create(){
//return new OrignClass();
DynamicProxyClass dynamicProxy = new DynamicProxyClass(new OriginClass());
ClassLoader classLoader = dynamicProxy.getClass().getClassLoader();
Class[] interfaces = new Class[]{BaseIF.class};
BaseIF bi = (BaseIF)Proxy.newProxyInstance(classLoader,interfaces,dynamicProxy);
return bi;
}
/**
public BaseIF create(){
return new OriginClass();
}**/
}
动态代理类:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class DynamicProxyClass implements InvocationHandler {
BaseIF obj;
public DynamicProxyClass(BaseIF obj){
this.obj = obj;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if(method.getName().equals("myMethod")){
System.out.println(" locked");
Object res = obj.myMethod();
System.out.println(" unlocked");
return res;
}else{
return null;
}
}
}
客户端调用:
public class Client {
/**
* @param args
*/
public static void main(String[] args) {
BaseIFFactory factory = new BaseIFFactory();
BaseIF bi = (BaseIF)factory.create();
bi.myMethod();
}
}
使用动态代理来实现AOP的拦截器,这是Spring等框架的缺省实现。
下面我们在上面代码重构一下,以利于实现AOP的拦截器。
拦截器接口:
package proxy;
import java.lang.reflect.Method;
public interface Interceptor {
void beforeAction(Method method, Object[] args);
void afterAction(Method method, Object[] args);
}
如果要实现拦截,只要实现这个接口就可以。
下面是动态代理模板类:
package proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class DynamicProxyTemplate implements InvocationHandler {
Object obj;
Interceptor interceptor;
public DynamicProxyTemplate(Object obj, Interceptor interceptor) {
this.obj = obj;
this.interceptor = interceptor;
}
public Object invoke(Object proxy, Method method, Object[] args) {
Object o = null;
try {
interceptor.beforeAction(method, args);
o = method.invoke(obj, args);//BuinessOne.mymethod();
interceptor.afterAction(method, args);
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (Exception e){
e.printStackTrace();
}
return o;
}
}
产生动态代理实例对象的工厂:
package proxy;
import java.lang.reflect.Proxy;
public class ProxyFactory {
Object o;
Interceptor interceptor;
public ProxyFactory(Object o, Interceptor interceptor) {
this.o = o;
this.interceptor = interceptor;
}
public Object create() {
Object result = null;
try {
long start = System.currentTimeMillis();
DynamicProxyTemplate dynamicProxy = new DynamicProxyTemplate(o, interceptor);
ClassLoader classLoader = dynamicProxy.getClass().getClassLoader();
Class[] interfaces = o.getClass().getInterfaces();
result = Proxy.newProxyInstance(classLoader, interfaces, dynamicProxy);
System.out.println("time2=" + (System.currentTimeMillis() - start));
} catch (IllegalArgumentException e) {
e.printStackTrace();
}
return result;
}
}
好了,框架部分基本完成,下面我们以应用这个框架案例:
我们的业务接口:
package sample;
public interface BusinessIF {
public Object myMethod();
}
业务实现类:
public class BusinessTwo implements BusinessIF {
public Object myMethod() {
System.out.println("hello,It is me!");
return "hello,It is me!";
}
我们要做一个授权验证的拦截器:
package sample;
import java.lang.reflect.Method;
import proxy.Interceptor;
public class AuthInterceptor implements Interceptor {
public void beforeAction(Method method, Object[] args){
if(method.getName().equals("myMethod")){
System.out.println("AuthInterceptor ");
}
}
public void afterAction(Method method, Object[] args){
}
}
这是实现框架部分的Interceptor接口。
客户端调用代码:
public static void main(String[] args) {
ProxyFactory fk = new ProxyFactory(new BusinessTwo(), new AuthInterceptor());
long start = System.currentTimeMillis();
// 正常程序调用
System.out.println("=======client call bi.myMethod()!");
BusinessIF bi = (BusinessIF) fk.create();
String rs = (String) bi.myMethod();
System.out.println("=======client get the result=" + rs + (System.currentTimeMillis() - start));
}
输出结果是:
=======client call bi.myMethod()
AuthInterceptor
hello,It is me!
=======client get the result
显然,我们做的拦截器在业务类AuthInterceptor之前执行了,实现上检查权限。
这种权限检查方式比Jive论坛中编制一个个代理类要简单优雅得多。