Spring 是由多个部分组成,包括AOP、DAO、Conetxt、Web、MVC,并且他们都已IoC 容器为基础。Spring 这么多功能都是由于其IoC 容器的特性,实现了对多种框架的集成,但 AOP 是个例外,它不是对某个框架的集成,而是提供了面向方面编程的功能,你可以自由选择是否使用AOP。AOP 提供了强大的中间件解决方案,这使得IoC 容器更加完善。
我们可以把AOP 看做是 Sping 的一种增强,它使得 Spring 可以不需要 EJB 就能够提供声明式事务管理,或者也可以使用Spring AOP 框架的全部功能来实现自己定义的切面。
AOP将应用系统分为两部分,核心业务逻辑(Core business concerns)及横向的通用逻辑,也就是所谓的方面Crosscutting enterprise concerns,例如,所有大中型应用都要涉及到的持久化管理(Persistent)、事务管理(Transaction Management)、安全管理(Security)、日志管理(Logging)和调试管理(Debugging)等。
Spring AOP的核心设计思想:代理模式
AOP常用专业术语:
① 方面(Aspect):一个关注点的模块化,这个关注点实现可能另外横切多个对象。事务管理是J2EE应用中一个很好的横切关注点例子。方面用Spring的Advisor或拦截器实现。
② 连接点(Joinpoint):程序执行过程中明确的点,如方法的调用或特定的异常被抛出。
③ 通知(Advice):在特定的连接点,AOP框架执行的动作。各种类型的通知包括“around”、“before”和“throws”通知。通知类型将在下面讨论。许多AOP框架包括Spring都是以拦截器做通知模型,维护一个“围绕”连接点的拦截器链。
④ 切入点(Pointcut):指定一个通知将被引发的一系列连接点的集合。AOP框架必须允许开发者指定切入点,例如,使用正则表达式。
⑤ 引入(Introduction):添加方法或字段到被通知的类。Spring允许引入新的接口到任何被通知的对象。例如,你可以使用一个引入使任何对象实现IsModified接口,来简化缓存。
⑥ 目标对象(Target Object):包含连接点的对象,也被称作被通知或被代理对象。
⑦ AOP代理(AOP Proxy):AOP框架创建的对象,包含通知。在Spring中,AOP代理可以是JDK动态代理或CGLIB代理。
⑧ 编织(Weaving):组装方面来创建一个被通知对象。这可以在编译时完成(例如使用AspectJ编译器),也可以在运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
各种通知类型包括:
① Around通知:包围一个连接点的通知,如方法调用。这是最强大的通知。Aroud通知在方法调用前后完成自定义的行为,它们负责选择继续执行连接点或通过返回它们自己的返回值或抛出异常来短路执行。
② Before通知:在一个连接点之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
③ Throws通知:在方法抛出异常时执行的通知。Spring提供强制类型的Throws通知,因此你可以书写代码捕获感兴趣的异常(和它的子类),不需要从Throwable或Exception强制类型转换。
④ After returning通知:在连接点正常完成后执行的通知,例如,一个方法正常返回,没有抛出异常。
Around通知是最通用的通知类型。大部分基于拦截的AOP框架(如Nanning和Jboss 4)只提供Around通知。
Spring AOP 开发的两种方式:
① 基于@Aspect 注释符。适合在 Java 5 及以上的平台。
Spring 2.0 及以上版本可以无缝地整合Spring AOP、IoC 和 AspectJ,使得所有的AOP 应用完全融入基于 Spring 的应用体系。
② 基于Schema 模式。对 不支持Java 5 的应用开发,可以使用这种模式。
下面我们首先讲第一种方式:基于@Aspect 注释符 的应用
Spring 版本 spring-framework-3.0.5.RELEASE
需要的包:
org.springframework.core-3.0.5.RELEASE.jar
org.springframework.beans-3.0.5.RELEASE.jar
org.springframework.context-3.0.5.RELEASE.jar
org.springframework.expression-3.0.5.RELEASE.jar
org.springframework.asm-3.0.5.RELEASE.jar
org.springframework.aop-3.0.5.RELEASE.jar
org.springframework.aspects-3.0.5.RELEASE.jar
AspectJ 版本 aspectj-1.6.10
下载地址:http://www.eclipse.org/aspectj/downloads.php
需要的包:
aspectjweaver.jar
aspectjrt.jar
另外还需要的包:
aopalliance-1.0.jar 下载地址:http://sourceforge.net/projects/aopalliance/files/aopalliance/1.0/
cglib-nodep-2.1_2.jar 下载地址:http://www.findjar.com/jar/cglib/jars/cglib-nodep-2.1_3.jar.html
commons-logging-1.0.4.jar
log4j-1.2.12.jar
㈠ 定义方面类(Aspect)
在 applicationContext.xml 中启用@Aspect 注释
为了在Spring 配置中使用@Aspect 方面的注释,你必须首先启用 Spring 对于 @Aspect 的配置支持,自动代理基于该注释符来决定是否被横切。
自动代理 是指Spring 会判断一个Bean 是否使用了一个或多个切面通知,并据此生成相应的代理以拦截其方法调用,并确认通知是否如期进行。
如果 applicationContext.xml 的格式是DTD 的,可以在 applicationContext.xml 中添加如下的配置来启用@Aspect 注释 进行动态代理
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" />
声明一个切面类:
package com.demo.spring.aop;
import org.aspectj.lang.annotation.Aspect;
@Aspect
public class MyAspect {
}
然后在 applicationContext.xml 中添加如下:
<bean id="myAspect" class="com.demo.spring.aop.MyAspect"/>
㈡ 定义切入点函数(Pointcut)
Spring 中切入点知识
① AspectJ 指定切入点
● execution:匹配方法执行的连接点,这是Spring 主要的切入点指定者。
● within:限定匹配特定类型的连接点(在使用Spring AOP 的时候,在匹配的类型中定义方法的执行)。
● this:限定匹配特定类型的连接点(在使用Spring AOP 的时候,在匹配的类型中定义方法的执行),其中 Bean Refrence(Spring Aop 代理) 是指定代理类型的实例。
● target:限定匹配特定类型的连接点(在使用Spring AOP 的时候,方法被执行),其中目标对象(被代理 Application Object) 是指定类型的实例。
● args:限定匹配特定类型的连接点(在使用Spring AOP 的时候,方法被执行),其中参数是指定类型的实例。
● @target:限定匹配特定类型的连接点(在使用Spring AOP 的时候,方法被执行),其中执行的对象的类已经有指定类型的注解。
● @args:限定匹配特定类型的连接点(在使用Spring AOP 的时候,方法被执行),其中实际传入参数在运行时,类型有指定类型的注解。
● @within:限定匹配特定类型的连接点,其中连接点所在类型已指定注解(在使用Spring AOP 的时候,所执行方法的所在类型已经注解)。
● @annotation:限定匹配特定类型的连接点(在使用Spring AOP 的时候,方法被执行),其中连接点的主题有某种给定的注解。
② 切入点表达式的匹配模式
execution( 【修饰符】 返回类型 【全类名】 方法名(参数类型)【异常类型】)
其中 修饰符、全类名、异常类型为可选
一些常见的切入点的例子
execution(public * * (. .)) 任意公共方法被执行时,执行切入点函数。
execution( * set* (. .)) 任何以一个“set”开始的方法被执行时,执行切入点函数。
execution( * com.demo.service.AccountService.* (. .)) 当接口AccountService 中的任意方法被执行时,执行切入点函数。
execution( * com.demo.service.*.* (. .)) 当service 包中的任意方法被执行时,执行切入点函数。
within(com.demo.service.*) 在service 包里的任意连接点。
within(com.demo.service. .*) 在service 包或子包的任意连接点。
this(com.demo.service.AccountService) 实现了AccountService 接口的代理对象的任意连接点。
target(com.demo.service.AccountService) 实现了AccountService 接口的目标对象的任意连接点。
args(java.io.Serializable) 任何一个只接受一个参数,且在运行时传入参数实现了 Serializable 接口的连接点。
★ 定义切入点函数
@Pointcut("execution(* execute(..)) && target(com.demo.spring.test.HelloWorld)" )
public void pointcut(){
}
或
@Pointcut("execution(* execute(..)) && target(com.demo.spring.test.HelloWorld) && args(arg, . .)" )
public void pointcut(String arg){
}
★ 定义通知函数
前置通知 (Before Advice)
@Before("pointcut() && args(arg, . .)")
public void beforeExecute(JoinPoint thisJoinPoint,Object arg ){
System.out.println("连接点类型:" + thisJoinPoint.getKind());
System.out.println("代理类名:" + thisJoinPoint.getSourceLocation().getClass().getName());
System.out.println("目标类名:" + thisJoinPoint.getTarget().getClass().getName());
System.out.println("目标函数名:" + thisJoinPoint.getSignature().getName());
System.out.println("参数个数:" + thisJoinPoint.getArgs().length);
System.out.println("参数值:" + arg);
System.out.println("Before Advice!");
}
返回后通知(After returning Advice)
@AfterReturning(pointcut = "pointcut()", returning = "retVal")
public void afterExecuet(JoinPoint thisJoinPoint, Object retVal){
System.out.println("return " + retVal);
}
抛出异常后通知(After Throwing Advice)
@AfterThrowing(pointcut = "pointcut()", throwing = "ex")
public void afterThrowing(JoinPoint thisJointPoint, Exception ex){
System.out.println("Throwing "+ex);
}
后通知 (After Advice)
@After("pointcut()")
public void afterExecute(JoinPoint thisJoinPoint){
System.out.print("After Advice!");
}
环绕通知(Around Advice)
@Around("pointcut()")
public Object userOperate(ProceedingJoinPoint thisJoinPoint) throws Throwable{
System.out.println("Around Advice!");
return thisJoinPoint.proceed();
}
上面的每个通知函数都有一个
JoinPoint 类型 和 ProceedingJoinPoint 类型的参数,通过该参数可以获得目标类的信息。
㈢ 建立目标函数
public class HelloWorld {
protected String message;
public String getMessage(){
return message;
}
public void setMessage(String message){
this.message = message;
}
public void execute(){
System.out.println("Hello "+getMessage()+"!");
}
}
然后在 applicationContext.xml 中添加如下:
<bean id="helloWorld" class="com.demo.spring.test.HelloWorld">
<property name="message">
<value>World</value>
</property>
</bean>
注:环绕通知与前置通知和后置通知的区别:
环绕通知:
1)环绕通知 目标方法的调用由环绕通知决定,使得通知有机会 即 在目标方法执行之前 又 在执行之后 运行。它可以决定目标方法什么时候执行,如何执行,甚至是否 执行。
2)环绕通知 可以控制返回对象,即你可以返回一个与目标对象完全不同的返回值,虽然这很危险,但是你却可以办到。目标方法的返回值 就是 环绕通知的返回值。proceed() 方法可以在通知体内调用一次、多次 或根本不用调用。
如果环绕通知体内的返回类型与目标方法的返回类型一致为thisJoinPoint.proceed();则在目标方法前执行,如果返回类型与目标方法的返回类型不一致,则在目标方法后执行,如果返回为null,则不表方法不执行。
前置通知和后置通知:
1)前置和后置通知是不能决定 目标方法什么时候执行,如何执行,甚至是否 执行,他们只是在目标方法调用前后执行通知而已,即目标方法肯定是要执行的。
2)而后置方法是无法办到 返回一个与目标对象完全不同的返回值,因为他是在目标方法返回值后调用。
#########################################################################################################
当Sturts2 与 Spring 整合开发时,用Spring AOP 来实现 Struts2 的事务管理时,应该注意的问题:
spring对AOP的支持
1、如果目标对象实现了接口,默认会采用JDK的动态代理机制实现AOP
2、如果目标对象实现了接口,可以强制使用CGLIB实现AOP
3、如果目标对象没有实现接口,必须使用CGLIB生成代理
4、如果代理的目标对象有多个,有实现接口的,有没有实现接口的,spring会自动在CGLIB和JDK动态代理之间切换
.如何强制使用CGLIB生成代理?
① 添加包文件 cglib-nodep-2.1_2.jar
② 在applicationContext.xml 中添加红色部分:
<bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" >
<property name="proxyTargetClass" value="true/">
</bean>
如果是Schema 方式添加如下:
<aop:aspectj-autoproxy proxy-target-class="true"/>
JDK代理和CGLIB代理的区别
* JDK的代理对象 必须实现一个或多个接口。
* CGLIB代理的是 没有实现接口的对象,是针对类实现代理的,主要对指定的类生成一个子类,并覆盖其中的方法。
因为是继承,所以不能使用final来修饰类或方法。
分享到:
相关推荐
Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的重要组成部分,它提供了一种在不修改源代码的情况下,对程序进行功能增强的技术。这个"spring aop jar 包"包含了实现这一功能所需的类和接口,...
Spring AOP,全称为Aspect Oriented Programming,是面向切面编程的一种编程范式,它是对传统的面向对象编程(OOP)的一种补充。在OOP中,核心是对象,而在AOP中,核心则是切面。切面是关注点的模块化,即程序中的...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点问题,如日志、事务管理、安全性等。本示例将简要介绍如何在Spring应用中实现AOP,通过实际的...
3、对spring aop认识模糊的,不清楚如何实现Java 自定义注解的 4、想看spring aop 注解实现记录系统日志并入库等 二、能学到什么 1、收获可用源码 2、能够清楚的知道如何用spring aop实现自定义注解以及注解的逻辑...
Spring AOP 是一种面向切面编程的技术,它允许我们在不修改源代码的情况下,对应用程序的特定部分(如方法调用)进行增强。在 Spring 中,AOP 的实现主要依赖于代理模式,有两种代理方式:JDK 动态代理和 CGLIB 动态...
Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许开发者在不修改源代码的情况下,通过插入切面来增强或改变程序的行为。在本教程中,我们将深入探讨Spring AOP的不同使用方法,包括定义切点、通知类型...
Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的一个重要模块,它通过提供声明式的方式来实现面向切面编程,从而简化了应用程序的开发和维护。在Spring AOP中,我们无需深入到每个...
现在,我们回到主题——"springaop依赖的jar包"。在Spring 2.5.6版本中,使用Spring AOP通常需要以下核心jar包: - `spring-aop.jar`:这是Spring AOP的核心库,包含了AOP相关的类和接口。 - `spring-beans.jar`:...
Spring AOP 和 Spring IOC 是 Spring 框架的两个核心组件,它们对于任何基于 Java 的企业级应用开发都至关重要。Spring AOP(面向切面编程)允许开发者在不修改源代码的情况下,通过“切面”来插入新的行为或增强已...
面向切面编程(AOP)是一种编程范式,旨在将横切关注点(如日志、安全等)与业务逻辑分离,从而提高模块化。...利用Java反射机制和Spring AOP框架,开发者可以方便地实现AOP,从而提升代码的模块化和可维护性。
**Spring AOP 实现机制详解** Spring AOP(面向切面编程)是Spring框架的核心特性之一,它允许程序员在不修改源代码的情况下,通过“切面”来插入额外的业务逻辑,如日志、事务管理等。AOP的引入极大地提高了代码的...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它允许程序员在不修改源代码的情况下,通过在运行时插入额外的行为(如日志记录、性能监控等)来增强对象的功能。动态代理则是Spring AOP实现的核心技术之一...
### Spring AOP面向方面编程原理:AOP概念详解 #### 一、引言 随着软件系统的日益复杂,传统的面向对象编程(OOP)逐渐暴露出难以应对某些横切关注点(cross-cutting concerns)的问题。为了解决这一挑战,面向方面编程...
在讨论Spring AOP(面向切面编程)时,首先需要理解几个核心概念。Spring AOP 是Spring框架提供的一个功能模块,它允许开发者将横切关注点(cross-cutting concerns)从业务逻辑中解耦出来,通过在方法调用前后进行...
### Spring AOP 实现流程日志跟踪 #### 一、背景与目的 在现代软件开发过程中,为了确保系统的稳定性和可维护性,通常会引入非功能性的需求来增强应用程序的功能,比如日志记录、安全控制等。这些需求往往不是业务...
Spring AOP(面向切面编程)是Spring框架的重要组成部分,它提供了一种模块化和声明式的方式来处理系统中的交叉关注点,如日志、事务管理等。在Java应用中,AOP通过代理模式实现了切面编程,使得我们可以将业务逻辑...
### Spring AOP 入门详解 #### 一、Spring AOP 概述 Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的一个关键特性,它为开发者提供了在运行时动态添加代码(即横切关注点或切面)到已有...
Spring源码最难问题:当Spring AOP遇上循环依赖 Spring源码中最难的问题之一是循环依赖问题,当Spring AOP遇上循环依赖时,该如何解决? Spring通过三级缓存机制解决循环依赖的问题。 在Spring中,bean的实例化...
Spring AOP,即Spring的面向切面编程模块,是Spring框架的重要组成部分,它允许开发者在不修改源代码的情况下,对程序进行横切关注点的处理,如日志、事务管理等。实现这一功能,主要依赖于三个核心的jar包:aop...
在`springAop1`这个压缩包中,可能包含了一个简单的应用示例,展示了如何定义一个切面类,以及如何在该类中定义通知方法。例如,我们可能会看到一个名为`LoggingAspect`的类,其中包含了`@Before`注解的方法,用于在...