Spring AOP

最近研究一下Spring,就写了一篇Spring AOP的文章,希望大家能够很快的上手,例子是李刚老师的一本书中的,我参考了一下,把自己的理解来和大家一起分享学习。
AOP(Aspect Oriented Programming)提供了另外一种角度来思考程序结构,这种方式弥补了面向对象编程(OOP)的不足。将程序中的交叉业务逻辑提取出来,称之为切面。AOP是将这些切面动态的织入到目标对象,然后生成一个代理对象的过程。主要的功能有:日志记录,性能统计,安全控制,事务处理,异常处理等。

首先我们要明白一下Spring AOP中的几个概念:

1.切面(Aspect): 一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。 在Spring AOP中,切面可以使用通用类(基于模式的风格) 或者在普通类中以 @Aspect 注解(@AspectJ风格)来实现。

2.连接点(Joinpoint): 在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。 在Spring AOP中,一个连接点 总是 代表一个方法的执行。 通过声明一个org.aspectj.lang.JoinPoint类型的参数可以使通知(Advice)的主体部分获得连接点信息。

3. 通知(Advice): 在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类型,其中包括“around”、“before”和“after”等通知。 通知的类型将在后面部分进行讨论。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。

4.切入点(Pointcut): 匹配连接点(Joinpoint)的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。 切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。

5.引入(Introduction): (也被称为内部类型声明(inter-type declaration))。声明额外的方法或者某个类型的字段。 Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。 例如,你可以使用一个引入来使bean实现 IsModified 接口,以便简化缓存机制。

6.目标对象(Target Object): 被一个或者多个切面(aspect)所通知(advise)的对象。也有人把它叫做 被通知(advised) 对象。 既然Spring AOP是通过运行时代理实现的,这个对象永远是一个 被代理(proxied) 对象。

7. AOP代理(AOP Proxy): AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)。 在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。 注意:Spring 2.0最新引入的基于模式(schema-based)风格和@AspectJ注解风格的切面声明,对于使用这些风格的用户来说,代理的创建是透明的。

8. 织入(Weaving): 把切面(aspect)连接到其它的应用程序类型或者对象上,并创建一个被通知(advised)的对象。 这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。 Spring和其他纯Java AOP框架一样,在运行时完成织入。
织入的形式有三种 :1.运行时织入,即在java运行的过程中,使用java提供的代理来实现织入。2.类加载织入,是指通过自定义类的加载器在JVM加载字节码的时候进行织入。3.编译器织入,使用专门的编译器来编译包括切面模块在内的整个应用程序。

通知的类型可以包括:

前置通知(Before advice): 在某连接点(join point)之前执行的通知,但这个通知不能阻止连接点前的执行(除非它抛出一个异常)。
返回后通知(After returning advice): 在某连接点(join point)正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
抛出异常后通知(After throwing advice): 在方法抛出异常退出时执行的通知。
后通知(After (finally) advice): 当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
环绕通知(Around Advice): 包围一个连接点(join point)的通知,如方法调用。这是最强大的一种通知类型。 环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它们自己的返回值或抛出异常来结束执行。
环绕通知是最常用的一种通知类型。大部分基于拦截的AOP框架,例如Nanning和JBoss4,都只提供环绕通知。
在我们的项目当中,我们可以采取注解(Annotation)的“零配置”方式还可以采取XML文件配置。

首先看一些基于注解方式的AOP
定义一个切面通过使用@Aspect标注
[b]Before增强处理[/b]

@Aspect
public class BeforeAdviceTest {

@Before("execution(* com.icss.inter.impl.*.*(..))")
public void authority(){

System.out.println("模拟权限功能...");
}

}

在上面的程序中使用@Aspect修饰了BeforeAdviceTest类,这表明该类是一个切面类,在该切面类中定义了一个authority()方法,使用@before来注解,这样就可以把这个方法转换成一个Before增强处理。
使用@Before Annotation时,直接指定了切入点表达式,指定匹配某个包下所有类的所有方法的执行作为切入点。

[b]Around增强处理[/b]

@Aspect
public class AroundAdviceTest {

@Around("execution(* com.icss.inter.impl.*.*(..))")
public Object processTx(ProceedingJoinPoint jp) throws Throwable{

System.out.println("开始事务...");
Object rvt=jp.proceed(new String[]{"被改变的参数"});
System.out.println("结束事务...");
return rvt+"新增的内容";
}

}

@Around用于标注Around增强处理,Around增强处理是功能比较强大的增强处理,它近似等于before增加处理和AfterReturning增强处理的总和,Around增强处理既可以在执行目标方法之前织入增强动作也可以在其之后织入。
[b]AfterReturning增强处理[/b]

@Aspect
public class AfterReturningAdviceTest {

@AfterReturning(returning="rvt" ,pointcut="execution(* com.icss.inter.impl.*.*(..))")
public void log(Object rvt){

System.out.println("获取目标返回值:"+rvt);
}

}

AfterReturning增强处理将在目标方法正常完成后背织入。其中returning指定了一个返回值形参名来访问目标方法的返回值。

[b]AfterThrowing增强处理[/b]

@Aspect
public class AfterThrowingAdviceTest {

@AfterThrowing(throwing="ex" ,pointcut="execution(* com.icss.inter.impl.*.*(..))")
public void doRecoveryAction(Throwable ex){
System.out.println("抛出异常:"+ex);
}
}

AfterThrowing增强处理增强处理主要用于处理程序中未处理的异常。其中throwing指定一个返回值形参名。
[b]After增强处理[/b]

@Aspect
public class AfterAdviceTest {

@After("execution(* com.icss.inter.impl.*.*(..))")
public void release(){

System.out.println("模拟方法结束后释放资源");
}

}

无论一个方法是如何结束的,After增强处理都会被织入,因此After增强处理必须准备处理正常返回和异常返回两种情况,这中增强处理通常用于释放资源。
定义一个接口:

public interface People {

public String sayHello(String name);

public void eat(String food);
}


定义一个接口的实现类:


@Component
public class Chinese implements People {

@Override
public String sayHello(String name) {
// TODO Auto-generated method stub

return name +"hello ,Spring AOP";
}

@Override
public void eat(String food) {
// TODO Auto-generated method stub
System.out.println("我在吃:"+food);
}



}
这是一个很普通的java类,采取@component注解方式

Spring 配置文件代码:

<?xml version="1.0" encoding="gb2312"?>
<!-- Spring配置文件的文件头 -->
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!--AnnotationAwareAspectJAutoProxyCreator是一个bean后处理器,该Bean后处理器将会为容器生成AOP代理-->

<bean
class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"></bean>

<!--指定自动搜索Bean组件,以及切面类 -->
<context:component-scan base-package="com.icss.inter.impl,com.icss.advice">

<context:include-filter type="annotation"
expression="org.aspectj.lang.annotation.Aspect" />

</context:component-scan>
<!--启动@AspectJ支持 -->
<aop:aspectj-autoproxy />
</beans>


主程序的测试类:

public class BeanTest {
public static void main(String[] args) throws Exception {
// 创建Spring容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");

People c=(People) ctx.getBean("chinese");
String msg=c.sayHello("ICSS");
System.out.println(msg);
c.eat("apple");

}
}


程序运行的结果:

开始事务...
模拟权限功能....
目标类的异常处理:a.txt (系统找不到指定的文件。)
结束事务...
获取目标返回值:被改变的参数:hello ,Spring AOP新增的内容
模拟方法结束后释放资源
被改变的参数:hello ,Spring AOP新增的内容
====================
开始事务...
模拟权限功能....
我在吃:被改变的参数
结束事务...
获取目标返回值:null新增的内容
模拟方法结束后释放资源

由于时间比较仓促没有太多理论的解释,如有不明白的请留言,或者有错误的情指教。

源文件如下:
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

le4

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值