`

spring的aop框架

阅读更多

Spring 中所有的通知都是以 Java 类的形式编写的。 Spring 是采用运行期的方式来将切面织入到系统中的。

代理 Bean 只有在第一次被应用系统需要的时候才被创建。 Spring 有两种方式创建代理: Proxy 类创建代理 ( 实现过接口的目标类 ) 和运用 CGLIB 库创建代理 ( 没有实现过任何接口的目标类 ) 。需要注意两点: 1 、对接口创建代理优于对类创建代理,因为这样会产生更加松耦合的系统, 2 、标记为 final 的方法是不能被通知的,因为 Spring 在实现的时候是为目标类产生子类。

Spring 只支持方法联接点。

 

 

Spring 中通知的类型:

1 Around    org.aopalliance.intercept.MethodInterceptor   栏截对目标对象方法的调用

2 Before    org.springframework.aop.MethodBeforAdvice     在目标方法被调用之前调用

3 After     org.springframework.aop.AfterReturningAdvice  当目标方法被调用之后调用

4 Thorws    org.springframework.aop.ThrowsAdvice          当目标方法抛出异常时调用

 

前置通知 实现 MethodBeforeAdvice 接口,该接口有以下方法:

void befor(Method method,Object []args,Object target) throws Throwable;

例:

public class WelcomeAdvice implements MethodBeforeAdvice{

       public void before(Method method,Object []args,Object target){

              System.out.println("Hello,"+((Customer)args[0]).getName());

       }

}

配置文件如下:

<beans>

<bean id="aaaTargetObject" class="AAA"/>   // 目标类 , 这是一个实现某个接口的类

<bean id="welcomeAdvice" class="WelcomeAdvice"/>  // 通知类

<bean id="aaa" class="org.springframework.aop.framework.proxyFactoryBean">

       <property name="interceptorNames">

              <list>

                     <value>welcomAdvice</value>

              </list>

       </property>

       <property name="target">

              <ref bean="aaaTargetObject"/>

       </property>

</bean>

</beans>

 

后置通知 实现 AfterReturningAdvice 接口,该接口有以下方法:

void afterReturning(Object returnValue,Method method,Object []args,Object target) throws Throwable;

例:

public class ThankYouAdvice implements AfterReturningAdvice{

       public void afterReturning(Object returnValue,Method method,Object []args,Object target){

              System.out.println("Thank you, come again.");

       }

}

在前置通知和后置通知中都不能改变参数中传进来的值,改变执行流程的惟一方法就是抛出异常。

 

环绕通知 实现 MethodInterceptor 接口,该接口有以下方法:

Object invoke(MethodInvocation invocation) throws Throwable;

环绕通知能够控制目标方法是否真的被调用,通过调用 MethodInvocation.proceed() 方法来调用目标方法。它还可以让你控制返回的对象。

例:

public class ExampleAroundInterceptor implements MethodInterceptor{

       public Object invoke(MethodInvocation invocation) throws Throwable{

              // 调用之前可以做一些处理

              Object returnObject=invocation.proceed();// 调用目标方法

              // 调用之后还可以做一些处理

              return returnObject;

       }

}

 

异常通知 实现 ThrowsAdvice 接口,此接口是一个标示接口,没有定义必须实现的方法,但是下面两个方法中必须实现一个:

void afterThrowing(Throwable throwable);

void afterThrowing(Method method,Object []args,Object target,Throwable throwable);

ThrowsAdvice 要处理的异常取决于你的方法定义的异常类型,在一个实现类中,也可以实现多个 afterThrowing 方法,根据抛出的异常类型调用适当的方法。

 

引入通知 给目标对象添加新的方法 ( 以及属性 )

<aop:aspectj-autoproxy />
    <aop:config>
        <aop:aspect ref="shop">
            <aop:declare-parents
                types-matching="apple.spring.naop.Shop+"
                implement-interface="apple.spring.naop.Bye"
                default-impl="apple.spring.naop.ByeImpl"/>
        </aop:aspect>
</aop:config>

 

 

定义切入点

切入点 就是应用通知的地方,切入点决定了一个特定的类的特定方法是否满足一条特定的规则,如果一个方法符合的话,通知就应用到该方法上。 Spring 的切入点可以让我们以一种灵活的方式定义在什么地方将通知织入到我们的类中。

切入点的核心接口是 Pointcut 接口,同时它也需要两个接口支持,如下:

public interface Pointcut{

       ClassFilter getClassFilter(); // 决定一个类是否符合要求

       MethodMatcher getMethodMatcher(); // 决定一个方法是否符合要求

}

public interface ClassFilter{

       boolean matches(Class clazz);

}

此接口总是包含一个简单的 ClassFilter 接口的实现 --ClassFilter.TRUE ,它是规范的适合任何类的 ClassFilter 实例,它适合于只根据方法决定什么时候符合要求的切入点。

public interface MethodMatcher{

       boolean matches(Method m,class targetClass);// 静态的决定一个方法是否被通知织入

       public boolean isRuntime();// 决定是静态的还是动态的织入

       public boolean mathes(Method m,Class targetClass,Object []args);// 动态的决定一个方法是否被通知织入,系统开销会增加,不推荐使用

}

 

 

大多数的切面是由定义切面行为的通知和定义切面在什么地方执行的切入点给合而成的, Spring 为此提供了 Advisor ,它把通知和切入点组合到一个对象中。接口 PointcutAdvisor 提供了这些功能,接口如下:

public interface PointcutAdvisor{

       Pointcut getPointcut();

       Advice getAdvice();

}

大多数 Spring 自带的切入点都有一个对应的 PointcutAdvisor 。这样方便你在一个地方定义通知和切入点。

 

使用 Spring 的静态切入点

Spring 为创建静态切入点提供了方便的父类: StaticMethodMatcherPointcut 。如果想自定义静态切入点的话,继承这个类,并实现 isMatch 方法就 OK 了。

Spring 提供了一个静态切入点的实现类: NameMatchMethodPointcut 。它有如下两个方法:

Public void setMappedName(String);

Public void setMappedNames(String []);

这个类通过名字映射,上面两个方法的参数中均可以使用通配符 *

 

规则表达式切入点, Spring 提供了 RegexpMethodPointcut 让你利用正则表达式的力量来定义切入点。

符号

描述

示例

.

匹配任何单个字符

setFoo. 匹配 setFooB, 但不匹配 setFoo setFooBar

+

匹配前一个字符一次或多次

setFoo.+ 匹配 setFooBar setFooB, 但不匹配 setFoo

*

匹配前一个字符 0 次或多次

setFoo.* 匹配 setFoo,setFooB setFooBar

\

匹配任何正则表达式符号

\.setFoo. 匹配 bar.setFoo, 但不匹配 setFoo

如果你想匹配所有 setXxx 方法,我们需要使用 .*set*. 模版 ( 第一个通配符匹配任何类名。笔者认为此处《 Spring in action 》一书中有误,我认为此处应为 .*set.*) 。如果使用 RegexpMethodPointcut ,你需要在你的应用系统中引入 ORO 类库。

<bean id=”queryPointcutAdvisor”

       Class=”org.springframework.aop.support.RegExPointcutAdvisor”>

       <property name=”pattern”>

              <value>.*get.+By.+</value>

       </property>

       <property name=”advice”>

              <ref bean=”queryInterceptor”/>

       </property>

</bean>

 

使用动态切入点

Spring 提供了一种内置的动态切入点: ControlFlowPointcut 。这个切入点根据线程调用堆栈的信息来匹配方法。也就是说,它可以配置成只有当指定方法或类能在当前线程执行堆栈中找到时,返回 true

<bean id=”servletPointcut” class=”org.springframework.aop.support.ControlFlowPointcut”>

       <construct-arg>

              <value>javax.servlet.http.HttpServlet</value>

       </construct-arg>

</bean>

<bean id=”servletAdvisor” class=”org.springframework.aop.support.DefaultPointcutAdvisor”>

       <property name=”advice”>

              <ref bean=”servletInterceptor”/>

       </property>

       <property name=”pointcut”>

              <ref bean=”servletPointcut”/>

       </property>

</bean>

注: ControlFlowPointcut 明显比其他的动态切入点慢。

 

切入点实施

Spring 支持在切入点上进行操作 合并与产叉 来创建新的切入点。只有当切入点都匹配时交叉集合才匹配,任何一个切入点匹配都会使合并集合匹配。 Spring 为创建这两种切入点提供了两个类:第一个类是 ComposablePointcut 。通过将已有的 ComposablePointcut 、切入点、 MethodMatcher 以及 ClassFilter 对象进行合并或交叉,组装成一个新的 ComposablePointcut 对象。这可以通过调用 ComposablePointcut 实例的 intersection () union () 方法实现。

ComposablePointcut cp=new ComposablePoint()

cp=p.intersection(myPointcut).union(myMethodmatcher);

为了对两个 Pointcut 对象进行合并,必须使用 Pointcuts 类。这是一个工具类,它拥有很多操作 Pointcut 对象的静态方法。如:

Pointcut union=Pointcuts.union(pointcut1,pointcut2);

 

创建引入

引入与其他类型的 Spring 通知有所不同。其它类型通知是在方法调用的周围织入到不同的连接点,而引入则是影响整个类,他们通过给需要消息的类型添加方法和属性来实现。也就是说,你可以用一个已存在的类让它实现另外的接口,维持另外的状态 ( 这也叫混合 ) 。换句话说,引入让你能够动态地建立复合对象,提供了多态继承的好处。

实现 IntroductionInterceptor

Spring 通过一个特殊的方法拦截器接口 IntroductionMethodInterceptor 来实现引入。这个接口有一个方法:

Boolean implementsInterface(Class intf);

如果 IntroductionMethodInterceptor 是为了实现指定接口,那么方法 implementsInterface 应该返回 true 。就是说,对用这个接口声明的方法的任何调用将被委托给 IntroductionMethodInterceptor invoke() 方法。 Invoke() 方法负责实现这个方法,不能调用 MethodInvocation.proceed() 。它引入了新的接口,调用目标对象是没有用的。

 

使用 ProxyBeanFactory

BeanFactory 对象是一个负责创建其他 JavaBean JavaBean 。属性列表参照<<Spring in action>>

 

属性

使 

target

代理的目标对象

proxyInterfaces

代理应该实现的接口列表

interceptorNames

需要应用到目标对象上的通知 Bean 的名字。可以是拦截器, Advisor 或其他通知类型的名字。这个属性必须按照在 BeanFactory 中使用的顺序设置。

singleton

是否返回的是同一个代理实例。如果使用的是状态通知,应该设置为 false

aopProxyFactory

使用的 ProxyFactoryBean 实现

exposeProxy

目标对象是否需要得到当前的代理。通过调用 AopContext.getCurrentProxy 实现。记住这样做会在你的代码中引入 Spring 专有的 AOP 代码,所以,尽量避免使用。

frozen

一旦工厂被创建,是否可以修改代理的通知。

optimize

是否对创建的代理进行优化 ( 仅适用于 CGLIB)

ProxyTargetClass

是否代理目标类,而不是实现接口。 ( 需要 CGLIB 支持 )

 

大多数情况下我们只用到前三个属性。

如果想避免将目标对象暴露给系统中其他 Bean 的话,可以将它声明为一个内部 Bean

proxyInterfaces 属性指定了从工厂中创建的 Bean 需要实现的接口。如:

<property name=”proxyInterfaces”>

       <value>com.springinaction.service.CourseService</value>

</property>

这样就让 ProxyBeanFactory 知道它创建的所有 Bean 都要实现 CourseService 接口。可以像这样只提供一个接口,也可以用 <list> 提供多个接口。

interceptorNames 属性定义了一个应用到目标对象上的 Advisor 或通知 Bean 的列表。目标 Bean 也可以放在此属性的 <list> 列表的最后,但是最好还是用 Target 属性设置目标 Bean

 

自动代理

Spring 有一个自动代理机制,它可以让容器为我们产生代理。 Spring 有两个类提供这种服务: BeanNameAutoProxyCreator DefaultAdvisorAutoProxyCreator

BeanNameAutoProxyCreator 为匹配一系列名字的 Bean 自动创建代理。它允许在名字的两端进行通配符匹配。通常用于为符合相同命名规则的 Bean 应用一个或一组切面 ( 主要是解决 target 属性配置时目标类过多的问题。 ) 如:

<bean id=”preformanceThresholdProxyCreator

Class=”org.springframework.aop.framework.autoproxy.BeanNameAutoProxyProlyCreator”>

<property name=”beanNames”>

       <list>

              <value>*Service</value>

       </list>

</property>

<propery name=”interceptorNames”>

       <value>performaceThresholdInterceptor</value>

</property>

</bean>

如果 Bean 是一个 Advisor 或拦截器,它将应用到代理对象的所有方法上。如果是通知的话, Advisor 切入点会根据不同 Bean 将通知应用到不同的地方。

自动代理框架对于代理需要暴露哪些接口作了一些假设。目标对象实现的任何接口代理对象都要暴露出来。如果目标类没有实现任何接口,那么应用于前面讨论过的 ProxyFactoryBean 一样的规则 动态生成一个子类。

DefaultAdvisorAutoProxyCreator

这个类的奇妙之处在于它实现了 BeanPostProcessor 接口。当 ApplicationContext 读入所有 Bean 的配置信息后, DefaultAdvisorAutoProxyCreator 将扫描上下文,寻找所有的 Advisor 。它将这些 Advisor 应用到所有符合 Advisor 切入点的 Bean 中。这个代理创建器只能与 Advisor 配合使用 ( 我们知道,一个 Advisor 是一个切入点和一个通知的结合体。 DefaultAdvisorAutoProxyCreator 需要 Advisor 来知道哪些 Bean 需要通知。 )

分享到:
评论

相关推荐

    Spring AOP框架实现的结构分析

    最后,本文的目标是从实现的角度来认识 SpringAOP 框架,观察的角度是从外部接口、内部实现、组成部分、执行过程四个方面来认识 SpringAOP 框架。本文的风格是首先列出 AOP 的基本概念,然后介绍框架所涉及到的核心...

    仿springAOP框架

    **仿Spring AOP框架详解** 在Java开发领域,Spring框架以其强大的功能和灵活性深受开发者喜爱,其中AOP(面向切面编程)是其核心特性之一。AOP允许开发者将关注点从主业务逻辑中分离出来,如日志记录、事务管理等,...

    手写springAop框架3.zip

    《手写Spring AOP框架详解》 在Java开发领域,Spring框架因其强大的功能和灵活性而备受推崇,其中AOP(面向切面编程)模块更是它的一大亮点。本文将深入探讨如何手写一个简单的Spring AOP框架,理解其背后的原理与...

    反射实现 AOP 动态代理模式(Spring AOP 的实现原理)

    面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志、安全等)与业务逻辑分离,从而提高模块化。...利用Java反射机制和Spring AOP框架,开发者可以方便地实现AOP,从而提升代码的模块化和可维护性。

    spring aop jar 包

    Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...

    第四章:Spring AOP API 设计模式1

    1. **抽象工厂模式(Abstract Factory)**:Spring AOP框架中的`AopProxyFactory`接口代表抽象工厂,如`DefaultAopProxyFactory`是其实现,负责创建代理对象。抽象工厂模式确保了客户端无需关注具体对象的创建细节,...

    spring aop支持jdk1.7的jar

    在Java 7中,虽然没有引入与AOP直接相关的重大更新,但Spring AOP框架可以充分利用Java 7的一些特性,如try-with-resources语句,提高代码的简洁性和可维护性。 aspectj-1.7.4.jar是AspectJ库的一部分,AspectJ是一...

    Spring AOP 16道面试题及答案.docx

    Spring AOP代理是框架为实现切面功能创建的对象,它在运行时实现切面协议。Spring提供了两种代理方式:JDK动态代理和CGLIB代理。JDK代理适用于那些实现了接口的类,而CGLIB代理则适用于没有实现接口的类。 引介...

    简单spring aop 例子

    Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...

    Spring AOP完整例子

    Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许开发者在不修改源代码的情况下,通过插入切面来增强或改变程序的行为。在本教程中,我们将深入探讨Spring AOP的不同使用方法,包括定义切点、通知类型...

    spring aop依赖jar包

    现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库,包含了AOP相关的类和接口。 - `spring-beans.jar`:...

    spring-aop.jar

    《深入解析Spring AOP框架——以spring-aop.jar为例》 Spring AOP,全称Aspect Oriented Programming(面向切面编程),是Spring框架的核心部分之一,它为Java开发者提供了强大的面向切面的编程能力。本文将围绕...

    Spring AOP面向方面编程原理:AOP概念

    2. **轻量级**:与一些需要预编译器的AOP框架不同,Spring AOP无需特殊的工具或编译步骤即可使用。这种轻量级的特性使得Spring AOP更易于学习和集成。 3. **灵活的通知模型**:Spring AOP提供了多种类型的通知,...

    spring AOP依赖三个jar包

    Spring AOP和其他AOP框架(如AspectJ)都实现了这些接口,以实现方法拦截和通知机制。 2. aspectjweaver-1.7.0.jar:这是AspectJ的织入器,负责在运行时动态地将切面(aspect)织入到目标类中。AspectJ提供了一种...

    spring aop 五个依赖jar

    5. **aopalliance-1.0.jar**:AOP Alliance是一个库,定义了一些通用的AOP接口,使得不同的AOP框架(如Spring AOP和AspectJ)可以互操作。它包含了一些基本的AOP概念,如Advisor、Pointcut和Proxy等,是连接不同AOP...

    Spring Aop四个依赖的Jar包

    Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要模块,它通过提供声明式的方式来实现面向切面编程,从而简化了应用程序的开发和维护。在Spring AOP中,我们无需深入到每个...

    Spring AOP实现机制

    Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的可复用性和可维护性。 ### 1. ...

    spring_aop.zip

    "spring-aop.jar"包含了Spring AOP框架的核心类和接口,如org.springframework.aop.*包下的内容,它提供了基于代理的AOP实现。而"spring-aspects.jar"则包含了一些预定义的AspectJ切面,比如事务管理方面的支持。 ...

Global site tag (gtag.js) - Google Analytics