spring学习笔记(五)
2014-01-21 00:00
302 查看
摘要: spring aop advice详解
针对上面的位置信息,Spring提供了5种对应的子接口:前置增强、后置增强、环绕增强、异常抛出增强、引介增强。
例子:
下面是一个懒人的睡觉方式
我们希望在睡觉前先完成洗漱,下面使用Advice使其睡觉前先洗漱
实现MethodBeforeAdvice接口,实现before方法,这个方法中的代码就是横切代码,参数分别是PointCut提供的目标方法对象(没有PointCut提供默认为类中的所有方法将遍历入参)、方法在调用时传入的参数数组、目标类对象。
当该方法发生异常时,将阻止目标类执行
下面使用Spring提供的ProxyFactory和测试类来验证效果
运行上面代码,将输出
看到这里可能有读者会说了,只是加一句简单的控制台打印代码有必要写的这么复杂吗?所以这里声明一下,上面的例子并不是很形象,如果只是像上面一样加一些简单代码完全可以单独提出一个方法,这个例子只是为了展示Advice的用法,同时这里也突出了一个问题,我们可以发现并不是任何时候使用Spring Aop都是好的,他也会增加我们代码的复杂度,所以用的时候请想清楚使用Aop是否合适。还有这里的例子代码都没有经过真实的运行测试,希望学习的朋友请自己动手写下代码,有问题可以提出来讨论,下面的例子也有相同问题,请勿怪。
Spring配置文件中使用代理:
ProxyFactoryBean负责为其他Bean创建代理实例,内部使用ProxyFactory完成这个工作,ProxyFactoryBean的可配置属性如下:
target:代理的目标对象
proxyInterfaces:代理所要实现的接口,可以为多借口
interceptorNames:需要织入目标对象的Bean列表,采用Bean的名称指定,这些Bean必须实现MethodInterceptor或Advisor,配置顺序对应调用顺序
singleton:返回对象是否为单例,默认是
optimize:当为true,强制使用CGLIB代理,对应单例推荐使用CGLIB代理,其他用JDK代理,因为CGLIB代理创建慢,但创建出的代理对象运行效率快,JDK相反
proxyTargetClass:是否使用类代理(不使用接口代理),true时使用CGLIB代理
实现AfterReturningAdvice接口,实现afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable方法,returnObj是方法返回结果,其他与前置增强一样。
还有一点与前置增强区别,当发生异常时,如果异常是目标方法声明的异常,异常将归并到目标方法,否则将异常转换成运行期异常抛出。
由于后置增强与前置用法相识,这里就不写例子了
异常抛出增强最适合是事物的回滚操作,在ThrowsAdvice接口中并没有定义任何的抽象方法,他只是一个标识接口,在运行期间Spring会通过反射识别。但是增强方法必须使用void afterThrowing([Method method, Object[] args, Object target], Throwable)这种格式的方法签名。
Advice详解
前面提到了,一个切面由一个PointCut和一个Advice组成,Advice主要包含了横切代码以及,织入位置的部分信息(即织入PointCut给定方法的方法的前面、后面、前面和后面、异常抛出时、添加一些新的方法和属性)。针对上面的位置信息,Spring提供了5种对应的子接口:前置增强、后置增强、环绕增强、异常抛出增强、引介增强。
(1) 前置增强:
Spring提供了org.springframework.aop.BeforeAdvice接口,但是因为Spring现在只支持方法级别的增强,所以MethodBeforeAdvice是当前可用的前置增强,表示在目标方法执行前实施增强,估计以后还会有其他的前置增强,敬请期待。例子:
Person.java public interface Person { public void sleep() ; }
下面是一个懒人的睡觉方式
LazyPerson.java public class LazyPerson implements Person { public void sleep() { System.out.println("I am sleeping.....ZZZZ"); } }
我们希望在睡觉前先完成洗漱,下面使用Advice使其睡觉前先洗漱
GreetingBeforeAdvice.java public class GreetingBeforeAdvice implements MethodBeforeAdvice { public void before(Method method, Object[] args, Object obj) throws Throwable { System.out.println("I am washing face....."); } }
实现MethodBeforeAdvice接口,实现before方法,这个方法中的代码就是横切代码,参数分别是PointCut提供的目标方法对象(没有PointCut提供默认为类中的所有方法将遍历入参)、方法在调用时传入的参数数组、目标类对象。
当该方法发生异常时,将阻止目标类执行
下面使用Spring提供的ProxyFactory和测试类来验证效果
BeforeAdviceTest.java public class BeforeAdviceTest { private Person target; private BeforeAdvie advice; private ProxyFactory pf; @BeforeTest public void init() { target = new LazyPerson(); advice = new GreetingBeforeAdvice(); pf = new ProxyFactory(); pf.setTarget(target); pf.addAdvice(advice); } @Test public void beforeAdvice() { Person proxy = (Person)pf.getProxy; proxy.sleep(); } }
运行上面代码,将输出
I am washing face..... I am sleeping.....ZZZZ
看到这里可能有读者会说了,只是加一句简单的控制台打印代码有必要写的这么复杂吗?所以这里声明一下,上面的例子并不是很形象,如果只是像上面一样加一些简单代码完全可以单独提出一个方法,这个例子只是为了展示Advice的用法,同时这里也突出了一个问题,我们可以发现并不是任何时候使用Spring Aop都是好的,他也会增加我们代码的复杂度,所以用的时候请想清楚使用Aop是否合适。还有这里的例子代码都没有经过真实的运行测试,希望学习的朋友请自己动手写下代码,有问题可以提出来讨论,下面的例子也有相同问题,请勿怪。
Spring配置文件中使用代理:
<bean id="advice" class="GreetingBeforeAdvice"/> <bean id="target" class="LazyPerson"/> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean" p:proxyInterfaces="person" p:interceptorNames="advice" p:target-ref="target"/>
ProxyFactoryBean负责为其他Bean创建代理实例,内部使用ProxyFactory完成这个工作,ProxyFactoryBean的可配置属性如下:
target:代理的目标对象
proxyInterfaces:代理所要实现的接口,可以为多借口
interceptorNames:需要织入目标对象的Bean列表,采用Bean的名称指定,这些Bean必须实现MethodInterceptor或Advisor,配置顺序对应调用顺序
singleton:返回对象是否为单例,默认是
optimize:当为true,强制使用CGLIB代理,对应单例推荐使用CGLIB代理,其他用JDK代理,因为CGLIB代理创建慢,但创建出的代理对象运行效率快,JDK相反
proxyTargetClass:是否使用类代理(不使用接口代理),true时使用CGLIB代理
(2) 后置增强
Spring提供了org.springframework.aop.AfterReturningAdvice目标方法执行后实施增强实现AfterReturningAdvice接口,实现afterReturning(Object returnObj, Method method, Object[] args, Object obj) throws Throwable方法,returnObj是方法返回结果,其他与前置增强一样。
还有一点与前置增强区别,当发生异常时,如果异常是目标方法声明的异常,异常将归并到目标方法,否则将异常转换成运行期异常抛出。
由于后置增强与前置用法相识,这里就不写例子了
(3) 环绕增强
Spring提供org.aoplliance.intercept.MethodInterceptor目标方法执行前后实施增强GreetingInterceptor.java public class GreetingInterceptor implements MethodInterceptor { //实现以下方法 public Object invoke(MethodInvocation invocation) throws Throwable { Object[] args = invocation.getArguments();//目标方法入参 //TO-DO 目标方法执行前需要执行的代码 Object obj = invocation.proceed();//反射调用目标方法 //TO-DO 目标方法执行后需要执行的代码 return obj; } }
(4) 异常抛出增强
Spring提供了org.springframework.aop.ThrowsAdvice表示在目标方法抛出异常后实施增强异常抛出增强最适合是事物的回滚操作,在ThrowsAdvice接口中并没有定义任何的抽象方法,他只是一个标识接口,在运行期间Spring会通过反射识别。但是增强方法必须使用void afterThrowing([Method method, Object[] args, Object target], Throwable)这种格式的方法签名。
(5) 引介增强
Spring提供了org.springframework.aop.IntroductionInterceptor,表示在目标方法中添加一些新的方法和属性,并不常用,所以这里不介绍了,感兴趣可以自己查找资料相关文章推荐
- spring学习笔记(20)----指定切面的优先级
- Java与Flex学习笔记(7)----将Spring与Flex整合(基于嵌入式tomcat)(2012-07-24 更新)
- spring学习笔记整理--04(配置Spring管理的bean的作用域、生命周期)
- Spring 学习笔记
- 【Spring学习笔记】之【2.3Ioc配置使用】
- ★(转)Spring学习笔记1
- Spring学习笔记 初始化属性为null值的方法
- Java框架spring 学习笔记(七):Spring相关概念
- SpringBoot学习笔记 - 环境搭建
- Spring学习笔记(一) --- Hello Spring
- Spring学习笔记--- BeanFactory简单模拟
- 【Spring学习笔记】之【3.4 bean的作用域】
- Spring学习笔记1
- [学习笔记]基于注解的spring3.0.x MVC学习笔记(三)
- Spring Boot的学习笔记
- 你绝对需要的Spring学习笔记(整合部分SSH)
- Spring MVC 学习笔记(一) 基于spring2.5的纯xml配置
- Spring学习笔记之Container overview
- spring boot 学习笔记(007)pom.xml修改
- spring学习笔记二