springAOP的实现方式

三种

纯XML方式,XML+注解,纯注解方式。

Spring 实现AOP思想使⽤的是动态代理技术

默认情况下, Spring会根据被代理对象是否实现接⼝来选择使⽤JDK还是CGLIB。当被代理对象没有实现

任何接⼝时, Spring会选择CGLIB。当被代理对象实现了接⼝, Spring会选择JDK官⽅的代理技术,不过

我们可以通过配置的⽅式,让Spring强制使⽤CGLIB。

接下来我们开始实现aop,

需求是:横切逻辑代码是打印⽇志,希望把打印⽇志的逻辑织⼊到⽬标⽅法的特定位置(service层transfer⽅法)

纯XML方式

引入aop相关的jar包

<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.12.RELEASE</version>
</dependency> <dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>

TransferServiceImpl.java文件:

package com.lagou.edu.service.impl;

import com.lagou.edu.dao.AccountDao;
import com.lagou.edu.pojo.Account;
import com.lagou.edu.service.TransferService;
import com.lagou.edu.utils.ConnectionUtils;
import com.lagou.edu.utils.TransactionManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ImportResource;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service; /**
* @author 应癫
*/
@Service("transferService")
public class TransferServiceImpl implements TransferService { // 最佳状态
// @Autowired 按照类型注入 ,如果按照类型无法唯一锁定对象,可以结合@Qualifier指定具体的id
@Autowired
@Qualifier("accountDao")
private AccountDao accountDao; @Override
public void transfer(String fromCardNo, String toCardNo, int money) throws Exception { /*try{
// 开启事务(关闭事务的自动提交)
TransactionManager.getInstance().beginTransaction();*/
System.out.println("执行转账业务逻辑");
Account from = accountDao.queryAccountByCardNo(fromCardNo);
Account to = accountDao.queryAccountByCardNo(toCardNo); from.setMoney(from.getMoney()-money);
to.setMoney(to.getMoney()+money); accountDao.updateAccountByCardNo(to);
//int c = 1/0;
accountDao.updateAccountByCardNo(from); }
}

打印日志Util:

package com.lagou.edu.utils;

/**
* @author 应癫
*/ public class LogUtils { /**
* 业务逻辑开始之前执行
*/ public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
System.out.println(arg);
}
System.out.println("业务逻辑开始执行之前执行.......");
} /**
* 业务逻辑结束时执行(无论异常与否)
*/ public void afterMethod() {
System.out.println("业务逻辑结束时执行,无论异常与否都执行.......");
} /**
* 异常时时执行
*/
public void exceptionMethod() {
System.out.println("异常时执行.......");
} /**
* 业务逻辑正常时执行
*/ public void successMethod(Object retVal) {
System.out.println("业务逻辑正常时执行.......");
} } public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知中的beforemethod...."); Object result = null;
try{
// 控制原有业务逻辑是否执行
// result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}catch(Exception e) {
System.out.println("环绕通知中的exceptionmethod....");
}finally {
System.out.println("环绕通知中的after method....");
} return result;
}

applicationContext.xml

<!--进行aop相关的xml配置,配置aop的过程其实就是把aop相关术语落地-->
<!--横切逻辑bean-->
<bean id="logUtils" class="com.lagou.edu.utils.LogUtils"></bean>
<!--使用config标签表明开始aop配置,在内部配置切面aspect--> <!--aspect = 切入点(锁定方法) + 方位点(锁定方法中的特殊时机)+ 横切逻辑 -->
<aop:config>
<aop:aspect id="logAspect" ref="logUtils"> <!--切入点锁定我们感兴趣的方法,使用aspectj语法表达式-->
<!--..参数中的两个点表示可以有参数,也可以没有参数,有的话也可以是任意类型,参数中的 *表示参数可以是任意类型,但必须有参数。 -->
<!--包名中的..两个点表示中间可以是任意层-->
<!--<aop:pointcut id="pt1" expression="execution(* *..*.*(..))"/>-->
<aop:pointcut id="pt1" expression="execution(public void com.lagou.edu.service.impl.TransferServiceImpl.transfer(java.lang.String,java.lang.String,int))"/> <!-- <aop:pointcut id="pt1" expression="execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))"/>
-->
<!--方位信息,pointcut-ref关联切入点-->
<!--aop:before前置通知/增强-->
<aop:before method="beforeMethod" pointcut-ref="pt1"/>
<!--aop:after,最终通知,无论如何都执行-->
<!--aop:after-returnning,正常执行通知,retValue是接受方法的返回值的-->
<aop:after-returning method="successMethod" returning="retValue"/>
<!--aop:after-throwing,异常通知--> <aop:around method="arroundMethod" pointcut-ref="pt1"/> </aop:aspect>
</aop:config>-->

测试:

    /**
* 测试xml aop
*/
@Test
public void testXmlAop() throws Exception {
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
TransferService transferService = applicationContext.getBean(TransferService.class);
transferService.transfer("6029621011000","6029621011001",100);
}

环绕通知不和前置及后置通知一起使用,因为环绕通知可以实现前置和后置的功能,并且可以控制原有业务逻辑是否执行,非常强大。

XML+注解方式

将上面纯XML方式改为注解方式

将applicationContext.xml中的内容取掉,改为类中添加注解:

package com.lagou.edu.utils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component; /**
* @author 应癫
*/
@Component
@Aspect
public class LogUtils { @Pointcut("execution(* com.lagou.edu.service.impl.TransferServiceImpl.*(..))")
public void pt1(){ } /**
* 业务逻辑开始之前执行
*/
@Before("pt1()")
public void beforeMethod(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
for (int i = 0; i < args.length; i++) {
Object arg = args[i];
System.out.println(arg);
}
System.out.println("业务逻辑开始执行之前执行.......");
} /**
* 业务逻辑结束时执行(无论异常与否)
*/
@After("pt1()")
public void afterMethod() {
System.out.println("业务逻辑结束时执行,无论异常与否都执行.......");
} /**
* 异常时时执行
*/
@AfterThrowing("pt1()")
public void exceptionMethod() {
System.out.println("异常时执行.......");
} /**
* 业务逻辑正常时执行
*/
@AfterReturning(value = "pt1()",returning = "retVal")
public void successMethod(Object retVal) {
System.out.println("业务逻辑正常时执行.......");
} /**
* 环绕通知
*
*/
/*@Around("pt1()")*/
public Object arroundMethod(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("环绕通知中的beforemethod...."); Object result = null;
try{
// 控制原有业务逻辑是否执行
// result = proceedingJoinPoint.proceed(proceedingJoinPoint.getArgs());
}catch(Exception e) {
System.out.println("环绕通知中的exceptionmethod....");
}finally {
System.out.println("环绕通知中的after method....");
} return result;
} }

在application.xml中配置注解驱动:

    <!--开启aop注解驱动
proxy-target-class:true强制使用cglib -->
<aop:aspectj-autoproxy/>

纯注解模式

我们只需要替换掉xml+注解模式中的注解驱动的部分即可,

    <!--开启aop注解驱动
proxy-target-class:true强制使用cglib -->
<aop:aspectj-autoproxy/>

改为 @EnableAspectJAutoProxy //开启spring对注解AOP的⽀持,在项目中添加到任意个配置类上即可。

欢迎访问:

微信公众号(程序员资料站):code_data

springAOP的三种实现方式的更多相关文章

  1. 通过三个DEMO学会SignalR的三种实现方式

    一.理解SignalR ASP .NET SignalR 是一个ASP .NET 下的类库,可以在ASP .NET 的Web项目中实现实时通信(即:客户端(Web页面)和服务器端可以互相实时的通知消息 ...

  2. Hive metastore三种配置方式

    http://blog.csdn.net/reesun/article/details/8556078 Hive的meta数据支持以下三种存储方式,其中两种属于本地存储,一种为远端存储.远端存储比较适 ...

  3. django 模板语法和三种返回方式

    模板 for循环 {% for athlete in athlete_list %} <li>{{ athlete.name }}</li> {% endfor %} if语句 ...

  4. js的三种继承方式及其优缺点

    [转] 第一种,prototype的方式: //父类 function person(){ this.hair = 'black'; this.eye = 'black'; this.skin = ' ...

  5. spring ioc三种注入方式

    spring ioc三种注入方式 IOC ,全称 (Inverse Of Control) ,中文意思为:控制反转 什么是控制反转? 控制反转是一种将组件依赖关系的创建和管理置于程序外部的技术. 由容 ...

  6. Map三种遍历方式

    Map三种遍历方式 package decorator; import java.util.Collection; import java.util.HashMap; import java.util ...

  7. php 递归函数的三种实现方式

    递归函数是我们常用到的一类函数,最基本的特点是函数自身调用自身,但必须在调用自身前有条件判断,否则无限无限调用下去.实现递归函数可以采取什么方式呢?本文列出了三种基本方式.理解其原来需要一定的基础知识 ...

  8. JSON的三种解析方式

    一.什么是JSON? JSON是一种取代XML的数据结构,和xml相比,它更小巧但描述能力却不差,由于它的小巧所以网络传输数据将减少更多流量从而加快速度. JSON就是一串字符串 只不过元素会使用特定 ...

  9. Qt 2D绘图 渐变填充(三种渐变方式)

    在qt中提供了三种渐变方式,分别是线性渐变,圆形渐变和圆锥渐变.如果能熟练应用它们,就能设计出炫目的填充效果. 线性渐变: 1.更改函数如下: void Dialog::paintEvent(QPai ...

随机推荐

  1. vue学习第一天:v-bind的使用(让属性绑定变量)

    v-bind的使用 v-bind: 是vue中,提供用于绑定属性的指令  例: <input type="button" value="按钮" title ...

  2. GitHub 热点速览 Vol.25:距离优雅编程你差个它

    作者:HelloGitHub-小鱼干 摘要:如何优雅地夸一个程序员呢?vscode-rainbow-fart 作为一个彩虹屁的项目,深得程序员心,能在你编程时疯狂称赞你的除了你自己,还有它.除了鼓励之 ...

  3. SSH网上商城四

    第29课:10-SSH网上商城:购物模块的实体的封装 1.现在我们要实现购物车的模块,当用户在点击 加入购物车按钮的时候需要跳转到 上面我们需要对购物车的对象进行封装 上面一个商品就对应一个记录项,购 ...

  4. C#数据结构与算法系列(十五):排序算法(SortAlgorithm)

    1.介绍 排序是将一组数据,以指定的顺序进行排序的过程 2.分类 内部排序法:指将需要处理的所有数据都加载到内部存储器中进行排序 外部排序法:数据量过大,无法全部加载到内存中,需要借助外部存储进行排序

  5. MySQL 合并查询,以map或对象的形式返回

    转载 CSDN博主「小林子林子」 -> https://blog.csdn.net/qq_26106607/article/details/84961254 原始SQL-> 目的-> ...

  6. springboot @Cacheable 基本使用

    加入依赖 <dependency> <groupId>org.springframework.boot</groupId> <artifactId>sp ...

  7. Taro 3 正式版发布:开放式跨端跨框架解决方案

    作者:凹凸曼 - yuche 从 Taro 第一个版本发布到现在,Taro 已经接受了来自于开源社区两年多的考验.今天我们很高兴地在党的生日发布 Taro 3(Taro Next)正式版,希望 Tar ...

  8. linux根据进程查端口,根据端口查进程

    [root@test_environment src]# netstat -tnllup   能显示对应端口和进程 Active Internet connections (only servers) ...

  9. return zero,or ,return non-zero

    it may return a value to its caller, which is in effect the environment in which the program was exe ...

  10. 使用.Net Core实现的一个图形验证码

    SimpleCaptcha是一个使用简单,基于.Net Standard 2.0的图形验证码模块.它的灵感来源于Edi.Wang的这篇文章https://edi.wang/post/2018/10/1 ...