Spring in Action 学习笔记—第三章创建切面
Spring的AOP(Aspect Oriented Programming)框架允许你将分散在系统中的功能放到一个地方—切面。依赖Spring的强大切入点机制,何时何地在系统中采用切面你有很多种选择。在本章中作者向我们介绍并且展示了Spring AOP基础的方方面面。
一、AOP介绍
AOP提供了另外一种思考程序结构的角度,弥补了OOP(面向对象编程)的不足。大家可以参看夏昕编写的《Spring开发指南》中的AOP部分,有简单明晰的对比和解释。就像刚开始理解OO概念一样,对于新手来说AOP也是非常抽象难以理解的,不能仅从一个概念上去定义AOP。假如我们有一个系统,分为好多个模块,每个模块都负责处理一项重要的功能。但是每个模块都需要一些相似的辅助功能如安全、日志输出等等。这就是一种交叉业务,而这种“交叉”非常适合用AOP来解决。(在AOP刚出现的时候被大家翻译成面向方面,而后来一部分人翻译成面向切面。谁更正确?也许在真正理解了AOP以后才能判断出来。)
1.AOP术语
l 切面(Aspect):切面是你要实现的交叉功能。它是应用系统模块化的一个切面领域。
l 连接点(Join point):连接点是应用程序执行过程中插入切面的地点(在程序执行过程中某个特定的点)。在Spring AOP中一个连接点代表一个方法的执行。这个点可以是方法调用,异常抛出或者是要修改的字段。通过申明一个import org.aspectj.lang.JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。
l 通知(Advice):通知切面的实际实现(参考手册:Action taken by an aspect at a particular join point.)。它通知应用系统新的行为。通知包括好多种类,在后面单独列出。(Advice一词在夏昕的《Spring开发指南》中被翻译为“处理逻辑”)
l 切入点(Pointcut):切入点定义了通知应该应用在哪些连接点。通知(Advice)可以应用到AOP的任何连接点。通知(Advice)将和一个切入点表达式关联,并在满足这个连接点的切入点上运行(例如:在执行一个特定名称的方法时)切入点表达式如何和连接点匹配是AOP的核心Spring使用缺省的AspectJ切入点的语法。
l 引入(Introduction):(也被叫做内部类型声明“inter-type declaration”)引入允许你为已经存在的类添加新的方法和属性。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。
l 目标对象(Target Object):目标对象是被通知对象。Spring AOP是运行时代里实现的,所以这个对象永远是一个被代理对象。
l 织入(Weaving):把切面(Aspect)连接到其它的应用程序类型或者对象上来创建一个被通知(advised)的对象。可以在编译时做这件事(例如使用AspectJ编译器),也可以在类加载或运行时完成。 Spring和其他纯Java AOP框架一样, 在运行时完成织入。
通知(Advice)类型:
l 前置通知(Before Advice):在一个连接点之前执行的通知,但这个通知不能阻止连接点钱的执行(除非它抛出异常)
l 返回后通知(After returning advice):在一个连接点正常完成后执行的通知。例如:一个方法正常返回,没有抛出任何异常。
l 抛出后通知(After throwing advice):在一个方法抛出异常时执行的通知。
l Finally后通知(After finally advice):当某连接点退出的时候执行的通知(不论是正常返回还是抛出异常)。
l 环绕通知(Around advice):包围一个连接点的通知,就像方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回他们自己的返回值域或抛出异常来结束执行。
2.Spring的AOP实现
在Spring中所有的通知都以Java类的形式编写。所以你可以像普通Java开发那样在IDE(Eclipse或NetBeans)中开发切面。而且,定义在什么地方应用通用的切入点通常在Spring的配置文件中配置。
Spring有两种代理创建方式:
(1) 如果目标对象(Target Object)实现了一个或多个接口暴露的方法,Spring将使用JDK的java.lang.reflect.Proxy类创建代理。
(2) 如果目标对象
(Target Object)没有实现任何接口,Spring使用CGLIB(http://cglib.sourceforge.net/ )库生成目标对象的子类。在创建这个子类的时候,Spring将通知织入,并且将对目标对象的调用委托给这个子类。注意用这种方式创建代理时需要将Spring发行包中lib/cglib文件加下的jar文件加载到工程文件中。使用这种代理时注意两点:
l 对接口创建代理优于对类创建代理,这样会产生更加松耦合的系统。
l 标记为final的方法不能被通知。
通过上面的一大堆名词解释应该对AOP以及Spring中的AOP有了一个大概的了解了。下面进一步详细解释Spring中的AOP。
二、创建通知
1.前置通知(Before Advice)
创建前置通知需要实现org.springframework.aop.MethodBeforeAdvice接口,该接口只有before(Method method, Object[] args, Object target) throws Throwable这个方法。我们可以这样理解前置通知:比如你到一个比较高档的饭店去吃饭,进门时会有礼仪小姐给你开门并且向您问好,这个礼仪小姐的行为就可以视为“前置通知”。
package springinaction.chapter03.createadvice;
import java.lang.reflect.Method;
import org.springframework.aop.MethodBeforeAdvice;
publicclass BeforeAdvice implements MethodBeforeAdvice
{
//实现MethodBeforeAdvice的before方法
publicvoid before(Method method, Object[] args, Object target)
{
System.out.println("befor advice");
}//end before
}//end class BeforeAdvice
2.返回后通知(After returning advice)
创建返回后通知需要实现org.springframework.aop.AfterReturningAdvice接口,该接口也只有一个方法:void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable。同样我们也可以这样理解After returning advice:当你在这家饭店用餐完后,礼仪小姐还会为您开门,并且欢迎您下次再来。这时礼仪小姐的行为就是“After returning advice”。
package springinaction.chapter03.createadvice;
import java.lang.reflect.Method;
import org.springframework.aop.AfterReturningAdvice;
publicclass AfterReturningAdviceImp implements AfterReturningAdvice
{
publicvoid afterReturning(Object returnValue, Method method, Object[] arg2, Object target) throws Throwable
{
System.out.println("afterReturning");
}
}
3.环绕通知(Around advice)
创建环绕通知需要实现org.aopalliance.intercept.MethodInterceptor接口,同样要实现一个invoke方法,该方法有一个MethodInvocation类型的参数。MethodInterceptor能够控制目标方法是否真的被调用。通过调用MethodInterceptor.proceed()方法来调用目标方法。MethodInterceptor让你可以控制返回的对象,你可以返回一个与proceed()方法返回对象完全不同的对象。我们可以这样理解环绕通知:当你用餐完后,饭店要确保你已经付款了,在付款后停止再出售食物给你。
package springinaction.chapter03.createadvice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
publicclass AroundAdvice implements MethodInterceptor
{
public Object invoke(MethodInvocation mi)
{
Object obj = null;
//do something....
return obj;
}//end invoke(...)
}//end class AroundAdvice()
4.抛出后通知(After throwing advice)
创建抛出后通知需要实现org.springframework.aop.ThrowsAdvice接口,该接口没有任何方法,但是要实现这个接口的类必须实现afterThorwing(Throwable throwable)或者afterThrowing(Method method, Object[] args, Object target)形式的一种,根据抛出的异常的类型恰当的方法将被调用。如果你在该饭店用餐后没有付钱就走或者多给钱他们没有找给你大概异常通知也就发生了。J
package springinaction.chapter03.createadvice;
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
publicclass AfterThorwsAdvice implements ThrowsAdvice
{
publicvoid afterThorwing(Throwable throwable)
{
//do something....
}
publicvoid afterThrowing(Method method, Object[] args, Object target)
{
//do something....
}
}
一般来说环绕通知是用的最广泛的一个通知类型,但是他们(Spring小组)鼓励我们用最合适的通知。例如我们有一个简单的验证身份的功能,那么我们只需要前置通知就可能实现我们要求的功能了。
三、定义切入点
在上面我们定义了各种通知。可以看到一个通知是要被执行的一个方法。光把通知定义出来不行,我们还要确定这些通知在我们的系统什么地方应用,否则通知是毫无用处的。这就是切入点的用处。切入点决定了一个特定的类的特定方法是否满足一条特定规则。如果确实符合,通知就应用到该方法上。
Spring根据需要织入通知的类和方法来定义切入点。Advice根据他们的特性织入目标类和方法。Spring的切入点框架的核心接口是Pointcut。
publicinterface Pointcut
{
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
ClassFilter接口决定了一个类是否符合通知的要求:
package org.springframework.aop;
publicinterface ClassFilter
{
boolean matches(Class clazz);
ClassFilter TRUE = TrueClassFilter.INSTANCE;
}
实现这个接口的类决定了以参数传入进来的类是否应该被通知。ClassFilter.TRUE是规范的的适合任何类的ClassFilter实例,他适用于创建只根据方法决定时候符合要求的切入点。
ClassFilter接口利用类过滤切面,MethodMactcher接口可以通过方法过滤切面:
package org.springframework.aop;
import java.lang.reflect.Method;
publicinterface MethodMatcher
{
boolean matches(Method method, Class targetClass);
boolean isRuntime();
boolean matches(Method method, Class targetClass, Object[] args);
MethodMatcher TRUE = TrueMethodMatcher.INSTANCE;
}
MethodMactcher接口有三个方法。matches(Method, Class)根据目标类和方法决定一个方法是否该被通知。isRuntime()方法被调用来决定MethodMatcher的类型。有两种类型:静态类型和动态类型。静态pointcut的意思是Advice总是被执行,此时的isRuntime()方法返回false。动态pointcut根据运行时方法的参数值决定通知是否需要执行,isRuntime()方法返回true。
有一个非常重要的名词Advisor:大多数切面是由定义切面行为的通知和定义切面在什么地方执行的切入点组合而成的。在Spring中把通知和切入点组合到一个对象中。PointcutAdvisor提供这些功能。
package org.springframework.aop;
publicinterface PointcutAdvisor extends Advisor
{
Pointcut getPointcut();
}
Spring中的RegexpMethodPointcut让你利用正则表达式来定义切入点。如果你对正则表达式不了解的话,赶快去学学吧,非常重要的内容。(开个玩笑的说,用了正则表达式能使你的代码上档次J),下面列出定义切入点时经常使用的符号:
符号
|
描述
|
示例
|
·
|
(英文点“.”)匹配任何单个字符
|
setFoo.匹配setFooB,但不匹配setFoo或setFooBar
|
+
|
匹配前一个字符一次或多次
|
setFoo.+匹配setFooB或setFooBar,但不匹配setFoo
|
*
|
匹配前一个字符0次或多次
|
setFoo.*匹配setFooB、setFooBar和setFoo
|
\
|
匹配任何正则表达式符号
|
\.setFoo.+匹配setFoo,但不匹配setFoo
|
下面引用《精通Srping》中的例子,这个例子讲的还是比较清晰的。如果前面的Ioc一章理解的很好的话,理解这个例子不是很难。难点在于ProxyFactoryBean这个类。
package jingtongspring;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
publicclass LoggingBeforAdvice implements MethodBeforeAdvice
{
protectedstaticfinal Log log = LogFactory.getLog(LoggingBeforAdvice.class);
publicvoid before(Method arg0, Object[] arg1, Object arg2) throws Throwable
{
log.info("before: The invocation of getContent()");
}
}
下面是配置文件:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id = "helloworldbean"
class = "org.springframework.aop.framework.ProxyFactoryBean">
<property name = "proxyInterfaces">
<value>jingtongspring.IHelloWord</value>
</property>
<property name="target">
<ref local = "helloworldbeanTarget"/>
</property>
<property name="interceptorNames">
<list>
<value>loggingBerforeAdvisor</value>
</list>
</property>
</bean>
<bean id="helloworldbeanTarget"
class="jingtongspring.HelloWord"/>
<bean id="loggingBeforAdbisor"
class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref local="loggingBeforeAdvice"/>
</property>
<property name="pattern">
分享到:
相关推荐
Spring in Action中文清晰版(带阅读笔记). Spring in Action中文清晰版(带阅读笔记).
### Spring in Action 学习笔记知识点总结 #### 1. Spring 框架基础 ##### 1.1 Spring 概述 - **轻量级**:Spring 的“轻量级”主要体现在其对资源消耗较少,同时具备低入侵性。在基于 Spring 开发的应用中,业务...
标题和描述均提到了“spring指南学习笔记”,这意味着文档聚焦于Spring框架的学习心得与关键概念。Spring是一个开源的Java企业级应用框架,以其强大的依赖注入(Dependency Injection, DI)和面向切面编程(Aspect ...
以下将详细介绍Spring学习笔记中的主要知识点。 **面向抽象编程** 面向抽象编程是一种设计原则,强调在代码中使用接口或抽象类,而不是具体实现类。这使得系统更具有灵活性,易于扩展和维护。在Spring框架中,我们...
### Spring学习笔记知识点详解 #### 一、Spring框架概述 **Spring** 是一个开源的、分层的企业级应用开发框架,旨在简化Java EE应用程序的开发。它的主要目标是提高开发效率,减少耦合度,并提供一种更为简洁的...
《Spring in Action》是一本深度剖析Spring框架的权威著作,其中文清晰版为中国的开发者提供了便利,便于理解和学习。本书全面覆盖了Spring的核心概念和技术,包括依赖注入、AOP(面向切面编程)、数据访问、Web开发...
本资源包“spring+hibernate学习笔记和项目源代码”提供了深入理解和实践这两个框架的机会,同时也包含了Struts的集成,形成经典的SSH(Spring、Struts、Hibernate)架构。以下是关于这些主题的详细知识解析: 1. *...
### Struts、Spring、Hibernate&Ajax 学习笔记总结 #### Struts 部分 **Struts** 是 Java 开源框架中最早出现且最具影响力的框架之一,它出自 Apache 组织,是 Java Web 应用开发的标准之一。Struts 以 MVC(Model...
容器(spring):管理dao,service,action,...包含并管理应用对象的生命周期和配置 框架:使用组件配置组合成复杂的应用,并提供很多基础功能 Spring提供了对开源社区中很多框架及JavaEE中很多技术的支持,让程序员很...
这个“struts+spring+hibernate学习笔记”应该涵盖了这三个框架的基础知识以及如何将它们整合使用的详细教程。 Struts是一个基于MVC(Model-View-Controller)设计模式的开源框架,主要用于控制Web应用的流程。它...
1. 学习 Spring 的基本概念和核心组件,理解 DI 和 AOP 的原理。 2. 掌握 Spring Bean 的配置和管理方式,包括 XML、注解和 JavaConfig。 3. 理解 Struts2 的工作流程,编写 Action 类并配置相应的 Action 映射。 4....
`spring_struts.txt`可能描述了如何配置Action和ActionForm,以及如何在Spring中管理Struts的业务逻辑。 6. **Spring事务管理**: Spring提供了PlatformTransactionManager接口,支持不同的事务管理策略,如编程式和...
### Spring学习笔记(最新版) #### 一、Spring框架简介 Spring框架是一个广泛使用的轻量级企业级应用框架,它提供了全面的解决方案来构建复杂的Java应用程序。Spring的核心特性包括依赖注入(Dependency Injection,...
4th》学习笔记 第一部分 Spring的核心 1. Spring之旅 依赖注入 AOP bean的初始化过程 spring容器 2. 装配Bean “initialization on demand holder”创建单例模式的理解,参考 Spring中单例的概念限于Spring上下文中,...
总之,Spring学习笔记对于理解SSH整合的全过程及其背后的设计原则非常有帮助,对于希望深入学习Java Web开发的开发者来说是一份宝贵的资源。通过实践和阅读这样的笔记,开发者可以更好地掌握这三大框架的使用,提升...
- Spring与Struts1集成,可以将Action对象交给Spring管理,通过Struts的配置让Controller管理这些Action,实现业务逻辑与展示层的分离。 以上就是Spring框架的基本知识,包括其核心特性、bean管理、依赖注入、AOP...
《Spring in Action》是关于Spring框架的一本权威指南,它深入浅出地介绍了Spring的核心概念和技术,对于理解和应用Spring框架有着重要的指导价值。在本文中,我们将围绕Spring框架的源码解析、工具使用以及相关学习...
在提供的"spring+struts集成学习笔记和项目源码"中,你将有机会深入理解这些概念,通过实际操作来学习如何将Spring的优秀特性与Struts的高效处理机制结合起来,构建出高效稳定的Web应用。源码分析和实践操作是加深...