【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/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()

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

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Android Jetpack学习系列——Navigation

写在前面 Google在2018年就推出了Jetpack组件库&#xff0c;但是直到今天我才给重视起来&#xff0c;这真的不得不说是一件让人遗憾的事。过去几年的空闲时间里&#xff0c;我一直在尝试做一套自己的组件库&#xff0c;帮助自己快速开发&#xff0c;虽然也听说过Jetpack&#…

第一课:Transformer

第一课&#xff1a;Transformer 文章目录 第一课&#xff1a;Transformer1、学习总结&#xff1a;什么是语言模型&#xff1f;大语言模型&#xff08;LLM&#xff09;技术演变史注意力机制Transformer结构课程ppt及代码地址 2、学习心得&#xff1a;3、经验分享&#xff1a;4、…

【DevOps-02】Code编码阶段工具

一、简要说明 在code阶段,我们需要将不同版本的代码存储到一个仓库中,常见的版本控制工具就是SVN或者Git,这里我们采用Git作为版本控制工具,GitLab作为远程仓库。 Git安装安装GitLab配置GitLab登录账户二、Git安装 Git官网 Githttps://git-scm.com/

移动通信原理与关键技术学习(2)

1.多径信道滤波器表示&#xff0c;多径信道可以认为是线性时变滤波器&#xff0c;接收信号为发送信号与信道冲激响应的卷积。 2.调制就是对信号源的信息进行处理加到载波上&#xff0c;使其变为适合于信道传输的形式的过程&#xff0c;就是使载波随信号而改变的技术。 3.进行调…

VUE 若依框架,当页面设置了keepAlive=true,v-if和v-hasPermi作用在统一个按钮上时v-hasPermi失效,出现按钮显示异常问题

当前列表页设置了缓存keepAlivetrue&#xff0c;同时&#xff0c;在同一个按钮上使用v-if判断数据状态、用v-hasPermi判断按钮权限 当v-if的数据状态改变&#xff0c;由 1 变成 2 的时候&#xff0c;后面的v-hasPermi判断失效 原因&#xff1a; 是因为一开始页面初始化时&#…

HTML5+CSS3⑥——CSS三大特性、表格、列表

CSS特性 继承性 层叠性 优先级 叠加计算规则 表格 表格结构标签 合并单元格 列表 无序列表 有序列表 定义列表

显著提升VMware虚拟机运行速度的技巧

最主要是要把CPU核心减少到2&#xff0c;以前设置为4非常卡。因为我的电脑一个就4个CPU。

听GPT 讲Rust源代码--compiler(11)

File: rust/compiler/rustc_mir_transform/src/simplify.rs 在Rust源代码中&#xff0c;rust/compiler/rustc_mir_transform/src/simplify.rs文件是Rust编译器中一系列进行MIR&#xff08;中间表示&#xff09;简化的转换的实现。MIR是Rust编译器中用于进行优化和代码生成的中间…

Python遍历读取 A 文件夹中的 A1、A2、A3、A4、A5 中的各子文件夹中的图片,并对每张图片处理后保存到指定路径

目录 一、具体步骤二、文件夹目录结构样例三、代码四、实例遍历处理后结果五、总结 一、具体步骤 首先&#xff0c;指定 A 文件夹的路径和重命名后的文件夹路径。 然后&#xff0c;遍历 A 文件夹中的各子文件夹。 在每个子文件夹中&#xff0c;遍历所有文件。 读取每个文件&am…

电路分析竟然这么简单?还可以用软件仿真~

同学们大家好&#xff0c;今天我们继续学习杨欣的《电子设计从零开始》&#xff0c;这本书从基本原理出发&#xff0c;知识点遍及无线电通讯、仪器设计、三极管电路、集成电路、传感器、数字电路基础、单片机及应用实例&#xff0c;可以说是全面系统地介绍了电子设计所需的知识…

【MongoDB】关于MongoDB更新文档update的操作,十分详细,建议收藏!!!

&#x1f601; 作者简介&#xff1a;一名大四的学生&#xff0c;致力学习前端开发技术 ⭐️个人主页&#xff1a;夜宵饽饽的主页 ❔ 系列专栏&#xff1a;MongoDB数据库学习 &#x1f450;学习格言&#xff1a;成功不是终点&#xff0c;失败也并非末日&#xff0c;最重要的是继…

UDP单播

CMakeLists.txt文件中添加如下行&#xff1a; link_libraries(ws2_32) 1.发送端 #include <iostream> #include <winsock2.h> #include <cstdio>#pragma comment(lib, "Ws2_32.lib") // Link with ws2_32.libint main() {1.Initialize winsock…

googlecode.log4jdbc慢sql日志,格式化sql

前言 无论使用原生JDBC、mybatis还是hibernate&#xff0c;使用log4j等日志框架可以看到生成的SQL&#xff0c;但是占位符和参数总是分开打印的&#xff0c;不便于分析&#xff0c;显示如下的效果: googlecode Log4jdbc 是一个开源 SQL 日志组件&#xff0c;它使用代理模式实…

AI的突破与融合:2024年中国智能技术的新纪元_光点科技

随着人工智能领域的不断突破&#xff0c;2024年注定将成为中国智能技术发展的一个新纪元。当下&#xff0c;AI技术不仅在理论研究上取得了重大进展&#xff0c;其在商业应用、社会服务等领域的融合也日益深入。本文将结合近期网络上的AI热点&#xff0c;展望中国在AI技术方面的…

Springboot整合RocketMQ 基本消息处理

目录 1. 同步消息 2. 异步消息 3. 单向消息 4. 延迟消息 5. 批量消息 6. 顺序消息 7. Tag过滤 导入依赖 <dependency><groupId>org.apache.rocketmq</groupId><artifactId>rocketmq-spring-boot-starter</artifactId></dependency> …

CNN——AlexNet

1.AlexNet概述 论文原文&#xff1a;ImageNet Classification with Deep Convolutional Neural Networks 在LeNet提出后&#xff0c;卷积神经网络在计算机视觉和机器学习领域中很有名气。但卷积神经网络并没有主导这些领域。这是因为虽然LeNet在小数据集上取得了很好的效果&am…

保姆级教程:从0到1搭建web自动化测试环境

之前都是在linux上安装&#xff0c;第一次在windows上配置环境&#xff0c;加上距离上次配置环境有点久了&#xff0c;竟也花了点时间。特此记录下保姆级教程&#xff0c;给初学者一个有效的参考&#xff01; 一. 环境搭建 工具清单 工具工具名版本Java开发工具包JDK1.8浏览…

AI边缘计算智能分析网关V4如何配置周界入侵检测算法

旭帆科技的智能分析网关V4内含近40种智能分析算法&#xff0c;包括人体、车辆、消防、环境卫生、异常检测等等&#xff0c;在消防安全、生产安全、行为检测等场景应用十分广泛&#xff0c;如常见的智慧工地、智慧校园、智慧景区、智慧城管等等&#xff0c;还支持抓拍、记录、告…

C++第四天

定义一个Person类&#xff0c;私有成员int age&#xff0c;string &name&#xff0c;定义一个Stu类&#xff0c;包含私有成员double *score&#xff0c;写出两个类的构造函数、析构函数、拷贝构造和拷贝赋值函数&#xff0c;完成对Person的运算符重载(算术运算符、条件运算…

【DevOps-03】Build阶段-Maven安装配置

一、简要说明 下载安装JDK8下载安装Maven二、复制准备一台虚拟机 1、VM虚拟复制克隆一台机器 2、启动刚克隆的虚拟机,修改IP地址 刚刚克隆的虚拟机 ,IP地址和原虚拟的IP地址是一样的,需要修改克隆后的虚拟机IP地址,以免IP地址冲突。 # 编辑修改IP地址 $ vi /etc/sysconfig…