- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章SpringAOP四种通知类型+环绕通知说明由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
SpringAOP的四种通知类型:前置通知、异常通知、后置通知、异常通知 。
。
给出 账户的业务层接口 IAccountService.java, 。
为了便于演示这四种通知类型,我们就只留下了一个方法.
public interface IAccountService { void saveAccount();}
给出 账户的业务层接口的实现类 AccountServiceImpl.java 。
public class AccountServiceImpl implements IAccountService{ @Override public void saveAccount() { System.out.println("执行了保存"); //int i=1/0; }}
给出一个日志类, 用于打印日志 。
public class Logger { /** * 前置通知 */ public void beforePrintLog(){ System.out.println("前置通知Logger类中的beforePrintLog方法开始记录日志了。。。"); } /** * 后置通知 */ public void afterReturningPrintLog(){ System.out.println("后置通知Logger类中的afterReturningPrintLog方法开始记录日志了。。。"); } /** * 异常通知 */ public void afterThrowingPrintLog(){ System.out.println("异常通知Logger类中的afterThrowingPrintLog方法开始记录日志了。。。"); } /** * 最终通知 */ public void afterPrintLog(){ System.out.println("最终通知Logger类中的afterPrintLog方法开始记录日志了。。。"); }}
给出配置信息bean.xml 。
<?xml version="1.0" encoding="UTF-8"?><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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置srping的Ioc,把service对象配置进来--> <bean id="accountService" class="service.AccountServiceImpl"></bean> <!-- 配置Logger类 --> <bean id="logger" class="utils.Logger"></bean> <!--配置AOP--> <aop:config> <!--配置切入点表达式 --> <aop:pointcut id="pt1" expression="execution(* service.AccountServiceImpl.saveAccount())"></aop:pointcut> <!--配置切面 --> <aop:aspect id="logAdvice" ref="logger"> <!-- 配置前置通知:在切入点方法执行之前执行--> <aop:before method="beforePrintLog" pointcut-ref="pt1" ></aop:before> <!-- 配置后置通知:在切入点方法正常执行之后值--> <aop:after-returning method="afterReturningPrintLog" pointcut-ref="pt1"></aop:after-returning> <!-- 配置异常通知:在切入点方法执行产生异常之后执行--> <aop:after-throwing method="afterThrowingPrintLog" pointcut-ref="pt1"></aop:after-throwing> <!-- 配置最终通知:无论切入点方法是否正常执行它都会在其后面执行--> <aop:after method="afterPrintLog" pointcut-ref="pt1"></aop:after> </aop:aspect> </aop:config></beans>
1)异常通知和后置通知永远只能执行一个 。
2)配置切入点表达式 。
此标签写在aop:aspect标签内部只能当前切面使用.
它还可以写在aop:aspect外面,此时就变成了所有切面可用 。
给出Test类 。
public class AOPTest { public static void main(String[] args) { //1.获取容器 ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml"); //2.获取对象 IAccountService as = (IAccountService)ac.getBean("accountService"); //3.执行方法 as.saveAccount(); }}
执行结果:
当我们放开AccountServiceImpl类中我们故意制造的异常 int i=1/0;时:
。
环绕通知,只需要稍稍微改变上面例子的两点即可 。
public class Logger { public Object aroundPringLog(ProceedingJoinPoint pjp){ Object rtValue = null; try{ Object[] args = pjp.getArgs();//得到方法执行所需的参数 System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。前置"); rtValue = pjp.proceed(args);//明确调用业务层方法(切入点方法) System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。后置"); return rtValue; }catch (Throwable t){ System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。异常"); throw new RuntimeException(t); }finally { System.out.println("Logger类中的aroundPringLog方法开始记录日志了。。。最终"); } }}
注意:pjp.proceed(args)会报异常,必须用 Throwable t,因为Exception拦不住它 。
<?xml version="1.0" encoding="UTF-8"?><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" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 配置srping的Ioc,把service对象配置进来--> <bean id="accountService" class="service.AccountServiceImpl"></bean> <!-- 配置Logger类 --> <bean id="logger" class="utils.Logger"></bean> <!--配置AOP--> <aop:config> <!--配置切入点表达式 --> <aop:pointcut id="pt1" expression="execution(* service.AccountServiceImpl.saveAccount())"></aop:pointcut> <!--配置切面 --> <aop:aspect id="logAdvice" ref="logger"> <!-- 配置环绕通知 详细的注释请看Logger类中--> <aop:around method="aroundPringLog" pointcut-ref="pt1"></aop:around> </aop:aspect> </aop:config></beans>
。
我们都知道,AOP机制的核心是在不修改源码的基础上对业务层方法的增强.
public AccountService getAccountService() { return (AccountService) Proxy.newProxyInstance(accountService.getClass().getClassLoader(), accountService.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object o, Method method, Object[] objects) throws Throwable { Object rtValue=null; try { //1、开启事务 txManager.beginTransaction(); //2、执行操作,整个过程像对每个方法进行了包装,并返回新的accountService对象 rtValue=method.invoke(accountService,objects); //3、提交事务 txManager.commit(); //4、返回结果 return rtValue; }catch (Exception e){ //5、回滚事务 txManager.rollback(); throw new RuntimeException(e); }finally { //6、释放连接 txManager.release(); } } }); }
如果不明确调用业务层方法,就像一个画皮,没有发挥本质的作用.
除此之外,我认为环绕通知可以代替其他的四个通知, 。
public Object aroundPrintLog(ProceedingJoinPoint pjp){//环绕通知是不是能够代替其他的通知 Object rtvalue=null; try { /** *这里的一切都是为都是给业务层方法进行增强,例如:把那些方法拿过来,然后核心的还是rtvalue=pjp.proceed(args), *其他的输出只不过是为核心的业务层方法进行修饰 */ Object[] args=pjp.getArgs();//得到方法执行所需的参数 System.out.println("前置通知"); rtvalue=pjp.proceed(args);//明确调用业务层方法 System.out.println("后置通知"); return rtvalue; }catch (Throwable e){ System.out.println("异常通知"); throw new RuntimeException(e); }finally { System.out.println("最终通知"); } }
这个属于典型的环绕通知,其中把输出方法换成相应的通知方法就可以(有不同观点的可以说出来一起讨论).
最后,分享一下我学这个知识的方法。方法增强,本质上就是对源码不修改的情况下进行方法的加工。就好像烤羊肉串一样,其中的核心就是羊肉,就像公司给你的业务层方法(这个是不让修改的)。在给顾客使用前,收先对羊肉进行刷油、烤、撒料一系列过程,这一过程就是我们对业务层方法的增强,使业务层的功能更加健壮,对应的烧烤也就是更美味。核心的一点就是正确调用业务层的方法,不管在哪类通知中,都能对业务层方法进行正确、有效地增强 。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持我.
原文链接:https://blog.csdn.net/qq_41949320/article/details/106841824 。
最后此篇关于SpringAOP四种通知类型+环绕通知说明的文章就讲到这里了,如果你想了解更多关于SpringAOP四种通知类型+环绕通知说明的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我正在尝试编写一个相当多态的库。我遇到了一种更容易表现出来却很难说出来的情况。它看起来有点像这样: {-# LANGUAGE ScopedTypeVariables #-} {-# LANGUAGE
谁能解释一下这个表达式是如何工作的? type = type || 'any'; 这是否意味着如果类型未定义则使用“任意”? 最佳答案 如果 type 为“falsy”(即 false,或 undef
我有一个界面,在IAnimal.fs中, namespace Kingdom type IAnimal = abstract member Eat : Food -> unit 以及另一个成功
这个问题在这里已经有了答案: 关闭 10 年前。 Possible Duplicate: What is the difference between (type)value and type(va
在 C# 中,default(Nullable) 之间有区别吗? (或 default(long?) )和 default(long) ? Long只是一个例子,它可以是任何其他struct类型。 最
假设我有一个案例类: case class Foo(num: Int, str: String, bool: Boolean) 现在我还有一个简单的包装器: sealed trait Wrapper[
这个问题在这里已经有了答案: Create C# delegate type with ref parameter at runtime (1 个回答) 关闭 2 年前。 为了即时创建委托(dele
我正在尝试获取图像的 dct。一开始我遇到了错误 The function/feature is not implemented (Odd-size DCT's are not implemented
我正在尝试使用 AFNetworking 的 AFPropertyListRequestOperation,但是当我尝试下载它时,出现错误 预期的内容类型{( “应用程序/x-plist” )}, 得
我在下面收到错误。我知道这段代码的意思,但我不知道界面应该是什么样子: Element implicitly has an 'any' type because index expression is
我尝试将 SignalType 从 ReactiveCocoa 扩展为自定义 ErrorType,代码如下所示 enum MyError: ErrorType { // .. cases }
我无法在任何其他问题中找到答案。假设我有一个抽象父类(super class) Abstract0,它有两个子类 Concrete1 和 Concrete1。我希望能够在 Abstract0 中定义类
我想知道为什么这个索引没有用在 RANGE 类型中,而是用在 INDEX 中: 索引: CREATE INDEX myindex ON orders(order_date); 查询: EXPLAIN
我正在使用 RxJava,现在我尝试通过提供 lambda 来订阅可观察对象: observableProvider.stringForKey(CURRENT_DELETED_ID) .sub
我已经尝试了几乎所有解决问题的方法,其中包括。为 提供类型使用app.use(express.static('public'))还有更多,但我似乎无法为此找到解决方案。 index.js : imp
以下哪个 CSS 选择器更快? input[type="submit"] { /* styles */ } 或 [type="submit"] { /* styles */ } 只是好
我不知道这个设置有什么问题,我在 IDEA 中获得了所有注释(@Controller、@Repository、@Service),它在行号左侧显示 bean,然后转到该 bean。 这是错误: 14-
我听从了建议 registering java function as a callback in C function并且可以使用“简单”类型(例如整数和字符串)进行回调,例如: jstring j
有一些 java 类,加载到 Oracle 数据库(版本 11g)和 pl/sql 函数包装器: create or replace function getDataFromJava( in_uLis
我已经从 David Walsh 的 css 动画回调中获取代码并将其修改为 TypeScript。但是,我收到一个错误,我不知道为什么: interface IBrowserPrefix { [
我是一名优秀的程序员,十分优秀!