AOP(Aspect Oriented Programming)的出现是为了解决面向对象语言程序设计中的离散却又耦合的冗余代码,AOP是OOP(Oriented Object Programming)设计思想的补充,OOP解决了程序中“纵向”代码冗余问题,AOP要解决类与类之间“横向”的代码冗余问题,设计中诸如:log、安全验证、性能监控、权限验证、事务等需求都会在类中方法造成大量代码重复。Java设计模式中Decorator可以在少量修改中起到一定作用,但是如果牵连模块过多,使用Decorator也将是一个大工程,装饰者模式不是解决此类问题的明智之举。
AOP有两种实现技术,其一是反射+Proxy动态代理,其二是利用Cglib实现代理。
反射+Proxy动态代理无需添加第三方依赖,但是效率上会付出代价,有实验数据表明,调用反射比直接调用方法的开销至少大10倍。动态代理要求被代理类和代理类实现同样一个接口,Proxy生成的对象是对接口一致的,而不是对象一致。
下面实现Java中自带的Proxy动态代理:
package com;
public interface Advice {
void before();
void after();
}
package com;
public class MyAdvice implements Advice {
@Override
public void before() {
System.out.println("之前做点事");
}
@Override
public void after() {
System.out.println("之后做点事");
}
}
package com;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyTest {
public static void main(String[] args) {
ProxyTest pt = new ProxyTest();
Collection target = new ArrayList(10);
Collection proxy = (Collection) pt.getProxy(target, new MyAdvice());
System.out.println(proxy.add("test"));
}
private Object getProxy(final Object target, final Advice advice) {
Object result;
result = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
advice.before();
Object retVal = method.invoke(target, args);
advice.after();
return retVal;
}
});
return result;
}
}
invoke方法参数分析:
proxy:被调用的方法的代理实例。该对象例子程序中并未使用,可以返回以连续调用,有兴趣可以访问:https://paste.ubuntu.com/26104595/。
method:代理对象的父接口中的Method实例。
args:代理对象上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。
例子程序中advice方法中的实现仅为一句输出,实际项目中根据需求需要更改为其他逻辑代码。
下面实现Cglib动态代理:
package cglib;
public class Advice {
public void before(){
System.out.println("这个是前置增强!!");
}
}
package cglib;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class Test implements MethodInterceptor {
Advice advice= new Advice();
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(ArrayList.class);
enhancer.setCallback(new Test());
ArrayList c = (ArrayList) enhancer.create();
c.add(1);
}
public Object intercept(Object target, Method method, Object[] args, MethodProxy proxy) throws Throwable {
advice.before();
Object obj = proxy.invokeSuper(target, args);
return obj;
}
}
Cglib实现上与java动态代理类似,只是它是生成的被代理类的子类,而java动态代理是要求被代理类与代理类实现一个共同接口。
Cglib底层实现使用ASM技术,ASM是一个Java字节码操纵框架,它被用来动态生成类或者增强既有类的功能,总而言之,ASM技术轻量级,相比BCEL 或者 SERP 等字节码操纵工具更小更快。想要深入了解ASM的朋友,可以参考:https://www.ibm.com/developerworks/cn/java/j-lo-asm30/。
两种技术简单总结如下:
SpringAOP中还好既存在java动态代理又有Cglib代理,Spring的操作逻辑是:如果有接口,首先使用java动态代理;如果没有接口,首先使用Cglib框架,产生代理对象;可强制配置,让SpringAOP只使用Cglib。