AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。
AOP实现的关键在于AOP框架自动创建的AOP代理,AOP代理主要分为静态代理(编译时增强)和动态代理(运行时增强),静态代理的代表为AspectJ;而动态代理则以Spring AOP为代表。
(1)使用AspectJ的编译时增强实现AOP
所谓的静态代理就是AOP框架会在编译阶段生成AOP代理类,因此也称为编译时增强。
举个实例的例子来说。首先我们有一个普通的Hello类
public class Hello {
public void sayHello() {
System.out.println("hello");
}
public static void main(String[] args) {
Hello h = new Hello();
h.sayHello();
}
}
使用AspectJ编写一个Aspect
public aspect TxAspect {
void around():call(void Hello.sayHello()){
System.out.println("开始事务 ...");
proceed();
System.out.println("事务结束 ...");
}
}
编译完成之后再运行这个Hello类,可以看到以下输出
开始事务 ...
hello
事务结束 ...
很显然,AOP已经生效了,那么究竟AspectJ是如何在没有修改Hello类的情况下实现代码增强的?
查看一下编译后的Hello.class
public class Hello {
public Hello() {
}
public void sayHello() {
System.out.println("hello");
}
public static void main(String[] args) {
Hello h = new Hello();
sayHello_aroundBody1$advice(h, TxAspect.aspectOf(), (AroundClosure)null);
}
}
如此,proceed()方法就是回调执行被代理类中的方法。
(2)使用Spring AOP
Spring AOP使用的动态代理,动态代理就是说AOP不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。需导入两个jar包:cglib.jar、asm.jar。
Spring AOP中的动态代理主要有两种方式:jdk动态代理 、cglib动态代理。jdk动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。jdk动态代理的核心是InvocationHandler接口 、Proxy类。
当目标类没有实现接口,那么Spring AOP会选择使用cglib来动态代理目标类。cglib(Code Generation Library)是一个代码生成的类库,可以在运行时动态的生成某个类的子类,cglib是通过继承的方式做的动态代理,所以若某个类被标记为final,那么它就无法使用cglib做动态代理的。
定义一个接口
public interface Person {
String sayHello(String name);
}
实现类
@Component
public class Chinese implements Person {
@Override
public String sayHello(String name) {
System.out.println("-- sayHello() --");
return name + " hello, AOP";
}
}
实现类
public class MyInvocationHandler implements InvocationHandler {
private Object target;
MyInvocationHandler() {
super();
}
MyInvocationHandler(Object target) {
super();
this.target = target;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 程序执行前加入逻辑,MethodBeforeAdviceInterceptor
System.out.println("before-----------------------------");
// 程序执行
Object result = method.invoke(target, args);
// 程序执行后加入逻辑,MethodAfterAdviceInterceptor
System.out.println("after------------------------------");
return result;
}
}
测试类
public class Test {
/**
* JDK动态代理测试类
*/
public static void main(String[] args) {
Chinese chinese= new Chinese();
MyInvocationHandler mih = new MyInvocationHandler(chinese);
Class<?> cls = chinese.getClass();
/**
* loader 类加载器
* interfaces 实现接口
* h InvocationHandler
*/
Person p = (Person)Proxy.newProxyInstance(cls.getClassLoader(), cls.getInterfaces(), h);
System.out.println(p.sayHello("张三"));
}
}
输出
before-----------------------------
张三 hello, AOP
after------------------------------
我们再来看看不是用接口的情况,修改Chinese类
实现类
@Component
public class Chinese {
public String sayHello(String name) {
System.out.println("-- sayHello() --");
return name + " hello, AOP";
}
}
实现类
public class CglibProxy implements MethodInterceptor {
public Object intercept(Object object, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("before-------------");
// 执行目标类add方法
proxy.invokeSuper(object, args);
System.out.println("after--------------");
return null;
}
}
目标类的工厂Factory类
public class Factory {
//获得增强之后的目标类,即添加了切入逻辑advice之后的目标类
public static Base getInstance(CglibProxy proxy) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Chinese.class);
//回调方法的参数为代理类对象CglibProxy,最后增强目标类调用的是代理类对象CglibProxy中的intercept方法
enhancer.setCallback(proxy);
// 此刻,base不是单纯的目标类,而是增强过的目标类
Chinese chinese = (Chinese) enhancer.create();
return chinese;
}
}
测试类
public class Test {
public static void main(String[] args) {
CglibProxy proxy = new CglibProxy();
// base为生成的增强过的目标类
Chinese chinese = Factory.getInstance(proxy);
System.out.println(chinese.sayHello("张三"));
}
}
输出
before-----------------------------
张三 hello, AOP
after------------------------------