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. ES6 基本语法:

    ES6.基本语法* ES6可以使用=>作为函数表达形式,简单的风格: 参数 + => +函数体;* 在JS中是以var定义一个变量 ,在ES6中是以let定义变量; let 和 var 区 ...

  2. git 如何解决 (master|MERGING)

    git 如何解决 (master|MERGING) git reset --hard head //回退版本信息 git pull origin master

  3. 搭建hadoop伪集群

    基础设置:jdk.ssh. 1.操作系统.环境.网络.必须软件 2.关闭防火墙 3.设置hosts映射 4.时间同步 5.安装jdk 6.设置ssh免秘钥部署配置:初始化运行:命令行使用:

  4. dubbo源码解析之负载均衡

    在分布式系统中,负载均衡是必不可少的一个模块,dubbo 中提供了五种负载均衡的实现,在阅读这块源码之前,建议先学习负载均衡的基础知识.把看源码当做一个印证自己心中所想的过程,这样会得到事半功倍的效果 ...

  5. Python中的错误和异常

    前言 错误是程序中的问题,由于这些问题而导致程序停止执行.另一方面,当某些内部事件发生时,会引发异常,从而改变程序的正常流程. python中会发生两种类型的错误. 语法错误 逻辑错误(异常) 语法错 ...

  6. 《The Google File System》论文研读

    GFS 论文总结 说明:本文为论文 <The Google File System> 的个人总结,难免有理解不到位之处,欢迎交流与指正 . 论文地址:GFS Paper 阅读此论文的过程中 ...

  7. iOS应用千万级架构开篇

    一款好的APP架构,是需要适应复杂的业务场景的.当然它也是可以监控的,比如性能.卡顿等.你写的每一行代码,测试都可以查看到,并测试覆盖到. 一直很想分享一下,一个大型的APP都做了些什么事情,这些事情 ...

  8. 生日聚会Party——这个线性dp有点嚣张

    题目描述 今天是hidadz小朋友的生日,她邀请了许多朋友来参加她的生日party. hidadz带着朋友们来到花园中,打算 坐成一排玩游戏.为了游戏不至于无聊,就座的方案应满足如下条件:对于任意连续 ...

  9. 一、web自动化快速使用

        1.什么是Selenium? selenium是一款基于web网页的UI自动化测试的框架,用来做web自动化测试 支持多浏览器操作,ie.firefox.chrome.edge.safaria ...

  10. PCA算法 | 数据集特征数量太多怎么办?用这个算法对它降维打击!

    本文始发于个人公众号:TechFlow,原创不易,求个关注 今天是机器学习专题的第27文章,我们一起来聊聊数据处理领域的降维(dimensionality reduction)算法. 我们都知道,图片 ...