(笔记)Spring实战_面向切面的Spring(3)_在XML中声明切面
来源:互联网 发布:两位数相乘最快算法 编辑:程序博客网 时间:2024/04/27 15:32
<aop:advisor>
定义AOP通知器 <aop:after>
定义AOP后置通知(不管被通知的方法是否执行成功) <aop:after-returning>
定义AOP after-returning通知 <aop:after-throwing>
定义AOP after-throwing通知 <aop:around>
定义AOP环绕通知 <aop:aspect>
定义切面 <aop:aspectj-autoproxy>
启用@AspectJ注解驱动的切面 <aop:before>
定义AOP前置通知 <aop:config>
顶层的AOP配置元素。大多数的<aop:*>
元素必须包含在<aop:config>
元素内 <aop:declare-parents>
为被通知的对象引入额外的接口,并透明地实现 <aop:pointcut>
定义切点为选秀节目创建一个观众类
package com.springinaction.springidol;public class Audience{ // 表演之前 public void takeSeats() { System.out.println("The audience is taking their seats."); } // 表演之前 public void turnOffCellPhones() { System.out.println("The audience is turning off their cellphones."); } // 表演之后 public void applaud() { System.out.println("CLAP CLAP CLAP CLAP"); } // 表演失败之后 public void demandRefund() { System.out.println("Boo!We want our money back!"); }}
<bean id="audience" class="com.springinaction.springidol.Audience" />
1.声明前置和后置通知
<aop:config> <aop:aspect ref="audience"> <aop:before pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="takeSeats" /> <aop:before pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="turnOffCellPhones" /> <aop:after-returning pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="applaud" /> <aop:after-throwing pointcut="execution(* com.springinaction.springidol.Performer.perform(..))" method="demandRefund" /> </aop:aspect> </aop:config>
关于Spring AOP配置元素,第一个需要注意的事项是大多数的AOP配置元素必须在<aop:config>
元素的上下文内使用。
为了避免重复定义切点,可以使用<aop:pointcut>
元素定义一个命名切点。
<aop:config> <aop:aspect ref="audience"> <aop:pointcut expression="execution(* com.springinaction.springidol.Performer.perform(..))" id="performance" /> <aop:before pointcut-ref="performance" method="takeSeats" /> <aop:before pointcut-ref="performance" method="turnOffCellPhones" /> <aop:after-returning pointcut-ref="performance" method="applaud" /> <aop:after-throwing pointcut-ref="performance" method="demandRefund" /> </aop:aspect> </aop:config>
<aop:pointcut>
元素所定义的切点可以被同一个<aop:aspect>
元素之内的所有通知元素所引用。如果想让定义的切点能够在多个切面使用,可以把<aop:pointcut>
元素放在<aop:config>
元素的作用域内。
2.声明环绕通知
pom.xml
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>3.2.17.RELEASE</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.7.4</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.7.4</version> </dependency>
记录开始时间、结束时间
public void watchPerformance(ProceedingJoinPoint joinpoint) { try { // 表演之前 System.out.println("The audience is taking their seats."); System.out.println("The audienct is turning off their cellphones."); long start = System.currentTimeMillis(); joinpoint.proceed();// 执行被通知的方法 // 表演之后 long end = System.currentTimeMillis(); System.out.println("CLAP CLAP CLAP CLAP"); System.out.println("The performance took " + (end - start) + " milliseconds."); } catch (Throwable e) { System.out.println("Boo!We want out money back!");// 表演失败之后 } }
ProceedingJoinPoint能让我们在通知里调用被通知方法。
更有意思的是,正如我们可以忽略调用proceed()方法来阻止执行被通知的方法,我们还可以在通知里多次调用被通知的方法。
<aop:around pointcut-ref="performance" method="watchPerformance" />
调试:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'carl' defined in class path resource [com/springinaction/springidol/spring-idol.xml]: Initialization of bean failed; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 6): Property or field 'song' cannot be found on object of type 'com.sun.proxy.$Proxy4' - maybe not public? at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:529) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458) at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:293) at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223) at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:290) at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:191) at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:636) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:938) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:139) at org.springframework.context.support.ClassPathXmlApplicationContext.<init>(ClassPathXmlApplicationContext.java:83) at com.springinaction.springtest.Demo1.test5(Demo1.java:52) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:606) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47) at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) at org.junit.runners.ParentRunner.run(ParentRunner.java:363) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:86) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192)Caused by: org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 6): Property or field 'song' cannot be found on object of type 'com.sun.proxy.$Proxy4' - maybe not public? at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:142) at org.springframework.beans.factory.support.AbstractBeanFactory.evaluateBeanDefinitionString(AbstractBeanFactory.java:1315) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.evaluate(BeanDefinitionValueResolver.java:214) at org.springframework.beans.factory.support.BeanDefinitionValueResolver.resolveValueIfNecessary(BeanDefinitionValueResolver.java:186) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyPropertyValues(AbstractAutowireCapableBeanFactory.java:1419) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1160) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:519) ... 34 moreCaused by: org.springframework.expression.spel.SpelEvaluationException: EL1008E:(pos 6): Property or field 'song' cannot be found on object of type 'com.sun.proxy.$Proxy4' - maybe not public? at org.springframework.expression.spel.ast.PropertyOrFieldReference.readProperty(PropertyOrFieldReference.java:211) at org.springframework.expression.spel.ast.PropertyOrFieldReference.getValueInternal(PropertyOrFieldReference.java:85) at org.springframework.expression.spel.ast.PropertyOrFieldReference.access$000(PropertyOrFieldReference.java:43) at org.springframework.expression.spel.ast.PropertyOrFieldReference$AccessorLValue.getValue(PropertyOrFieldReference.java:338) at org.springframework.expression.spel.ast.CompoundExpression.getValueInternal(CompoundExpression.java:82) at org.springframework.expression.spel.ast.SpelNodeImpl.getValue(SpelNodeImpl.java:93) at org.springframework.expression.spel.standard.SpelExpression.getValue(SpelExpression.java:89) at org.springframework.context.expression.StandardBeanExpressionResolver.evaluate(StandardBeanExpressionResolver.java:139) ... 40 more<!-- <property name="song" value="#{kenny.song}" /> -->
3.为通知传递参数
有时候通知并不仅仅是对方法进行简单包装,还需要校验传递给方法的参数值,这时候为通知传递参数就非常有用了。
读心者
package com.springinaction.springidol;public interface MindReader{ void interceptThoughts(String thoughts); String getThoughts();}package com.springinaction.springidol;public class Magician implements MindReader{ private String thoughts; public void interceptThoughts(String thoughts) { System.out.println("Intercepting volunteer's thoughts"); this.thoughts = thoughts; } public String getThoughts() { return thoughts; }}
志愿者
package com.springinaction.springidol;public interface Thinker{ void thinkOfSomething(String thoughts);}package com.springinaction.springidol;public class Volunteer implements Thinker{ private String thoughts; public void thinkOfSomething(String thoughts) { this.thoughts = thoughts; } public String getThoughts() { return thoughts; }}
spring-idol.xml
<bean id="magician" class="com.springinaction.springidol.Magician" /> <aop:config> <aop:aspect ref="magician"> <aop:pointcut expression="execution(* com.springinaction.springidol.Thinker.thinkOfSomething(String) and args(thoughts))" id="thinking" /> <aop:before pointcut-ref="thinking" method="interceptThoughts" arg-names="thoughts" /> </aop:aspect> </aop:config>
切点标识了Thinker的thinkOfSomething()方法,指定了String参数。然后再args参数中标识了将thoughts作为参数。
同样,<aop:before>
元素引用了thoughts参数,标识该参数必须传递给Magician的interceptThoughts()方法。
Test Demo
package com.springinaction.springtest;import static org.junit.Assert.assertEquals;import org.junit.Test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.springinaction.springidol.MindReader;import com.springinaction.springidol.Thinker;public class Demo10{ @Test public void test() { ApplicationContext ctx = new ClassPathXmlApplicationContext( "com/springinaction/springidol/spring-idol.xml"); Thinker volunteer = (Thinker)ctx.getBean("volunteer"); volunteer.thinkOfSomething("Hello World!"); MindReader magician = (MindReader)ctx.getBean("magician"); assertEquals("Hello World!", magician.getThoughts()); }}
4.通过切面引入新功能
回顾一下,切面只是实现了它们所包装Bean的相同接口的代理。如果除了实现这些接口,代理还能发布新接口的话,切面所通知的Bean看起来实现了新的接口,即便底层实现类并没有实现这些接口。
package com.springinaction.springidol;public interface Contestant{ void receiveAward();}package com.springinaction.springidol;public class GraciousContestant implements Contestant{ public void receiveAward() { System.out.println("Get $100000 award."); }}
<aop:config> <aop:aspect> <aop:declare-parents types-matching="com.springinaction.springidol.Performer" implement-interface="com.springinaction.springidol.Contestant" default-impl="com.springinaction.springidol.GraciousContestant" /> </aop:aspect> </aop:config>
<aop:declare-parents>
声明了此切面所通知的Bean在它的对象层次结构中拥有新的父类型。
类型匹配Performer接口(由types-matching属性指定)的那些Bean会实现Contestant接口(由implement-interface属性指定)。
这里有两种方式标识所引入接口的实现。使用default-impl属性通过它的全限定类名来显式指定Contestant的实现。或者,我们还可以使用delegate-ref属性来标识。
<bean id="contestantDelegate" class="com.springinaction.springidol.GraciousContestant" /> <aop:config> <aop:aspect> <aop:declare-parents types-matching="com.springinaction.springidol.Performer" implement-interface="com.springinaction.springidol.Contestant" delegate-ref="contestantDelegate" /> </aop:aspect> </aop:config>
- (笔记)Spring实战_面向切面的Spring(3)_在XML中声明切面
- (笔记)Spring实战_面向切面的Spring(1)_什么是面向切面编程
- (笔记)Spring实战_面向切面的Spring(4)_注解切面
- (笔记)Spring实战_面向切面的Spring(2)_使用切点选择连接点
- 面向切面的 Spring —— 如何在 XML 中声明切面?
- 《Spring实战》学习笔记(三)面向切面的Spring
- Spring 在XML中声明切面/AOP
- Spring实战笔记——面向切面编程(一)
- 18.Spring学习笔记_切面的优先级(by尚硅谷_佟刚)
- 《Spring实战》学习笔记-第四章:面向切面的Spring
- 《Spring实战》学习笔记-第四章:面向切面的Spring
- 《Spring实战》学习笔记-第四章:面向切面的Spring
- Spring学习笔记(三) 面向切面的Spring
- 《Spring3实战》摘要(4-1)--面向切面的Spring
- spring实战-基于注解的面向切面编程(AOP)
- Spring学习笔记:面向切面(AOP)的基本定义
- Spring 的面向切面编程(AOP)
- Spring(五)---面向切面的编程
- 如何在onCreate中获取View的高度和宽度
- JAVA 调用SAP端接口
- 换行标签的应用
- 使用 Velocity 模板引擎快速生成代码
- 字体样式标签
- (笔记)Spring实战_面向切面的Spring(3)_在XML中声明切面
- 无皮薄核桃
- web.xml学习随笔
- 注释html
- 约束和修改数据表
- 互联网征信时代来了
- sudo apt-get install xxx 时出现E:未发现软件包xxx
- 软件加密方案简介
- opencart 模板pavothemes 后台bug1:文本编辑器不显示