【Spring】AOP的AspectJ开发

news2024/11/29 18:25:10

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/beans
			        http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/context
			        http://www.springframework.org/schema/context/spring-context.xsd
			         http://www.springframework.org/schema/aop
			        http://www.springframework.org/schema/aop/spring-aop.xsd
			        http://www.springframework.org/schema/tx
			        http://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 {

    @Bean
    public 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;

    }

    @Bean
    public 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 {
    @Autowired
    AccountMapper 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;
    }


}

 测试类

    @Test
    public 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.coloradmin.cn/o/1348491.html

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

相关文章

Python+OpenGL绘制3D模型(六)材质文件载入和贴图映射

系列文章 一、逆向工程 Sketchup 逆向工程&#xff08;一&#xff09;破解.skp文件数据结构 Sketchup 逆向工程&#xff08;二&#xff09;分析三维模型数据结构 Sketchup 逆向工程&#xff08;三&#xff09;软件逆向工程从何处入手 Sketchup 逆向工程&#xff08;四&#xf…

NXP实战笔记(二):S32K3xx基于RTD-SDK在S32DS上配置PIT与STM中断并反转IO

目录 1、PIT 1.1、PIT概述 1.2、PIT的配置 1.3、Dio配置 1.4、中断配置 1.5、测试代码 1.6、测试结果 2、STM 2.1、STM概述 2.2、STM的配置 2.3、测试代码 2.4、测试结果 1、PIT 1.1、PIT概述 PIT是一组定时器&#xff0c;可用于引发中断和触发器&#xff0c;包括一…

【AI】人类视觉感知特性与深度学习模型(2/2)

目录 二、人类视觉感知特性对深度学习模型的启发 2.1 视觉关注和掩盖与调节注意力模型的关系 1.视觉关注和掩盖 2. 注意力机制模型 2.2 对比敏感度与U形网络的联系 2.3 非局部约束与点积注意力的联系 续上节 【AI】人类视觉感知特性与深度学习模型&#xff08;1/2&#…

【如何选择Mysql服务器的CPU核数及内存大小】

文章目录 &#x1f50a;博主介绍&#x1f964;本文内容&#x1f4e2;文章总结&#x1f4e5;博主目标 &#x1f50a;博主介绍 &#x1f31f;我是廖志伟&#xff0c;一名Java开发工程师、Java领域优质创作者、CSDN博客专家、51CTO专家博主、阿里云专家博主、清华大学出版社签约作…

python练习2【题解///考点列出///错题改正】

一、单选题 【文件】 *1.【单选题】 ——文件&#xff1a;读取方法 下列哪个选项可以从文件中读取任意字节的内容&#xff1f;&#xff08;C &#xff09;A A.read() B.readline() C.readlines() D.以上全部 A\B\C三种方法都是可以读取文件中任意的字节内容的&#xff0…

emacs:Searching for program: No such file or directory,sml;

首先&#xff0c;编辑一个现有的或新的 SML 文件&#xff08;如果没有其他方便的方法&#xff0c;可尝试C-x C-f test.smlC-x C-f test.sml 创建一个新文件&#xff09;。你会看到 Emacs 窗口底部的模式显示从 "基本"&#xff08;或其他任何模式&#xff09;变成了 S…

【ArcGIS微课1000例】0084:甘肃积石山地震震中100km范围内历史灾害点分布图(2005-2020)

甘肃积石山地震震中100km范围内历史灾害点分布图(2005-2020)。 文章目录 一、成果预览二、实验数据三、符号化四、地图整饰一、成果预览 本实验最终效果图如下所示: 二、实验数据 以下数据可以从本专栏配套的实验数据包中0084.rar中获取。 1. 历史灾害数据。为2005-2020时…

【c++】使用vector存放键值对时,明明给vector的不同键赋了不同的值,但为什么前面键的值会被后面键的值给覆盖掉?

错误描述 运行程序得到结果如下图所示&#xff08;左边是原始数据&#xff0c;xxml文件中真实数据的样子&#xff0c;右图是程序运行得到的结果结果&#xff09;&#xff1a; 对比以上两图可以发现&#xff0c;右图中两个实例的三个属性值都来自左图中的第二个User实例&#x…

思维训练-怎样设计一个MQ

架构师需要做各种设计&#xff0c;要不断地提高自己的设计能力。这有没有方法可以训练呢&#xff1f;有的&#xff0c;就是看到什么、想到什么&#xff0c;就假设对面坐着产品经理&#xff0c;一起讨论怎么把它设计出来。比如怎样设计一个MQ 我&#xff1a;首先我确认一下需求。…

2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项样题卷①

2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项&#xff08;高职组&#xff09; 样题&#xff08;第1套&#xff09; 目录 2023年“中银杯”四川省职业院校技能大赛“云计算应用”赛项&#xff08;高职组&#xff09; 样题&#xff08;第1套&#xff09; 模块一…

系统学习Python——装饰器:函数装饰器-[装饰器状态保持方案:外层作用域和非局部变量]

分类目录&#xff1a;《系统学习Python》总目录 我们在某些情况下可能想要共享全局状态。如果我们真的想要每个函数都有自己的计数器&#xff0c;要么像前面的文章那样使用类&#xff0c;要么使用Python3.X中的闭包函数&#xff08;工厂函数&#xff09;和nonlocal语句。由于这…

【产品设计】表对象建模

随着不断深入的拆解&#xff0c;从产品经理的设计方法到系统的拆解&#xff0c;每一部分都有值得探索的地方。 随着不断深入的拆解&#xff0c;从产品经理的设计方法&#xff0c;到经典系统的拆解&#xff0c;到零代码平台的构建&#xff0c;一直在走系统建设方法路线。如今再看…

SpringBoot解决前后端分离跨域问题:状态码403拒绝访问

最近在写和同学一起做一个前后端分离的项目&#xff0c;今日开始对接口准备进行 登录注册 的时候发现前端在发起请求后&#xff0c;抓包发现后端返回了一个403的错误&#xff0c;解决了很久发现是【跨域问题】&#xff0c;第一次遇到&#xff0c;便作此记录✍ 异常描述 在后端…

【AIGC风格prompt】风格类绘画风格的提示词技巧

风格类绘画风格的提示词展示 主题&#xff1a;首先需要确定绘画的主题&#xff0c;例如动物、自然景观、人物等。 描述&#xff1a;根据主题提供详细的描述&#xff0c;包括颜色、情感、场景等。 绘画细节&#xff1a;描述绘画中的细节&#xff0c;例如表情、纹理、光影等。 场…

设计模式(4)--对象行为(11)--访问者

1. 意图 表示一个作用于某对象结构中的各元素的操作。 使你可以在不改变各元素的类的前提下定义于作用于这些元素的新操作。 2. 五种角色 抽象访问者(Visitor)、具体访问者(Concrete Visitor)、抽象元素(Element)、 具体元素(Concrete Element)、对象结构(ObjectStructure) 3…

回顾2023在CSDN的足迹与2024展望

目录 一、关于博主 二、2023的历程 1、博客分类 2、年度创作数据 3、解锁勋章 4、主要的方向 二、技术感悟 1、技术深入 2、还是实践 三、展望2024 今天是2024年的第一天&#xff0c;告别2023年&#xff0c;让我们以全新的姿态&#xff0c;去迎接新的一年的挑战。2023年…

影视后期:Pr 调色处理之风格调色

写在前面 整理一些影视后期相关学习笔记博文为 Pr 调色处理中风格调色&#xff0c;涉及下面几个Demo 好莱坞电影电影感调色复古港风调色赛博朋克风格调色日系小清晰调色 理解不足小伙伴帮忙指正 简单地说就是害怕向前迈进或者是不想真正地努力。不愿意为了改变自我而牺牲目前所…

Xgboost分类模型的完整示例

往期精彩推荐 数据科学知识库机器学习算法应用场景与评价指标机器学习算法—分类机器学习算法—回归PySpark大数据处理详细教程 定义问题 UCI的蘑菇数据集的主要目的是为了分类任务&#xff0c;特别是区分蘑菇是可食用还是有毒。这个数据集包含了蘑菇的各种特征&#xff0c;如…

WorkQueue模型

WorkQueues&#xff0c;也被称为任务队列模型。当消息处理比较耗时的时候&#xff0c;可能生产消息的速度会远远大于消息的消费速度。长此以往&#xff0c;消息就会堆积越来越多&#xff0c;无法及时的处理。此时就可以使用work模型&#xff1a;让多个消费者绑定到一个队列&…

IDEA错误: 找不到或无法加载主类 com.atguigu.springcloud.EurekaServer7001_App

第一种方法&#xff1a; 可以手动点击maven中的compile编译一下&#xff0c;如下图&#xff1a; 第二种方法&#xff1a; 在pom.xml文件中加入编译插件&#xff1a; <build><plugins><!-- 编译插件 --><plugin><artifactId>maven-compiler-plu…