Spring中AOP实现.docx

上传人:b****7 文档编号:9517643 上传时间:2023-02-05 格式:DOCX 页数:45 大小:25.43KB
下载 相关 举报
Spring中AOP实现.docx_第1页
第1页 / 共45页
Spring中AOP实现.docx_第2页
第2页 / 共45页
Spring中AOP实现.docx_第3页
第3页 / 共45页
Spring中AOP实现.docx_第4页
第4页 / 共45页
Spring中AOP实现.docx_第5页
第5页 / 共45页
点击查看更多>>
下载资源
资源描述

Spring中AOP实现.docx

《Spring中AOP实现.docx》由会员分享,可在线阅读,更多相关《Spring中AOP实现.docx(45页珍藏版)》请在冰豆网上搜索。

Spring中AOP实现.docx

Spring中AOP实现

1.什么是SpringAOP

什么是aop:

AspectOrientedProgramming的缩写,面向切面编程,通过预编译和动态代理实现程序功能的

统一维护的一种技术

主要功能:

日志记录,性能统计,安全控制,事务处理,异常处理等

2.SpringAOP框架的用途

提供了声明的企业服务,特别是EJB的替代服务的声明

允许用户控制自己的方面,以完成OOP和AOP的互补使用

OOP:

模拟真实的世界,一切皆是对象

3.AOP的实现方式

下边这两种Spring都是支持的

3.1预编译

-AspectJ 完整的面向切面编程解决方案--》spring不是完整的解决方案,不过spring提供比较好的实现方式,当然spring是同时也是支持这种方式的,这也是一种常用的方式

3.2运行期间动态代理(JDK动态代理,CGLib动态代理)

-SpringAop,JbossAop

Spring的AOP使用纯java实现,无需特殊的编译过程,不需要控制类的加载器层次,目前只支持方法的执行的连接点(通知SpringBean某个方法执行)

不是为了提供完整AOP实现;而是侧重于一种AOP于IOC容器之间的整合,SpringAOP不会AspectJ(完整的AOP解决方案)竞争

Spring没有使用AspectJ的时候,也可以通过如下方式实现AOP

SpringAOP默认使用标准的JavaSE动态代理作为AOP代理,这使得任何接口(或者集合)都可以被代理

SpringAOP中也可以使用CGLIB代理(如果一个业务对象没有实现一个接口)

有接口的:

使用JDK的动态里

无接口的:

使用CGLIB代理

4.SpringAOP中的一些概念

在实际使用SpringAOP之前,了解他的概念是必不可少的一个过程, 

SpringAOP主要围绕以下概念展开:

切面(Aspect)一个关注点的模块化,这个关注点可能会横切多个对象

连接点(Joinpoint)程序执行过程中某个特定的连接点

通知(Advice)在切面的某个特的连接点上执行的动作

切入点(Pointcut)匹配连接的断言,在Aop中通知和一个切入点表达式关联

引入(Intruduction)在不修改类代码的前提下,为类添加新的方法和属性

目标对象(TargetObject)被一个或者多个切面所通知的对象

Aop代理(AOPProxy)AOP框架创建的对象,用来实现切面契约(aspectcontract)(包括方法执行等)

织入(Weaving)把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象,氛围:

编译时织入,类加载时织入,执行时织入

通知类型Advice:

前置通知(beforeadvice)在某个连接点(jionpoint)之前执行的通知,但不能阻止连接点前的执行(除非抛出一个异常)

返回后通知(afterreturningadvice)在某个连接点(jionpoint)正常执行完后执行通知

抛出异常通知(afterthrowingadvice)在方法异常退出时执行的通知

后通知(after(finally)advice)在方法抛出异常退出时候的执行通知(不管正常返回还是异常退出)

环绕通知(aroundadvice)包围一个连接点(jionpoint)的通知 

切入点Pointcut:

SpringAOP占时仅仅支持方法的连接点

execution(public**(..))切入点为执行所有的public方式时

execution(*set*(..))切入点执行所有的set开始的方法时

execution(*com.xyz.service.Account.*(..))切入点执行Account类的所有方法时

execution(*com.xyz.service..(..))切入点执行com.xyz.service包下的所有方法时

execution(*com.xyz.service...(..))切入点执行com.xyz.service包以及其子包的所有的方法时

上边这种方式aspectj和springaop通用的,其他方式可以自己查找资料 

5.SpringAOP实现

上边的一些概念,看过后可能还是不懂,可以自行查阅资料,下边我也会说明

我们在Java项目开发中,AOP常见的配置有如下3种:

a.基于SpringAOP容器的实现,使用AspectJ(Spring封装了AspectJ的使用),这是一种比较常用的方式,可以很容易看清代码结构

b.运行期间的动态代理实现,这是一种比较老的实现方式,比较繁琐

c.注解实现,这种方式开发起来简单,但是不利于后期维护,比如说很难找出你所有使用了SpringAOP注解的地方

这里我主要介绍第一种,和第二种的使用

5.1SpringAOP中的容器实现

5.1.1前置通知 before

某个需要切入的方法之前执行切面中的方法  Spring所有的切面通知都必须放在一个

config>内(可以配置多个

config>元素),每一个

config>可以包含pointcut,adviso

和aspect元素(注意这些元素的出现是由顺序的) 

配置文件:

spring-aop-schema-advice.xml

声明了切面类,当切入点中匹配到了类名包含BIZ字符串的类时,选取面类中的一个方法,在选取某种Adivice通知,切入该方法的执行过程其中:

aop:

aspect中id的值任意(表意性强) ref的值为切面类的id值    aop:

pointcut中expression写切入点表达式,说明那个方法可能需要做切入点   aop:

before中method的值为切面中的方法名说明切入那个方法,pointcut-ref的值为切入点的id值

xmlversion="1.0"encoding="UTF-8"?

>

//www.springframework.org/schema/beans"

xmlns:

xsi="http:

//www.w3.org/2001/XMLSchema-instance"

xmlns:

aop="http:

//www.springframework.org/schema/aop"

xsi:

schemaLocation="http:

//www.springframework.org/schema/beanshttp:

//www.springframework.org/schema/beans/spring-beans-3.2.xsd

http:

//www.springframework.org/schema/aophttp:

//www.springframework.org/schema/aop/spring-aop-3.2.xsd">

--切面类-->

--业务类-->

--aop配置可以配置多个-->

config>

--切面类-->

aspectid="aspectTest"ref="myAspect">

--切入点标识切入点aop包下类名包含Biz的类的所有方法-->

pointcutexpression="execution(*com.briup.spring.aop.bean.annotation.aop.*Biz.*(..))"id="myPointcut"/>

--通知,通过切入点切入切入切面类中的before方法-->

beforemethod="before"pointcut-ref="myPointcut"/>

aspect>

config>

切面类:

 

切面类中的某个方法,一般是用于切入业务类中的某个方法在某种状态时切入

/*

*声明一个切面类

**/

publicclassMyAspect{

publicvoidbefore(){

System.out.println("aspectbefore");

}

}

业务类:

//业务类

publicclassAspectBiz{

publicvoidbiz(){

System.out.println("Aspectbiz");

}

}

测试:

@Test

publicvoidaspectBefore(){

ClassPathXmlApplicationContextac=newClassPathXmlApplicationContext("com/briup/spring/chap4/spring-aop-schema-advice.xml");

AspectBizaspectBiz=(AspectBiz)ac.getBean("aspectBiz");

aspectBiz.biz();

}

结果:

aspectbefore

Aspectbiz

通过结果可以看出,前置通知在业务类AspectBiz的方法biz执行之前执行了before方法 

5.1.2后置通知after-returning

某个需要切入的方法执行完成之后执行切面中指定的方法  配置文件:

spring-aop-schema-advice.xml

config>

--切面类-->

aspectid="aspectTest"ref="myAspect">

--切入点标识切入点aop包下类名以Biz结尾的类的所有方法-->

pointcutexpression="execution(*com.briup.spring.aop.bean.annotation.aop.*Biz.*(..))"id="myPointcut"/>

--通知,通过切入点切入切入切面类中的before方法在执行切入点指定的方法之前执行-->

beforemethod="before"pointcut-ref="myPointcut"/>

--返回之后的通知-->

after-returningmethod="afterReturning"pointcut-ref="myPointcut"/>

aspect>

config>

切面类:

添加afterReturning方法

/*

*声明一个切面类

**/

publicclassMyAspect{

publicvoidbefore(){

System.out.println("aspectbefore");

}

publicvoidafterReturning(){

System.out.println("aspectafterReturning");

}

}

结果:

aspectbefore

Aspectbiz

aspectafterReturning

结果可以看出,后置通知会在业务方法的执行之后

5.1.3异常通知after-throwing

在方法抛出异常后的通知配置文件:

spring-aop-schema-advice.xml

config>

--切面类-->

aspectid="aspectTest"ref="myAspect">

--切入点标识切入点aop包下类名以Biz结尾的类的所有方法-->

pointcutexpression="execution(*com.briup.spring.aop.bean.annotation.aop.*Biz.*(..))"id="myPointcut"/>

--通知,通过切入点切入切入切面类中的before方法在执行切入点指定的方法之前执行-->

beforemethod="before"pointcut-ref="myPointcut"/>

--返回之后的通知-->

after-returningmethod="afterReturning"pointcut-ref="myPointcut"/>

---->

after-throwingmethod="afteThrowing"pointcut-ref="myPointcut"/>

aspect>

config>

切面类:

/*

*声明一个切面类

**/

publicclassMyAspect{

publicvoidbefore(){

System.out.println("aspectbefore");

}

publicvoidafterReturning(){

System.out.println("aspectafterReturning");

}

publicvoidafteThrowing(){

System.out.println("aspectafteThrowing");

}

}

业务类:

修改为如下:

publicvoidbiz(){

System.out.println("Aspectbiz");

thrownewRuntimeException();//出现异常的时候afteThrowing才会执行

}

测试和结果:

aspectbefore

Aspectbiz

aspectafteThrowing

上边的结果由于抛出异常后,不会正常的返回所有没有aspectafterReturning输出

5.1.4最终通知after(finally)advice 

不管方法是否会抛出异常都会通知,就像try...catch..finallly配置文件:

spring-aop-schema-advice.xml

config>

--切面类-->

aspectid="aspectTest"ref="myAspect">

--切入点标识切入点aop包下类名以Biz结尾的类的所有方法-->

pointcutexpression="execution(*com.briup.spring.aop.bean.annotation.aop.*Biz.*(..))"id="myPointcut"/>

--通知,通过切入点切入切入切面类中的before方法在执行切入点指定的方法之前执行-->

beforemethod="before"pointcut-ref="myPointcut"/>

--返回之后的通知-->

after-returningmethod="afterReturning"pointcut-ref="myPointcut"/>

---->

after-throwingmethod="afteThrowing"pointcut-ref="myPointcut"/>

--after(finally)advice不管是否抛出异常,最后都会执行的方法-->

aftermethod="after"pointcut-ref="myPointcut"/>

aspect>

config>

切面类:

/*

*声明一个切面类

**/

publicclassMyAspect{

publicvoidbefore(){

System.out.println("aspectbefore");

}

publicvoidafterReturning(){

System.out.println("aspectafterReturning");

}

publicvoidafteThrowing(){

System.out.println("aspectafteThrowing");

}

publicvoidafter(){

System.out.println("aspectafter(finally)");

}

}

业务类:

//业务类

publicclassAspectBiz{

publicvoidbiz(){

System.out.println("Aspectbiz");

thrownewRuntimeException();

}

}

测试结果:

aspectbefore

Aspectbiz

aspectafteThrowing

aspectafter(finally)

从结果中可以看出,抛出异常后,切面类中的after方法还是可以执行 

如果业务类如下:

没有异常,

publicclassAspectBiz{

publicvoidbiz(){

System.out.println("Aspectbiz");

}

}

结果:

aspectbefore

Aspectbiz

aspectafter(finally)

由以上结果可以看到,不管怎么样after方法还是会执行,很像try...catch..finally 

5.1.5环绕通知around 

在方法的执行前后执行通知配置文件:

spring-aop-schema-advice.xml

config>

--切面类-->

aspectid="aspectTest"ref="myAspect">

--切入点标识切入点aop包下类名以Biz结尾的类的所有方法-->

pointcutexpression="execution(*com.briup.spring.aop.bean.annotation.aop.*Biz.*(..))"id="myPointcut"/>

--通知,通过切入点切入切入切面类中的before方法在执行切入点指定的方法之前执行-->

beforemethod="before"pointcut-ref="myPointcut"/>

--返回之后的通知-->

after-returningmethod="afterReturning"pointcut-ref="myPointcut"/>

---->

after-throwingmethod="afteThrowing"pointcut-ref="myPointcut"/>

--after(finally)advice不管是否抛出异常,最后都会执行的方法-->

aftermethod="after"pointcut-ref="myPointcut"/>

--adrounadvice环绕通知,方法的第一参数必须是ProceedingJoinPoint类型-->

aroundmethod="around"pointcut-ref="myPointcut"/>

aspect>

config>

切面类:

可以看出,环绕方法的第一参数必须四ProceedingJoinPoint类型

/*

*声明一个切面类

**/

publicclassMyAspect{

publicvoidbefore(){

System.out.println("aspectbefore");

}

publicvoidafterReturning(){

System.out.println("aspectafterReturning");

}

publicvoidafteThrowing(){

System.out.println("aspectafteThrowing");

}

publicvoidafter(){

System.out.println("aspectafter(finally)");

}

publicvoidaround(ProceedingJoinPointjoinPoint){

Objectobject=null;

try{

System.out.println("aspectaround1");//方法执行前

object=joinPoint.proceed();//代表业务方法的执行

System.out.println("aspectaround1");//方法执行后

}catch(Throwablee){

e.printStackTrace();

}

}

}

测试结果:

aspectaround1

Aspectbiz

aspectaround1

从结果可以看出,joinPoint.proceed其实就是执行业务方法,我们可以在其之前做和之后做一些操作 

5.1.6通知中的参数传递这里我们列举环绕通知中的参数参数传递,其他通知也是同样的方式。

配置文件:

spring-aop-schema-advice.xml

xmlversion="1.0"encoding="UTF-8"?

>

//www.springframework.org/schema/beans"

xmlns:

xsi="http:

//www.w3.org/2001/XMLSchema-instance"

xmlns:

aop="http:

//www.springframework.org/schema/aop"

xsi:

schemaLocation="http:

//www.sprin

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 人文社科 > 广告传媒

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1