spring学习(二)—通知
来源:互联网 发布:网页排版设计软件 编辑:程序博客网 时间:2024/06/08 11:38
通知类型
1、Spring只支持方法通知,也就是说,只能在方法的前后进行通知,而不能在属性前后进行通知。
2、Spring支持四种通知类型:目标方法调用前(before),目标方法调用后(after),目标方法调用前后(around),以及目标方法抛出异常(throw)。
3、前置通知的类必须实现MethodBeforeAdvice接口,实现其中的before方法。
4、后置通知的类必须实现AfterReturningAdvice接口,实现其中的afterReturning方法。
5、环绕通知的类必须实现MethodInterceptor接口,实现其中的invoke方法。前后通知是唯一可以控制目标方法是否被真正调用的拦截类型,也可以控制返回对象。而前置拦截或后置拦截不能控制,它们不能印象目标方法的调用和返回。
6、异常通知 要实现 ThrowsAdvice ,ThrowAdvice 接口只是一个标示接口,它没有任何的方法,但是在使用时我们需要实现afterThrowing 方法来实现通知的具体内容。
测试
前置通知
ProBeginAdvice.java
package com.lgh.spring.advice;import java.lang.reflect.Method;import org.springframework.aop.MethodBeforeAdvice;public class ProBeginAdvice implements MethodBeforeAdvice { @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("前置通知:开启事务"); }}
后置通知
ProAfterAdvice
package com.lgh.spring.advice;import java.lang.reflect.Method;import org.springframework.aop.AfterReturningAdvice;public class ProAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("后置通知:提交事务"); }}
异常通知
ExecpetionAdvice.java
package com.lgh.spring.advice;import java.lang.reflect.Method;import org.springframework.aop.ThrowsAdvice;public class ExecpetionAdvice implements ThrowsAdvice { public void afterThrowing(Method m,Object[] os,Object target,Exception throwable) { System.out.println("异常通知: 程序出问题了:" + throwable.getMessage()); } }
环绕通知
AroundInterceptor
package com.lgh.spring.advice;import org.aopalliance.intercept.MethodInterceptor;import org.aopalliance.intercept.MethodInvocation;/* * 环绕通知 * */public class AroundInterceptor implements MethodInterceptor { @Override public Object invoke(MethodInvocation arg0) throws Throwable { System.out.println("环绕通知被调用:调用方法前执行 "); Object obj = arg0.proceed(); System.out.println("环绕通知被调用:调用方法后执行 "); return obj; }}被代理的类ProductDaoImpl
package com.lgh.spring.dao.impl;
public class ProductDaoImpl {
public void save(){ System.out.println("保存商品");}public void del(){ System.out.println("删除商品"); //int i = 9/0;}
}
在applicationContext.xml中配置
<bean id="productDao" class="com.lgh.spring.dao.impl.ProductDaoImpl" lazy-init="true"></bean><!-- 配置前置通知 --> <bean id="proBegin" class="com.lgh.spring.advice.ProBeginAdvice" lazy-init="true"></bean><!-- 配置后置通知 --> <bean id="proAfter" class="com.lgh.spring.advice.ProAfterAdvice" lazy-init="true"></bean><!-- 配置异常通知 --> <bean id="proThrow" class="com.lgh.spring.advice.ExecpetionAdvice"></bean><!-- 配置环绕通知 --> <bean id="proAround" class="com.lgh.spring.advice.AroundInterceptor"></bean> <!-- 配置代理对象 --> <bean id="proxy" class="org.springframework.aop.framework.ProxyFactoryBean" ><!-- 代理目标 --><property name="target" ref="productDao"></property><!-- 代理时所使用的通知 拦截器名集--><property name="interceptorNames"><list><!-- 相当于把 MyMethodBeforeAdvice前置通知和代理对象关联起来, 我们也可以把通知看成拦截器,struts2核心就是拦截器 --> <value>proBegin</value><value>proAfter</value><value>proThrow</value><value>proAround</value></list></property>
测试
SpringTest02
package com.lgh.spring.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.lgh.spring.biz.UserBiz;import com.lgh.spring.dao.impl.ProductDaoImpl;public class SpringTest02 { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); /* * 通过代理获取ProductDaoImpl * 因为ProductDaoImpl本身并没有与通知类有联系 * * */ ProductDaoImpl productDao = (ProductDaoImpl) ac.getBean("proxy"); System.out.println(productDao.getClass()); productDao.save(); System.out.println("------------------"); productDao.del(); }}
结果:
class com.lgh.spring.dao.impl.ProductDaoImpl$$EnhancerBySpringCGLIB$$e5e8be14前置通知:开启事务环绕通知被调用:调用方法前执行 保存商品环绕通知被调用:调用方法后执行 后置通知:提交事务前置通知:开启事务环绕通知被调用:调用方法前执行 删除商品环绕通知被调用:调用方法后执行 后置通知:提交事务
我们在ProductDaoImpl的del方法中添加一个除零异常
public void del(){ System.out.println("删除商品"); int i = 9/0; }
运行结果:
class com.lgh.spring.dao.impl.ProductDaoImpl$$EnhancerBySpringCGLIB$$e5e8be14前置通知:开启事务环绕通知被调用:调用方法前执行 保存商品环绕通知被调用:调用方法后执行 后置通知:提交事务------------------前置通知:开启事务环绕通知被调用:调用方法前执行 删除商品异常通知: 程序出问题了:/ by zeroException in thread "main" java.lang.ArithmeticException: / by zero at com.lgh.spring.dao.impl.ProductDaoImpl.del(ProductDaoImpl.java:12) at com.lgh.spring.dao.impl.ProductDaoImpl$$FastClassBySpringCGLIB$$c7e39ca2.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) ...
我们看到配置的异常通知起作用了
自动代理bean 定义
这时,我们所配置的代理只对一个对象起作用,如果有多个对象时,使用起来比较麻烦,
我们在这里可以使用自动代理bean 定义
<!-- 自动代理bean 定义 --><bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator"><property name="beanNames"><!-- 配置需要使用代理的bean --><value>pro*,userDao</value></property><property name="interceptorNames"><list><value>proBegin</value><value>proAfter</value><value>proThrow</value><value>proAround</value></list></property></bean><bean id="userDao" class="com.lgh.spring.dao.impl.UserDaoMysqlImpl" lazy-init="true" ></bean><bean id="userBiz" class="com.lgh.spring.biz.impl.UserBizImpl" lazy-init="true"><property name="userDao" ref="userDao"></property></bean>
测试
package com.lgh.spring.test;import org.springframework.context.ApplicationContext;import org.springframework.context.support.ClassPathXmlApplicationContext;import com.lgh.spring.biz.UserBiz;import com.lgh.spring.dao.impl.ProductDaoImpl;public class SpringTest03 { public static void main(String[] args) { ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml"); ProductDaoImpl productDao = (ProductDaoImpl) ac.getBean("productDao"); productDao.save(); System.out.println("----------------------------------"); UserBiz ub = (UserBiz) ac.getBean("userBiz"); ub.save(); System.out.println("----------------------------------"); productDao.del(); }}
结果:
前置通知:开启事务环绕通知被调用:调用方法前执行 保存商品环绕通知被调用:调用方法后执行 后置通知:提交事务----------------------------------UserDaoMysqlImpl 构造方法前置通知:开启事务环绕通知被调用:调用方法前执行 UserDaoMysqlImpl save方法环绕通知被调用:调用方法后执行 后置通知:提交事务----------------------------------前置通知:开启事务环绕通知被调用:调用方法前执行 删除商品异常通知: 程序出问题了:/ by zeroException in thread "main" java.lang.ArithmeticException: / by zero at com.lgh.spring.dao.impl.ProductDaoImpl.del(ProductDaoImpl.java:12) at com.lgh.spring.dao.impl.ProductDaoImpl$$FastClassBySpringCGLIB$$c7e39ca2.invoke(<generated>) at org.springframework.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204)
- spring学习(二)—通知
- spring学习笔记(17)——返回通知&异常通知&环绕通知
- Spring学习(九)-AOP切面通知
- Spring 学习之通知
- Spring AOP学习笔记(3):AOP返回通知&异常通知&环绕通知
- Spring学习(十)-AOP返回通知&异常通知&环形通知
- Spring学习(二)
- Spring学习(二)
- Spring学习(二)
- Spring学习(二)
- Spring学习(二)
- Spring学习(二)
- spring 学习笔记 引入通知
- Spring读书学习笔记(二)——Spring boot
- spring学习笔记(16)——AOP之前后置通知
- 17.Spring学习笔记_返回通知&异常通知&环绕通知(by尚硅谷_佟刚)
- Spring之AOP(二)---前置通知
- Spring AOP学习笔记(2):AOP前置通知&后置通知
- OpenGL绘制几何物体(特性)
- c#实现关闭当前窗体并打开另一个已经创建的窗体
- 动画篇之帧动画
- C/C++代码跟踪
- 大数阶乘算法
- spring学习(二)—通知
- 使用cookie跟踪用户例子
- php中include和require的区别
- Android MediaPlayer音频播放总结
- RSTP服务器架设
- tarjan算法求强连通分量
- 输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。 结果请按字母顺序输出。
- 121. Best Time to Buy and Sell Stock
- git管理冲突及Fastjson用法