`

Spring AOP Review

阅读更多

在阅读此文之前请你熟悉一些IOC的知识,同时了解AOP的概念。

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

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

Spring 只支持方法联接点。

<?xml:namespace prefix = o ns = "urn:schemas-microsoft-com:office:office" /?>

 

 

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 方法,根据抛出的异常类型调用适当的方法。

 

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

 

 

定义切入点

切入点 就是应用通知的地方,切入点决定了一个特定的类的特定方法是否满足一条特定的规则,如果一个方法符合的话,通知就应用到该方法上。 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 。属性列表如下:

属性

使 

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 需要通知。 )

<bean id=”advisor” class=”org.springframework.aop.support.RegexpMethodPointcutAdvisor”>

       <property name=”advice”>

              <bean class=”performaceThresholdInterceptor”/>

       </property>

       <property name=”pattern”>

              <value>.+Service\..+</value>

       </property>

</bean>

<bean id=”autoProxyCreator”

class=”org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator”/>

在读入所有 Bean 的定义信息后, BeanFactory 中的所有 Advisor 将被释放出来。它们会将它们的通知配置到任何匹配它们的切入点的 Bean ( 这就是它真正的威力 )

不用显示地将 Advisor 与其他东西结合,现在只要简单地定义它们,然后让它们自动地应用到它们匹配的地方。这样松耦合 Bean 以及它们的通知就实现了。

 

Spring 也支持通过元数据 (Metadata) 驱动自动代理。这种类型自动代理,代理配置是通过源代码属性而不是外部配置文件获得的。最常见的元数据自动配置是声明式事务支持。

分享到:
评论

相关推荐

    spring-aop-review-tcf.zip

    在"spring-aop-review-tcf"这个示例中,你可以看到如何配置Spring的AOP支持,以及如何定义切面(Aspect)和通知(Advice)。切面通常包含一个或多个通知,通知定义了增强的逻辑。通知类型包括前置通知(Before)、...

    review_spring.rar

    Spring框架,作为Java开发中的核心组件,以其强大的依赖注入(DI)和面向切面编程(AOP)能力,极大地简化了企业级应用的开发。在本文中,我们将深入探讨Spring的配置方式,包括XML配置、基于注解的装配,以及Spring...

    java程序员面试题

    7. **Model4-Spring-review.doc**: 可能包含Spring框架的深入复习,包括Spring MVC的处理流程、Spring AOP的切面定义、Spring Boot的自动配置、Spring Cloud的微服务治理等。 面试准备时,Java程序员需要全面掌握...

    review_sm.rar

    3. **AOP(面向切面编程)**:SpringMVC支持AOP,用于实现日志记录、权限控制、事务管理等功能。我们可以通过定义Aspect来实现切面逻辑,并通过@Pointcut、@Before、@After等注解指定切入点和增强行为。 4. **...

    javasnmp源码-java_review:复习资料

    AOP,aop如何实现 ​ ​ JDK动态代理和cgLib动态代理 ​ ​ ​ sprin创建bean过程 ​ ​ SpringMVC常用注解 ​ springMVC处理请求流程/工作流程 ​ ​ SpringMVC @RequestParam,@PathParam,@...

    review_second-源码.rar

    2. **Spring框架**:广泛使用的Java企业级应用框架,包含IoC(控制反转)和AOP(面向切面编程)等特性。 3. **数据库连接**:如JDBC,用于与数据库交互,处理CRUD操作。 4. **RESTful API**:如果项目涉及前后端分离...

    springboot070基于springboot的大创管理系统_论文.doc

    Spring作为核心容器,提供依赖注入(DI)和面向切面编程(AOP)等功能。Spring MVC处理HTTP请求,负责视图和控制层的交互。MyBatis则作为持久层框架,实现了SQL与Java代码的解耦,使得数据库操作更为灵活。 数据库...

    Java+mysql+Linux面试题

    Spring 是一个综合性的框架,提供了许多功能模块,例如 IoC 容器、AOP、MVC 等。Spring Boot 是一个基于 Spring 的框架,提供了自动装配原理,能够快速搭建一个程序。Spring Boot 的主要特点是自动装配、快速开发和...

    【Java毕业设计】房屋租赁系统(verio_house)是一个基于 SSM 开发的标准 Java Web 项目。整.zip

    1. **Spring框架**:Spring是Java企业级应用的核心,它提供了依赖注入(DI)和面向切面编程(AOP)等核心功能,使得代码更加模块化和易于测试。在verio_house项目中,Spring可能用于管理各种bean,包括数据访问对象...

    基于SSM的民宿网站系统源码.zip

    1. **Spring框架**:Spring是Java开发的核心框架,它提供了依赖注入(DI)和面向切面编程(AOP)功能,使得代码更加模块化和易于测试。在本项目中,Spring负责管理各个组件的生命周期,如数据库连接池、服务层对象等...

    SpringWebServicesMovReview2

    3. **消息驱动的架构**:Spring Web Services基于Spring框架,支持基于消息的交互,可以利用Spring的IoC(控制反转)和AOP(面向切面编程)特性来解耦服务实现。 4. **XML处理**:Spring Web Services与XPath和XSLT...

    精选_基于SSM的校园二手交易平台_源码打包

    SSM是Java Web开发中常用的一个组合,它整合了Spring的核心控制反转(IoC)和面向切面编程(AOP),SpringMVC作为Web层的处理框架,以及MyBatis作为持久层的ORM工具。 【描述】"基于SSM的校园二手交易平台" 指出该系统...

    jsp+ssm+mysql实现的校园二手市场交易平台源码

    1. **Spring**:这是一个全面的Java应用框架,它提供了依赖注入(DI)和面向切面编程(AOP)等功能,帮助开发者管理对象之间的依赖关系,简化了代码的编写和维护。在本项目中,Spring作为整个系统的中枢,负责管理...

    JavaReview.zip

    13. **Spring框架**:Spring是Java开发中最流行的框架,提供了依赖注入、AOP、数据访问、Web MVC等功能。 14. **数据库连接**:JDBC是Java访问数据库的标准API,包括连接、执行SQL、处理结果集等操作。 15. **单元...

    JSP基于SSM网上书评软件平台可升级SpringBoot源码案例设计.zip

    Spring是核心的依赖注入(DI)和面向切面编程(AOP)框架,负责管理应用的组件和实现松耦合。SpringMVC是Spring框架的一个模块,用于构建Web应用程序,它提供了模型-视图-控制器(MVC)的架构模式。MyBatis是一个...

    ssm互助养老系统源码数据库演示.zip

    1. **Spring**:Spring是一个开源的应用框架,它管理应用对象的生命周期和配置,提供AOP(面向切面编程)支持,还有强大的数据访问层支持。在本项目中,Spring用于处理控制层的事务管理、依赖注入等核心功能。 2. **...

    基于springboot校园二手书交易管理系统.zip

    Spring提供了依赖注入和AOP(面向切面编程)等功能;SpringMVC负责处理HTTP请求,将数据模型与视图分离;MyBatis则作为持久层框架,简化了数据库操作。本系统可能使用SSM进行业务逻辑处理和数据访问。 **三、Java...

    基于SSM框架+vue的Web网盘系统的设计与实现.pdf

    * Spring框架是Java开发的核心框架,提供了依赖注入、AOP、MVC等功能。 * SpringMVC框架是基于Spring的Web应用程序框架,提供了强大的Web应用程序开发功能。 * MyBatis框架是一个持久层框架,提供了数据库交互的功能...

    kanban-board-app

    在Java编程中,kanban-board-app可能是用Spring框架构建的,这是一个广泛使用的Java企业级应用框架,提供依赖注入(DI)和面向切面编程(AOP),使得创建和维护大型项目更为便捷。Spring Boot是Spring的一个扩展,它...

Global site tag (gtag.js) - Google Analytics