1. AOP的概念
AOP 是Aspect-Oriented Programming(面向方面编程或者面向切面)的简称,维基百科对其解释如下:
Aspect是一种新的模块化机制,用来描述分散在对象、类或者函数中的横切关注点。从关注点分离出横切关注点是面向切面的程序设计的核心概念。分离关注点使解决特定领域问题的代码从业务逻辑中独立出来,业务逻辑的代码中不再含有针对特定领域问题代码的调用,业务逻辑同特定领域问题的关系通过切面来封装、维护这样原本分散在整个应用程序中的变动就可以很好的管理起来。
2 相关概念
2.1 Advice(通知):定义在连接点做什么,为切面增强提供织入接口。在Spring AOP中,它主要描述Spring AOP围绕方法调用注入的切面行为。
2.2 Pointcut(切点):切点决定Advice通知应该作用于哪个连接点,也就是说通过Pointcut来定义需要增强的方法的集合,这些集合的选取可以按照一定规则来完成。比如在某个Package下的所有类的所有方法,或者用正则表达式来匹配。
2.3 Advisor(通知器):完成对目标方法的切面增强设计(advice)和关注点的设计(pointcut)以后,需要一个对象把它们结合起来,完成这个的就是Advixor(通知器)。
3. 动态代理特性
在Spring AOP实现中,使用的核心技术就是动态代理,而这种动态代理实际上是JDK的一个特性(在JDK 1.3以上的版本,实现了动态代理)。通过JDK动态代理特性,可以为任意的java对象创建代理对象,这个特性是通过JAVA Reflection API来完成的。下面我们来先学习下Proxy模式。
3.1 Proxy模式
上图就是Proxy的静态类图,在Proxy调用的过程中,如果客户(client)调用Proxy的request方法,会在调用目标对象的request方法前后调用一系列的处理,而这一系列处理对于目标对象来说是透明的,目标对象对于这些处理是毫无知情的,这就是Proxy模式。
以下是代码实例
首先定义一个接口
1 public interface Subject { 2 public void rent(); 3 public void hello(String str); 4 }
接口的实现类
1 public class RealSubject implements Subject { 2 3 public void rent() { 4 System.out.println("I want to rent my house"); 5 } 6 7 public void hello(String str) { 8 System.out.println("hello " + str); 9 } 10 11 }
动态代理类
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Method; 3 4 public class DynamicProxy implements InvocationHandler { 5 6 // 我们要代理的真实对象 7 private Object subject; 8 public DynamicProxy(Object subject){ 9 this.subject = subject; 10 } 11 public Object invoke(Object object, Method method, Object[] args) 12 throws Throwable { 13 //在代理真实对象前我们可以添加一些自己的操作 14 System.out.println("before rent the house"); 15 method.invoke(subject, args); 16 //在代理真实对象后我们可以添加一些自己的操作 17 System.out.println("after rent the house"); 18 return null; 19 } 20 21 }
测试类
1 import java.lang.reflect.InvocationHandler; 2 import java.lang.reflect.Proxy; 3 4 public class client { 5 public static void main(String[] args) { 6 // 我们要代理的真实对象 7 Subject realSubject = new RealSubject(); 8 9 //我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的 10 InvocationHandler handler = new DynamicProxy(realSubject); 11 // 绑定代理对象 12 Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); 13 subject.rent(); 14 15 } 16 }
输出结果:
before rent the house
I want to rent my house
after rent the house