目录
前言
昨天学习梳理了Spring IOC,进天学习梳理一下Spring AOP。Spring AOP 面向切面编程,是Spring核心框架的重要组成部分。使用动态代理机制,构建基于Java语言的简单而强大的AOP框架。
一、Spring AOP的实现机制
SpringAOP属于第二代AOP,采用动态代理机制和字节码生成技术(CGLIB)实现。与最初的AspectJ采用编译器将横切逻辑织入目标对象不同,动态代理机制和字节码生成都是在运行期间为目标对象生成一个代理对象,而将横切逻辑织入到这个代理对象中,系统最终使用的是织入了横切逻辑的代理对象,而不是真正的目标对象。
1.设计模式-代理模式
在代理模式中通常涉及4种角色如图所示:
- ISubject 该接口是对被访问者或者被访问资源的抽象。在严格的设计模式中,这样的抽象接口是必须的,但往宽了说,某些场景下不使用类似的统一抽象接口也是可以的。
- SubjectImpl 被访问者或者被访问资源的具体实现类。如果你要访问某位明星,那么SubjectImpl就是你想访问的明星。
- SubjectProxy 被访问者或者被访问资源的代理实现类,该类持有一个ISubject接口的具体实例。在这个场景中,我们要对subjectImp1进行代理,那么SubiectProxy现在持有的就是SubjectImpl的实例。
- Client 代表访问者的抽象角色,Cient将会访问ISubject类型的对象或者资源。在这个场景中,Client将会请求具体的subjectImp1实例,但Client无法直接请求其真正要访问的资源SubjectImpl,而是必须要通过ISubject资源的访问代理类SubjectProxy进行。
SubjectImpl和SubjectProxy都实现了相同的接口ISubject,而SubjectProxy内部持有SubjectImpl的引用。当Client通过reguest()请求服务的时候,SubjectProxy将转发该请求给SubjectImpl。从这个角度来说,subjectProxy反而有多此一举之嫌了。不过,subjectproxy的作用不只局限于请求的转发,更多时候是对请求添加更多访问限制。
2.动态代理
JDK1.3之后引入了一种称之为动态代理(DynamicProxy)的机制。使用该机制,我们可以为指定的接口在系统运行期间动态地生成代理对象,从而帮助我们走出最初使用静态代理实现AOP的窘境。动态代理机制的实现主要由一个类和一个接口组成,即java.lang.reflect.Proxy类和java.lang.reflect.InvocationHandler接口。
public class TestInvocationHandler implements InvocationHandler {
//被代理对象
private Object target;
//向代理对象注入被代理对象
public TestInvocationHandler(Object target){
this.target = target;
}
//实现代理具体增强内容
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
}
public class ProxyRunTest {
public static void main(String[] args) {
/**
* 第一个参数:类加载器
* 第二个参数:代理对象实现的接口类
* 第三个参数:调用的处理器
*/
ISubject iSubject = (ISubject) Proxy.newProxyInstance(ProxyRunTest.class.getClassLoader(), new Class[]{ISubject.class},new TestInvocationHandler(new SubjectImpl()));
iSubject.request();
}
}
InvocationHandler就是我们实现横切逻辑的地方,它是横切逻辑的载体,作用跟Advice是一样的。所以,在使用动态代理机制实现AOP的过程中,我们可以在InvocationHand1er的基础上细化程序结构,并根据Advice的类型,分化出对应不同Advice类型的程序结构。我们将在稍后看到Spring AOP中的不同Advice类型实现以及结构规格。
动态代理虽好,但不能满足所有的需求。因为动态代理机制只能对实现了相应Interface的类使用,如果某个类没有实现任何的Interface,就无法使用动态代理机制为其生成相应的动态代理对象。对于没有实现任何Interface的目标对象,我们需要寻找其他方式为其动态的生成代理对象。默认情况下,如果SpringAOP发现目标对象实现了相应Interface,则采用动态代理机制为其生成代理对象实例。而如果目标对象没有实现任何Interface,SpringAOP会尝试使用一个称为CGLIB的开源的动态字节码生成类库,为目标对象生成动态的代理对象实例。