【Spring】AOP的AspectJ开发

AOP基础不了解可以阅读:【Spring】AOP原来如此-CSDN博客

AspectJ是一个居于JAVA开发的AOP框架

基于XML的声明式AspectJ

        基于XML的声明式AspectJ是通过XML文件来定义切面,切入点及通知,所有的切面、切入点和通知必须定义在内,

元素及其子元素如下图所示

        上图中,Spring配置文件中元素下包含多个元素,一个元素又包含属性和子元素,它的子元素在配置时必须按照此顺序来定义,在元素下,同样包含了属性和多个子元素,通过使用元素及其子元素可以在xml文件中配置切面、切入点和通知

1、配置切面

        配置文件中用的是元素,将一个定义好的SpringBean转换为切面Bean,所以要先定义好一个Bean,完成后ref引用即可

        常用属性id和ref

package com.aqiuo.aspectj.xml;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//切面类
public class MyAspect {//前置通知public void myBefore(JoinPoint joinPoint) {System.out.println("前置通知,模拟执行权限检查");System.out.println("前置类是:"+joinPoint.getClass());System.out.println("被植入增强处理的目标方法是"+joinPoint.getSignature().getName());}//后置通知public void myAfterReturning(JoinPoint joinPoint) {System.out.println("后置通知,模拟日志记录...");System.out.println("被置入增强处理的目标方法为"+joinPoint.getSignature().getName());}/*** 环绕通知* 返回值必须是Object* 必须接受一个参数,参数类型必须是ProceedingJoinPoint* 方法必须抛异常*/public Object myAround(ProceedingJoinPoint joinPoint)throws Throwable {System.out.println("环绕开始,执行方法前开启事务...");Object object=joinPoint.proceed();System.out.println("环绕结束,执行方法后关闭事务...");return object;}/*** 异常通知*/public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {System.out.println("异常通知出错了"+e.getMessage());}/*** 最终通知*/public void myAfter(JoinPoint joinPoint) {System.out.println("最终通知。,模拟方法结束后释放资源...");}
}

2、配置切入点

        在Spring的配置文件中,切入点是通过元素来定义的。当它作为的子元素定义时,它是全局切入点,可以被多个切面共享。当它作为元素的子元素时,表示切入点只对当前切面有效

        常用属性id和expression,值如下

        execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throw-pattern?)

例子:execution(public String com.aqiuo.jdk.*.*(..))

表达式解释:
  • modifier:匹配修饰符,public, private 等,省略时匹配任意修饰符
  • ret-type:匹配返回类型,使用 * 匹配任意类型
  • declaring-type:匹配目标类,省略时匹配任意类型
  • .. 匹配包及其子包的所有类
  • name-pattern:匹配方法名称,使用 * 表示通配符
  • () 匹配没有参数的方法
  • (..) 匹配有任意数量参数的方法
  • (,String) 匹配有两个参数的方法,并且第一个为任意类型,第二个为 String 类型
  • throws-pattern:匹配抛出异常类型,省略时匹配任意类型

3、配置通知

通知常用的属性及其描述

pointcut

该属性用于指定一个切入点,Spring将在匹配该表达式的连接点时织入该通知

pointcut-ref

该属性指定一个已经存在的切入点名称,如配置代码中的myPointCut,通常pointcut与pointcut-ref二选一

method

该属性指定一个方法名,指定将切面bean中的该方法转换为增强处理

throwing

该属性只对元素有效,用于指定一个形参名,异常通知方法可以通过该形参访问目标方法所输出的异常

returning

该属性只对元素有效,用于指定一个形参名,后置通知方法可以通过该形参访问目标方法的返回值

示例: 


//xml文件<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd  " > <bean id="myAspect" class="com.aqiuo.demo.MyAspect"></bean><aop:config><aop:aspect id="myAspect" ref="myAspect"><aop:pointcut id="point1" expression="execution(public * com.aqiuo.service.impl.*.*(..))"></aop:pointcut><!--前置方法:第一个执行--><aop:before method="before" pointcut-ref="point1"></aop:before><!--异常方法第三个执行--><aop:after-throwing method="after_throwing" pointcut-ref="point1"></aop:after-throwing><!--后置方法:第三个执行--><aop:after-returning method="after_returning" pointcut-ref="point1"></aop:after-returning><!--最终方法第二个执行--><aop:after method="after" pointcut-ref="point1"></aop:after><!--环绕方法--></aop:aspect></aop:config></beans>//测试

注意标签的摆放位置会导致执行的顺序出错,要按一定的顺序排放

基于注解的声明式AspectJ

与基于代理类的AOP实现相比,XML的声明式AspectJ要便捷很多,但也存在Spring文件中配置大量代码信息,为了解决这个问题,AspectJ框架为AOP的实现提供了一套注解,用来取代Spring配置文件中为实现AOP功能所配置的 臃肿代码

AspectJ的注解及其描述

@Aspect

用来定义一个切面类

@Pointcut

用来定义切入点表达式,使用时还需要定义一个包含名字和任意参数的方法签名来表示切入点名称,实际上,这个方法签名就是一个返回值为void,且方法体为空的普通方法

@Before

用于定义前置通知,

相当于BeforeAdvice,在使用时,通常需要指定一个value属性值,该属性值用于指定一个切入点表达式(可以是已经有的切入点,也可以是切入点表达式)

在目标方法执行之前执行执行的通知。无论何时都第一个执行

@AfterReturning

用于定义后置通知,相当于AfterReturningAdvice.在使用时可以指定 pointcut/value和returning属性,其中,pointcut/value两个属性的作用一样,都是作用于指定切入点表达式,returning属性值用于表示Advice方法中可以定义与此同名的形参。该形参用于访问目标方法值的返回值

在目标方法执行之后执行的通知。正常执行时第三个执行

@Around

用于定义环绕通知,相当于MethodInterceptor。在使用时需要指定一个value属性,该属性用于指定该通知被植入的切入点

@AfterThrowing

用于定义异常通知处理程序中未处理的异常,相当于ThrowAdvice.在使用时可以指定pointcut/value和throw属性。pointcut/value用于指定切入点表达式,throwing属性值用于指定一个形参名表示Advice方法中可定义与此同名的形参,该形参可用于访问目标方法抛出的异常

在目标方法抛出异常时执行的通知。出现异常时第三个执行

@After

最终通知,不管是否异常都会执行

是在目标方法执行之后执行的通知。无论何时都第二个执行

@DeclareParents

无需了解

 配置切面:

这个切面要加上@Aspect :标注为切面类 @Component:加入spring容器


@Aspect
@Component
public class MyAspect01 {@Pointcut(value = "execution(public * com.aqiuo.service.impl.*.*(..))")public void pointCut(){}@Before(value = "pointCut()")public void before(JoinPoint joinPoint){System.out.println("注解前置通知");}@AfterReturning(value ="pointCut()" )public void afterReturning(JoinPoint joinPoint){System.out.println("注解后置通知");}@After(value = "pointCut()")public void after(JoinPoint joinPoint){System.out.println("注解最终通知");}@AfterThrowing(value ="pointCut()",throwing = "e")public void afterThrowing(JoinPoint joinPoint,Throwable e){System.out.println("注解异常处理通知");e.printStackTrace();}@Around(value = "pointCut()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕注解前置");Object res = proceedingJoinPoint.proceed();System.out.println("环绕注解后置");return res;}}

在配置文件中加扫描标签和AOP的驱动注解标签 
<context:component-scan base-package="com.aqiuo.service.impl"></context:component-scan>
 <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:context="http://www.springframework.org/schema/context"xmlns:tx="http://www.springframework.org/schema/tx"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/contexthttp://www.springframework.org/schema/context/spring-context.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsdhttp://www.springframework.org/schema/txhttp://www.springframework.org/schema/tx/spring-tx.xsd"><context:component-scan base-package="com.aqiuo.service.impl"></context:component-scan><aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>

注意:

  • 如果同一个连接点有多个通知需要执行,那在同一个切面中,目标方法之前的前置通知和环绕通知的执行顺序是未知的,目标方法之后的后置通知和环绕通知的执行顺序也是未知的
  • 注解才加
  • 用spring的配置自动完成创建代理织入切面的工作。必须要有,否则没有增强
  • 有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强
  • 当配为时,表示使用CGLib动态代理技术织入增强。
  • 不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

 纯注解开发:

配置注解类

@EnableAspectJAutoProxy()这个是替代<aop:aspectj-autoproxy>

放在配置类上

package com.aqiuo.config;import com.aqiuo.aspect.MyAspect01;
import com.aqiuo.demo.MyAspect;
import org.springframework.beans.factory.annotation.Configurable;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Import;@Configurable
@ComponentScan("com")
@EnableAspectJAutoProxy()
@Import(DaoConfig.class)
public class SpringConfig {}

由于我dao层要用到数据源,所以额外写了一个DAO的配置类(初学,不用可以不写)

package com.aqiuo.config;import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;import javax.sql.DataSource;public class DaoConfig {@Beanpublic DataSource getDataSource(){DruidDataSource druidDataSource=new DruidDataSource();druidDataSource.setDriverClassName("com.mysql.jdbc.Driver");druidDataSource.setUrl("jdbc:mysql://localhost:3306/ssm?characterEncoding=utf-8");druidDataSource.setUsername("root");druidDataSource.setPassword("3.14159265358");return druidDataSource;}@Beanpublic JdbcTemplate getJdbcTemplate(DataSource ds){JdbcTemplate jdbcTemplate=new JdbcTemplate();jdbcTemplate.setDataSource(ds);return jdbcTemplate;}}

编写配置类 

package com.aqiuo.aspect;import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;@Aspect
@Component
public class MyAspect01 {@Pointcut(value = "execution(public * com.aqiuo.service.impl.*.*(..))")public void pointCut(){}@Before(value = "pointCut()")public void before(JoinPoint joinPoint){System.out.println("注解前置通知");}@AfterReturning(value ="pointCut()" )public void afterReturning(JoinPoint joinPoint){System.out.println("注解后置通知");}@After(value = "pointCut()")public void after(JoinPoint joinPoint){System.out.println("注解最终通知");}@AfterThrowing(value ="pointCut()",throwing = "e")public void afterThrowing(JoinPoint joinPoint,Throwable e){System.out.println("注解异常处理通知");e.printStackTrace();}@Around(value = "pointCut()")public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {System.out.println("环绕注解前置");Object res = proceedingJoinPoint.proceed();System.out.println("环绕注解后置");return res;}}

 被增强的方法:


@Service
public class AccountServiceImpl implements AccountService {@AutowiredAccountMapper accountMapper;public Boolean pay(Integer money, Integer produce, Integer customer) throws SQLException {accountMapper.addMoney(money, produce);System.out.println("AccountService执行啦...");accountMapper.subMoney(money, customer);return false;}}

 测试类

    @Testpublic void run2() throws SQLException {ApplicationContext applicationContext=new AnnotationConfigApplicationContext(SpringConfig.class);AccountService accountService= (AccountService) applicationContext.getBean(AccountService.class);accountService.pay(100,1,2);}

总结:

        1.纯xml配置文件方式:

写一个类,再xml文件中配置bean,和即可

        2.配置加注解:

写一个切面类(加上注解@Aspect @Component @Before等)

再配置文件中写: 注解驱动

        3.纯注解方式

在配置类上添加@EnableAspectJAutoProxy()

其他不变,注意扫描一定要都扫描到

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/589331.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【SpringBoot】常用注解

RequestBody&#xff1a;自动将请求体中的 json 数据转换为实体类对象。 这个例子凑巧传入的json属性键名和User键名一致&#xff0c;可以直接使用User实体类对象&#xff0c;如果键名不一致则需要用一个Map 类接收参数&#xff1a; PutMapping("/update")public R…

给多行文本的每行添加指定的前缀textwrap.indent()

【小白从小学Python、C、Java】 【计算机等考500强证书考研】 【Python-数据分析】 给多行文本的每行添加指定的前缀 textwrap.indent() [太阳]选择题 请问以下代码输出的第一行结果是&#xff1f; import textwrap text welcome to China! print("【显示】text\n&quo…

基于单片机的公交车站自动报站器设计与实现

一、摘要 随着城市交通的快速发展&#xff0c;公交车作为城市公共交通的主要工具&#xff0c;其便捷性和高效性得到了广泛的认可。然而&#xff0c;由于公交车站的广播系统存在一定的局限性&#xff0c;如人工报站容易出现失误、音量大小不一等问题&#xff0c;给乘客带来了不…

Head First Design Patterns - 观察者模式

观察者模式 观察者模式定义了对象之间的一对多依赖&#xff0c;当一个对象改变状态时&#xff0c;它的所有依赖者都会收到通知并自动更新。观察者模式是一种对象行为型模式。 场景 很多用户都订阅了某一公众号&#xff0c;当该公众号更新时&#xff0c;所以用户都会收到消息…

【JS笔记】JavaScript语法 《基础+重点》 知识内容,快速上手(一)

JavaScript基础语法 HTML &#xff1a;标记语言JavaScript &#xff1a;编程语言&#xff08;脚本&#xff09; 序言 JavaScript发展历史&#xff08;JS&#xff09; 1. 1994年&#xff0c;网景公司(Netscape)发布了Navigator浏览器0.9版&#xff0c;这是世界上第一款比较成…

Mybatis Java API - SqlSessionFactoryBuilder

在MyBatis中&#xff0c;用于与数据库进行交互的主要Java接口是SqlSession。通过这个接口&#xff0c;您可以执行命令、获取映射器并管理事务。稍后我们将更详细地讨论SqlSession本身&#xff0c;但首先我们必须学习如何获取SqlSession的实例。SqlSession是由SqlSessionFactory…

C++17中的内联变量

在C11中&#xff1a; (1).声明为constexpr的函数隐式地是内联函数; (2).deleted函数隐式地是一个内联函数。 在内联函数中&#xff1a; 1.所有函数定义中的函数局部静态对象(function-local static object)在所有翻译单元之间共享(它们都引用一个翻译单…

【c++————————构造函数和析构函数】

【c————————构造函数和析构函数】 欢迎阅读新一期的c模块————构造函数和析构函数 ✒️个人主页&#xff1a;-Joker- &#x1f3f7;️专栏&#xff1a;C &#x1f4dc;代码仓库&#xff1a;c_code &#x1f339;&#x1f339;欢迎大佬们的阅读和三连关注&#xff0c…

软件集成测试

软件集成测试是将各个独立的软件模块组合起来&#xff0c;并测试它们之间的接口和交互是否正常工作的过程。下面是软件集成测试的一般步骤&#xff1a; 确定测试策略&#xff1a;确定集成测试的目标、范围和测试策略。确定要测试的软件模块和它们之间的依赖关系。 设计测试用例…

Dependency Track:智能组件分析平台。

Dependency Track:智能组件分析平台。 ############################# 免责声明:工具本身并无好坏,希望大家以遵守《网络安全法》相关法律为前提来使用该工具,支持研究学习,切勿用于非法犯罪活动,对于恶意使用该工具造成的损失,和本人及开发者无关。 ################…

基于关键点的人脸对齐方法

人脸旋转校正的一般步骤&#xff1a; 1.人脸检测&#xff1a;首先使用人脸检测算法来检测图像中的人脸位置。 2.人脸关键点检测&#xff1a;对于每张检测到的人脸&#xff0c;使用人脸关键点检测算法来检测人脸中的关键点&#xff0c;如眼睛、鼻子、嘴巴等。 &#xff08;项目…

【leetcode100-026】【链表/快慢指针】环形链表II

【题干】 给定一个链表的头节点 head &#xff0c;返回链表开始入环的第一个节点。 如果链表无环&#xff0c;则返回 null。 如果链表中有某个节点&#xff0c;可以通过连续跟踪 next 指针再次到达&#xff0c;则链表中存在环。 为了表示给定链表中的环&#xff0c;评测系统…

Linux | 解决问题Ubuntu重启无法进入系统以及网络无法连接【图文详解】

Ubuntu18.04重启无法进入系统&#xff0c;重开后如图 一直在加载系统内核4.15.0-213-generic,无法加载 错误原因 原本的系统是Ubuntu16.04,使用命令升级到Ubuntu18.04版本&#xff0c;升级重启后&#xff0c;远程无法连接&#xff01; 错误解决 第一步&#xff1a;进入GRUB…

AIGC入门系列1:感性的认识扩散模型

1、序言 大家好&#xff0c;欢迎来到AI手工星的频道&#xff0c;我是专注AI领域的手工星。AIGC已经成为AI又一个非常爆火的领域&#xff0c;并且与之前的AI模型不同&#xff0c;AIGC更适合普通人使用&#xff0c;我们不仅可以与chatgpt对话&#xff0c;也能通过绘画模型生成想…

基于SpringBoot的线上学习资源智能推荐系统

文章目录 项目介绍主要功能截图:部分代码展示设计总结项目获取方式🍅 作者主页:超级无敌暴龙战士塔塔开 🍅 简介:Java领域优质创作者🏆、 简历模板、学习资料、面试题库【关注我,都给你】 🍅文末获取源码联系🍅 项目介绍 基于SpringBoot的线上学习资源智能推荐系…

使用ASP.NET MiniAPI 调试未匹配请求路径

本文将介绍如何在使用ASP.NET MiniAPI时调试未匹配到的请求路径。我们将详细讨论使用MapFallback方法、中间件等工具来解决此类问题。 1. 引言 ASP.NET MiniAPI是一个轻量级的Web API框架&#xff0c;它可以让我们快速地构建和部署RESTful服务。然而&#xff0c;在开发过程中如…

Hystrix相关面试题及答案

1、什么是Hystrix&#xff0c;它是如何工作的&#xff1f; Hystrix是一个由Netflix开源的库&#xff0c;主要用于在分布式系统中提供延迟和容错功能&#xff0c;通过阻止服务故障的蔓延和提供回退机制来保护系统。它在服务架构中扮演着重要的角色&#xff0c;特别是在微服务架…

PACC:数据中心网络的主动 CNP 生成方案

PACC&#xff1a;数据中心网络的主动 CNP 生成方案 文章目录 PACC&#xff1a;数据中心网络的主动 CNP 生成方案PACC算法CNP数据结构PACC参数仿真结果参考文献 PACC算法 CNP数据结构 PACC参数 仿真结果 PACC Hadoop Load0.2 的情况&#xff1a; PACC Hadoop Load0.4 的情况&a…

go slice源码探索(切片、copy、扩容)和go编译源码分析

文章目录 概要一、数据结构二、初始化2.1、字面量2.2、下标截取2.2.1、截取原理 2.3、make关键字2.3.1、编译时 三、复制3.1、copy源码 四、扩容4.1、append源码 五&#xff1a;切片使用注意事项六&#xff1a;参考 概要 Go语言的切片&#xff08;slice&#xff09;是对数组的…

axios的使用及说明

目录 1.说明 2.直接使用 3.封装使用 4.注意 1.说明 官网&#xff1a;Axios 实例 | Axios中文文档 | Axios中文网 Axios 是一个基于 promise 网络请求库&#xff0c;作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使…