您的位置:首页 > 编程语言 > Java开发

Spring对AOP的支持 推荐

2008-07-03 17:13 405 查看
[/b]Spring[/b]对AOP[/b]的支持[/b]
4.1 AOP[/b]介绍[/b]
首先让我们从一些重要的AOP概念和术语开始。这些术语不是Spring特有的。不过AOP术语并不是特别的直观,如果Spring使用自己的术语,将会变得更加令人困惑。
· 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象。事务管理是J2EE应用中一个关于横切关注点的很好的例子。在Spring AOP中,切面可以使用基于模式或者基于@Aspect注解的方式来实现。
· 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候。在Spring AOP中,一个连接点总是表示一个方法的执行。
· 通知(Advice):在切面的某个特定的连接点上执行的动作。其中包括了“around”、“before”和“after”等不同类型的通知(通知的类型将在后面部分进行讨论)。许多AOP框架(包括Spring)都是以拦截器做通知模型,并维护一个以连接点为中心的拦截器链。
· 切入点(Pointcut):匹配连接点的断言。通知和一个切入点表达式关联,并在满足这个切入点的连接点上运行(例如,当执行某个特定名称的方法时)。切入点表达式如何和连接点匹配是AOP的核心:Spring缺省使用AspectJ切入点语法。
· 引入(Introduction):用来给一个类型声明额外的方法或属性(也被称为连接类型声明(inter-type declaration))。Spring允许引入新的接口(以及一个对应的实现)到任何被代理的对象。例如,你可以使用引入来使一个bean实现
IsModified
接口,以便简化缓存机制。
· 目标对象(Target Object): 被一个或者多个切面所通知的对象。也被称做被通知(advised)对象。既然Spring AOP是通过运行时代理实现的,这个对象永远是一个被代理(proxied)对象。
· AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(例如通知方法执行等等)。在Spring中,AOP代理可以是JDK动态代理或者CGLIB代理。
· 织入(Weaving):把切面连接到其它的应用程序类型或者对象上,并创建一个被通知的对象。这些可以在编译时(例如使用AspectJ编译器),类加载时和运行时完成。Spring和其他纯Java AOP框架一样,在运行时完成织入。
[align=left]通知类型:[/align]

前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
异常通知(After throwing advice):在方法抛出异常退出时执行的通知。
最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。

[align=left] 环绕通知是最常用的通知类型。和AspectJ一样,Spring提供所有类型的通知,我们推荐你使用尽可能简单的通知类型来实现需要的功能。例如,如果你只是需要一个方法的返回值来更新缓存,最好使用后置通知而不是环绕通知,尽管环绕通知也能完成同样的事情。用最合适的通知类型可以使得编程模型变得简单,并且能够避免很多潜在的错误。比如,你不需要在JoinPoint上调用用于环绕通知的proceed()方法,就不会有调用的问题。在Spring 2.0中,所有的通知参数都是静态类型,因此你可以使用合适的类型(例如一个方法执行后的返回值类型)作为通知的参数而不是使用Object数组。 通过切入点匹配连接点的概念是AOP的关键,这使得AOP不同于其它仅仅提供拦截功能的旧技术。 切入点使得通知可以独立对应到面向对象的层次结构中。例如,一个提供声明式事务管理的环绕通知可以被应用到一组横跨多个对象的方法上(例如服务层的所有业务操作)。 [/align]
[align=left] 4.2 [/b]创建通知[/b][/align]
[align=left] 我们通过一个简单的例子来理解AOP。[/align]
[align=left] 代码清单1[/align]
[align=left]public class Foo {[/align]
[align=left] public void printName(String name){[/align]
[align=left] System.out.println("The Name is : " + name);[/align]
[align=left] }[/align]
[align=left] public void printAge(String age){[/align]
[align=left] System.out.println("The Age is : " + age);[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]import java.lang.reflect.Method;[/align]
[align=left]import org.springframework.aop.MethodBeforeAdvice;[/align]
[align=left]public class FooBeforeAdvice implements MethodBeforeAdvice{[/align]
[align=left] @Override[/align]
[align=left] public void before(Method method, Object[] args, Object object)[/align]
[align=left] throws Throwable {[/align]
[align=left] //打印出类的名称[/align]
[align=left] System.out.print("Class Name is " + [/align]
[align=left] object.getClass().getSimpleName() + " ");[/align]
[align=left] //打印出参数的值[/align]
[align=left] System.out.println("arg is "+(String)args[0] + " ");[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]import org.springframework.aop.framework.ProxyFactory;[/align]
[align=left]public class Test {[/align]
[align=left] public static void main(String[] args) {[/align]
[align=left] Foo foo = new Foo();[/align]
[align=left] FooBeforeAdvice advice = new FooBeforeAdvice();[/align]
[align=left] //Spring提供的代理工厂[/align]
[align=left] ProxyFactory pf = new ProxyFactory();[/align]
[align=left] //设置代理目标[/align]
[align=left] pf.setTarget(foo);[/align]
[align=left] //为代理目标添加增强[/align]
[align=left] pf.addAdvice(advice);[/align]
[align=left] //生成代理实例[/align]
[align=left] Foo proxy = (Foo)pf.getProxy();[/align]
[align=left] proxy.printName("Tony");[/align]
[align=left] proxy.printAge("27");[/align]
[align=left] } [/align]
[align=left]}[/align]
[align=left]控制台输出信息[/align]
[align=left]Class Name is Foo arg is Tony [/align]
[align=left]The Name is : Tony[/align]
[align=left]Class Name is Foo arg is 27 [/align]
[align=left]The Age is : 27[/align]
[align=left]代码清单1中我们的Foo.java类有两个方法,我们创建了FooBeforeAdvice继承前置增强接口MethodBeforeAdvice,在before方法中我同通过参数object获得代理的对象信息,通过参数args获得代理方法的参数值,最后我们通过ProxyFactory将目标类和增强类融合,生成了代理实例并调用代理实例的方法。而在Spring中又如何配置AOP呢?[/align]
[align=left]4.3[/b]前置增强[/b][/b][/align]
[align=left]代码清单2[/align]
[align=left]<bean id="foo" class="com.tony.test.Foo" scope="singleton"/>[/align]
[align=left]<bean id="fooBeforeAdvice" class="com.tony.test.FooBeforeAdvice"/>[/align]
[align=left]<bean id="proxy" [/align]
[align=left] class="org.springframework.aop.framework.ProxyFactoryBean">[/align]
[align=left] <property name="interceptorNames"><!-- 指定增强 -->[/align]
[align=left] <list>[/align]
[align=left] <value>fooBeforeAdvice</value>[/align]
[align=left] </list>[/align]
[align=left] </property>[/align]
[align=left] <!-- 指定目标代理Bean -->[/align]
[align=left] <property name="target" ref="foo"/>[/align]
[align=left]</bean>[/align]
[align=left]import org.springframework.beans.factory.BeanFactory;[/align]
[align=left]import org.springframework.beans.factory.xml.XmlBeanFactory;[/align]
[align=left]import org.springframework.core.io.ClassPathResource;[/align]
[align=left]public class Test {[/align]
[align=left] public static void main(String[] args) {[/align]
[align=left] ClassPathResource resource = new [/align]
[align=left] ClassPathResource("spring-config-beans.xml"); [/align]
[align=left] //实例化BeanFactory[/align]
[align=left] BeanFactory factory = new XmlBeanFactory(resource); [/align]
[align=left] Foo foo = (Foo)factory.getBean("proxy");[/align]
[align=left] foo.printName("Tony");[/align]
[align=left] foo.printAge("27");[/align]
[align=left] } [/align]
[align=left]}[/align]
[align=left]控制台信息[/align]
[align=left]Class Name is Foo arg is Tony [/align]
[align=left]The Name is : Tony[/align]
[align=left]Class Name is Foo arg is 27 [/align]
[align=left]The Age is : 27[/align]
[align=left]代码清单2中我们只需修改Spring的配置文件,将增强类和目标类装配起来就可以了,我们在Test.java就像正常的调用Foo一样,可是控制台取已经是被拦截了。[/align]
[align=left]4.4[/b]后置增强[/b][/b][/align]
[align=left]代码清单1[/align]
[align=left]public class Foo {[/align]
[align=left] public String printName(String name){[/align]
[align=left] return "The Name is : " + name;[/align]
[align=left] }[/align]
[align=left] public String printAge(String age){[/align]
[align=left] return "The Age is : " + age;[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]import java.lang.reflect.Method;[/align]
[align=left]import org.springframework.aop.AfterReturningAdvice;[/align]
[align=left]public class FooAfterAdvice implements AfterReturningAdvice{[/align]
[align=left] @Override//参数分别是代理方法的返回值,被代理的方法,方法的参数,代理对象[/align]
[align=left] public void afterReturning(Object returnValue, Method method,[/align]
[align=left] Object[] args,Object object) throws Throwable {[/align]
[align=left] //打印出类的名称[/align]
[align=left] System.out.print("Class Name is " + [/align]
[align=left] object.getClass().getSimpleName() + " ");[/align]
[align=left] //打印出参数的值[/align]
[align=left] System.out.println("arg is "+[/align]
[align=left] (String)args[0] + " ");[/align]
[align=left] //打印出返回值图[/align]
[align=left] System.out.println("ReturnValue is " + [/align]
[align=left] returnValue.toString());[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]<bean id="foo" class="com.tony.test.Foo" scope="singleton"/>[/align]
[align=left]<bean id="fooAfterAdvice" class="com.tony.test.FooAfterAdvice"/>[/align]
[align=left]<bean id="proxy" [/align]
[align=left] class="org.springframework.aop.framework.ProxyFactoryBean">[/align]
[align=left] <property name="interceptorNames"><!-- 指定增强 -->[/align]
[align=left] <list>[/align]
[align=left] <value>fooAfterAdvice</value>[/align]
[align=left] </list>[/align]
[align=left] </property>[/align]
[align=left] <!-- 指定目标代理Bean -->[/align]
[align=left] <property name="target" ref="foo"/>[/align]
[align=left]</bean>[/align]
[align=left]控制台输出[/align]
[align=left]Class Name is Foo arg is Tony [/align]
[align=left]ReturnValue is The Name is : Tony[/align]
[align=left]Class Name is Foo arg is 27 [/align]
[align=left]ReturnValue is The Age is : 27[/align]
[align=left]代码清单中我们修改了Foo.java类两个方法都返回String类型的参数,定义了一个FooAfterAdvice.java类这个类实现了AfterReturningAdvice接口,分别打印出被代理类的名称,方法参数值和返回值。我们查看控制台输出的信息,发现在目标方法执行结束后还打印出增强类输出的信息。[/align]
[align=left]4.5[/b]环绕增强[/b][/b][/align]
[align=left]代码清单[/b]1[/b][/align]
[align=left]public class Foo {[/align]
[align=left] public void printName(String name){[/align]
[align=left] System.out.println("The Name is : " + name);[/align]
[align=left] }[/align]
[align=left] public void printAge(String age){[/align]
[align=left] System.out.println("The Age is : " + age);[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]import org.aopalliance.intercept.MethodInterceptor;[/align]
[align=left]import org.aopalliance.intercept.MethodInvocation;[/align]
[align=left]public class FooInterceptor implements MethodInterceptor{[/align]
[align=left] @Override[/align]
[align=left] public Object invoke(MethodInvocation invocation) throws Throwable {[/align]
[align=left] //目标方法入参[/align]
[align=left] Object[] args = invocation.getArguments();[/align]
[align=left] //打印方法入参[/align]
[align=left] System.out.println("准备执行目标方法");[/align]
[align=left] //执行目标方法[/align]
[align=left] Object obj = invocation.proceed();[/align]
[align=left] System.out.println("目标方法执行完成");[/align]
[align=left] //返回方法返回值[/align]
[align=left] return obj;[/align]
[align=left] }[/align]
[align=left]}[/align]
[align=left]<bean id="foo" class="com.tony.test.Foo" scope="singleton"/>[/align]
[align=left]<bean id="fooInterceptor" class="com.tony.test.FooInterceptor"/>[/align]
[align=left]<bean id="fooAfterAdvice" class="com.tony.test.FooAfterAdvice"/>[/align]
[align=left]<bean id="proxy" [/align]
[align=left] class="org.springframework.aop.framework.ProxyFactoryBean">[/align]
[align=left] <property name="interceptorNames"><!-- 指定增强 -->[/align]
[align=left] <list>[/align]
[align=left] <value>fooInterceptor</value>[/align]
[align=left] </list>[/align]
[align=left] </property>[/align]
[align=left] <!-- 指定目标代理Bean -->[/align]
[align=left] <property name="target" ref="foo"/>[/align]
[align=left]</bean>[/align]
[align=left]控制台输出[/align]
[align=left]准备执行目标方法[/align]
[align=left]The Name is : Tony[/align]
[align=left]目标方法执行完成[/align]
[align=left]准备执行目标方法[/align]
[align=left]The Age is : 27[/align]
[align=left]目标方法执行完成[/align]
[align=left]代码清单1中我们定义了FooInterceptor.java实现MethodInterceptor接口对目标方法进行环绕增强,查看控制台我们就能看出FooInterceptor在每次方法的执行前后都进行了处理。[/align]

我的其它Spring文章,也许会对您有帮助

Spring的任务调度和邮件发送

Spring应用的单元测试

Spring的数据库支持

Spring的MVC框架

Spring的IoC容器

Spring对AOP的支持

Spring2.5注释驱动与基于注释的MVC
[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息