Spring-AOP

目录

一、引入AOP

二、核心AOP概念和术语

三、切点表达式

四、Spring实现AOP

(一)@AspectJ的支持

1 、基于注解开发

1.1 引入依赖

1.2  实现目标类

1.3 定义切面类(日志管理)

1.4 将目标类和切面类纳入Spring容器

1.5 开启组件扫描、自动代理

1.6 测试

2、基于XML方式开发

(二) 基于Schema的AOP支持

1.1 声明Aspect

1.2 编写Spring配置文件(目标类使用组件扫描)

1.3 测试

五、总结


AOP (Aspect Oriented Programming)意为面向切面编程,通过预编译和运行期间动态代理实现程序功能的一种技术。Spring中通过JDK动态代理和Cglib动态代理技术实现AOP。Spring可以灵活切换这两种动态代理方式,如果代理接口会默认使用JDK动态代理,如果代理某个类,这个类没有实现接口,就会切换Cglib。此外,我们也可以配置Spring选择。


一、引入AOP

    系统开发中不仅要做核心业务, 还需要做一些系统业务,例如:事务管理、运行记录、安全日志等,这些系统业务被称为交叉业务。

    如果在每一个业务处理过程当中,都掺杂这些交叉业务进去的话,存在两方面问题:

  • 交叉业务代码在多个业务流程中反复出现,显然这些交叉代码没有得到复用。并且修改这些交叉代码,修改起来很麻烦。
  • 程序员无法专注核心业务代码的编写,在编写核心代码的同时还需要处理这些交叉业务。

     见上图,方便理解AOP思想。将非核心业务与核心业务进行分离,同时把这些非核心业务切入到业务流程当中的过程称为AOP。 

二、核心AOP概念和术语

  • JoinPoint(连接点)程序执行过程中的一个点,例如一个方法的执行或一个异常的处理。在Spring AOP中,一个连接点总是代表一个方法的执行。
  • 切点(Pointcut)真正切入切面的方法,指定哪些方法需要切入 
  • 通知(Advice)一个切面在特定连接点采取的行动,根据通知类型确定执行流程。通知包括前置通知、后置通知、环绕通知等。
  • Aspect(切面)通知 + 切面 
  • Target object(目标对象) 被一个或多个切面所 advice 的对象。也被称为 "advised object"。由于Spring AOP是通过使用运行时代理来实现的,这个对象总是一个被代理的对象。

  • AOP proxy(代理对象) 一个由AOP框架创建的对象,以实现切面契约(advice 方法执行等)。在Spring框架中,AOP代理是一个JDK动态代理或CGLIB代理。

  • Weaving(织入)将通知应用到目标对象的过程。

三、切点表达式

    切点表达式用来定义通知往哪些方法切入。

切点表达式语法格式

execution( [访问权限修饰符] 返回值类型 [全限定类名] 方法名(形式参数列表)[异常] )

     构成 @Pointcut 注解的值的 pointcut 表达式是一个常规的AspectJ pointcut表达式。关于AspectJ的 pointcut 语言的全面讨论,请参见 《AspectJ编程指南》(以及 AspectJ 5开发者笔记 的扩展)或关于AspectJ的书籍之一(如Colyer等人的《Eclipse AspectJ》,或Ramnivas Laddad的《AspectJ in Action》)。 

四、Spring实现AOP

(一)@AspectJ的支持

1 、基于注解开发

1.1 引入依赖
<!--spring context依赖-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-context</artifactId>
  <version>5.1.9.RELEASE</version>
</dependency>
<!--spring aop依赖-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.1.9.RELEASE</version>
</dependency>
<!--spring aspects依赖-->
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aspects</artifactId>
  <version>5.1.9.RELEASE</version>
</dependency>
1.2  实现目标类
@Service("userService")
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMongoDao userMongoDao;
    @Override
    public User login(String name, String password) {
        Document doc = new Document();
        doc.put("name", name);
        doc.put("password", password);
        ArrayList<Document> list = userMongoDao.queryAll(doc);
        User user = null;
        if (! list.isEmpty()) {
            Document document = list.get(0);
            user = new User();
            user.setId((ObjectId) document.get("_id"));
            user.setName((String) document.get("name"));
        }
        return user;
    }
}
1.3 定义切面类(日志管理)
package com.zookin.service.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class LoggerAspect {
    private static final Logger LOGGER = LoggerFactory.getLogger(LoggerAspect.class);

    @Pointcut("execution(public * com.zookin.service.*.*(..))")
    public void logPointcut() {}

    @Before("logPointcut()")
    public void beforeAdvice(JoinPoint joinPoint) {
        LOGGER.info("before advice:" + joinPoint.getSignature().getName());
    }

    @Around("logPointcut()")
    public Object aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
        long startTime = System.currentTimeMillis();
        Object result = joinPoint.proceed();
        long endTime = System.currentTimeMillis();
        LOGGER.info("Method:" + joinPoint.getSignature().getName() + " execution time:" + (endTime - startTime) + "ms");
        return result;
    }

    @AfterReturning(pointcut = "logPointcut()", returning = "result")
    public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
        LOGGER.info("After returning from method: " + joinPoint.getSignature().getName() + ", result: " + result);
    }

    @AfterThrowing(pointcut = "logPointcut()", throwing = "exception")
    public void afterThrowingAdvice(JoinPoint joinPoint, Exception exception) {
        LOGGER.error("Exception thrown from method: " + joinPoint.getSignature().getName() + ", exception: " + exception.getMessage());
    }

}
1.4 将目标类和切面类纳入Spring容器

  目标类添加@Service注解,切面类添加@Component、@Aspect注解。 

1.5 开启组件扫描、自动代理
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">

    <context:component-scan base-package="com.zookin.service"/>
    <aop:aspectj-autoproxy proxy-target-class="true"/>

</beans>
1.6 测试
@Test
    public void loginTest() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = applicationContext.getBean("userService", UserService.class);
        User login = userService.login("zookin", "zookin");
        System.out.println(login);
}

2、基于XML方式开发

略.... 

(二) 基于Schema的AOP支持

  如果喜欢基于XML的格式,Spring也提供了对使用 aop 命名空间标签定义切面的支持。它支持与使用 @AspectJ 风格时完全相同的 pointcut 表达式和advice种类。要使用本节描述的 aop 命名空间标签,你需要导入 spring-aop schema,如 基于XML schema的配置 中所述。

 在你的Spring配置中,所有的aspect和 advisor元素都必须放在一个 <aop:config> 元素(你可以在一个应用上下文配置中拥有多个 <aop:config> 元素)。一个 <aop:config> 元素可以包含 pointcut、 advisor 和 aspect 元素(注意这些必须按顺序声明)。

1.1 声明Aspect

      通过使用 <aop:aspect> 元素来声明一个切面,并通过使用 ref 属性来引用支持 Bean,如下例所示。

<aop:config>
    <aop:aspect id="myAspect" ref="aBean">
        ...
    </aop:aspect>
</aop:config>

<bean id="aBean" class="...">
    ...
</bean>

支持切面的Bean(本例中的 aBean)当然可以像其他Spring Bean一样被配置和依赖注入。 

1.2 编写Spring配置文件(目标类使用组件扫描)

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       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">

    <context:component-scan base-package="com.zhj.service"/>
    <aop:aspectj-autoproxy proxy-target-class="true"/>

    <bean id="timerAspect" class="com.zhj.service.aspect.TimerAspect"></bean>

    <aop:config>
        <aop:pointcut id="aa" expression="execution(* com.zhj.service.CommodityService.*(..))"/>
        <aop:aspect ref="timerAspect">
            <aop:around method="time" pointcut-ref="aa"/>
        </aop:aspect>
    </aop:config>
    
</beans>

1.3 测试

    @Test
    public void commodityTest() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
        CommodityService commodityService = applicationContext.getBean("commodityService", CommodityService.class);
        ArrayList<Commodity> commodities = commodityService.queryCommodity("自行车", 0, null);
    }


 


五、总结

   AOP是Spring框架的核心组件,AOP蕴含的底层原理十分值得了解和挖掘。Spring 框架自5.0版本以来,集成了Log4j、SLF4j框架,本文我简单地整合日志框架来说明AOP的实现,此外我们可以使用AOP实现事务管理,见上一篇博客。上述内容如果有错误的地方,希望大佬们可以指正。我一直在学习的路上,您的帮助使我收获更大!觉得对您有帮助的话,还请点赞支持!我也会不断更新文章!Spring-事务支持icon-default.png?t=N7T8https://mp.csdn.net/mp_blog/creation/editor/134687195

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

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

相关文章

分布式搜索引擎(Elastic Search)+消息队列(RabbitMQ)部署

一、分布式搜索引擎&#xff1a;Elastic Search Elastic Search的目标就是实现搜索。是一款非常强大的开源搜索引擎&#xff0c;可以帮助我们从海量数据中快速找到需要的内容。在数据量少的时候&#xff0c;我们可以通过索引去搜索关系型数据库中的数据&#xff0c;但是如果数…

MySQL-含json字段表和与不含json字段表查询性能对比

含json字段表和与不含json字段表查询性能对比 说明: EP_USER_PICTURE_INFO_2:不含json字段表 20200729json_test:含有json字段表 其中20200729json_test 标准ID、MANAGER_NO、PHONE_NO 为非json字段 data为json字段 2个表中MANAGER_NO、PHONE_NO都创建了各自的索引 测试…

iphone/安卓手机如何使用burp抓包

iphone 1. 电脑 ipconfig /all 获取电脑网卡ip&#xff1a; 192.168.31.10 2. 电脑burp上面打开设置&#xff0c;proxy&#xff0c;增加一条 192.168.31.10:8080 3. 4. 手机进入设置 -> Wi-Fi -> 找到HTTP代理选项&#xff0c;选择手动&#xff0c;192.168.31.10:8080 …

gitlab注册无中国区电话验证问题

众所周知gitlab对中国区不友好&#xff0c;无法直接注册&#xff0c;页面无法选择86的手机号进行验证码发送。 Google上众多的方案是修改dom&#xff0c;而且时间大约是21年以前。 修改dom&#xff0c;对于现在的VUE、React框架来说是没有用的&#xff0c;所以不用尝试。 直接看…

the name of a constructor must match the name of the enclosing class

构造器名匹配封闭类名 命令码的位置关系不对 解决&#xff1a;调整 命令码所在层级

pandas详细笔记

一&#xff1a;什么是Pandas from matplotlib import pyplot import numpy as np import pandas as pdarange np.arange(1, 10, 2) series pd.Series(arange,indexlist("ABCDE")) print(series)二&#xff1a;索引 三&#xff1a;切片 位置索引切片&#xff08;左闭…

排序的概念及其运用

1.排序的概念 排序&#xff1a;所谓排序&#xff0c;就是使一串记录&#xff0c;按照其中的某个或某些关键字的大小&#xff0c;递增或递减的排列起来的操作。 稳定性&#xff1a;假定在待排序的记录序列中&#xff0c;存在多个具有相同的关键字的记录&#xff0c;若经过排序…

华清远见嵌入式学习——C++——作业6

作业要求&#xff1a; 代码&#xff1a; #include <iostream>using namespace std;class Animal { public:virtual void perform() 0;};class Lion:public Animal { private:string foods;string feature; public:Lion(){}Lion(string foods,string feature):foods(foo…

SpringBoot_02

Web后端开发_07 SpringBoot_02 SpringBoot原理 1.配置优先级 1.1配置 SpringBoot中支持三种格式的配置文件&#xff1a; application.propertiesapplication.ymlapplication.yaml properties、yaml、yml三种配置文件&#xff0c;优先级最高的是properties 配置文件优先级…

PET(Point-Query Quadtree for Crowd Counting, Localization, and More)

PET&#xff08;Point-Query Quadtree for Crowd Counting, Localization, and More&#xff09; 介绍实验记录训练阶段推断阶段 介绍 论文&#xff1a;Point-Query Quadtree for Crowd Counting, Localization, and More 实验记录 训练阶段 TODO 推断阶段 下面是以一张输…

图解Spark Graphx实现顶点关联邻接顶点的collectNeighbors函数原理

一、场景案例 在一张社区网络里&#xff0c;可能需要查询出各个顶点邻接关联的顶点集合&#xff0c;类似查询某个人关系比较近的都有哪些人的场景。 在用Spark graphx中&#xff0c;通过函数collectNeighbors便可以获取到源顶点邻接顶点的数据。 下面以一个例子来说明&#…

C语言之程序的组成和元素格式

目录 关键字 运算符 标识符 姓名和标识符 分隔符 常量和字符串常量 自由的书写格式 书写限制 连接相邻的字符串常量 缩进 本节我们来学习程序的各组成元素&#xff08;关键字、运算符等&#xff09;和格式相关的内容。 关键字 在C语言中&#xff0c;相if和else这样的标识…

Arduino学习笔记2023年11月30日

目录 1 编程软件下载2 代码结构3 IO引脚控制3.1 引脚初始化3.2 引脚使用数字量输出数字量输入模拟量输出模拟量输入 4 串口串口初始化串口输出串口输入 5 外部中断6 函数6.1 映射区间函数6.2 延时函数 总结 1 编程软件下载 官网链接&#xff1a;https://www.arduino.cc/ 下载链…

python学习:opencv+用鼠标画矩形和圆形

目录 步骤 定义数据 新建一个窗口黑色画布 显示黑色画布 添加鼠标回调函数 循环 一直显示图片 一直判断有没有按下字母 m 关闭所有窗口 鼠标回调函数 步骤 当鼠标按下记录坐标并记录鼠标标记位为true&#xff0c;移动的时候就会不断的画矩形或者圆&#xff0c;松下的时候就再…

Apache Doris 在某工商信息商业查询平台的湖仓一体建设实践

本文导读&#xff1a; 信息服务行业可以提供多样化、便捷、高效、安全的信息化服务&#xff0c;为个人及商业决策提供了重要支撑与参考。本文以某工商信息商业查询平台为例&#xff0c;介绍其从传统 Lambda 架构到基于 Doris Multi-Catalog 的湖仓一体架构演进历程。同时通过一…

CC++内存管理方式

文章目录 1. C/C内存分布总结 C语言中动态内存管理C内存管理方式new/delete操作内置类型new和delete操作自定义类型c推荐是用new和deleteoperator new与operator delete函数 定位new 1. C/C内存分布 我们先来看下面的一段代码和相关问题 int globalVar 1; static int static…

用Python手把手教你WordCloud可视化

目录 WordCloud是什么&#xff1f; 具体使用 总结 WordCloud是什么&#xff1f; WordCloud是一种数据可视化技术&#xff0c;通过根据文本中单词的频率或权重来生成一个视觉上吸引人的词云图。在词云图中&#xff0c;单词的大小和颜色通常与其在文本中的出现频率相关&#…

STM32F1外部中断EXTI

目录 1. EXTI简介 2. EXTI基本结构 3. AFIO复用IO口 4. EXTI框图 5. EXTI程序配置 5.1 首先先配置要使用的GPIO口的引脚 5.2 配置AFIO数据选择器&#xff0c;选择想要中断的引脚 5.3 EXTI配置 1. EXTI简介 EXTI&#xff08;Extern Interrupt&#xff09;外部中…

Qt创建和使用动态库链接

首先建立库文件 顺序确认完成后&#xff0c;构建完成 注意&#xff1a;上图中mydll_global.h中的内容可以复制到mydll.h中去&#xff0c;在以后调用时只调用mydll.h即可&#xff0c;否则调用时需要两个头文件同事使用。 在mydll.h和mydll.cpp中可以正常编写代码&#xff…

这个sql有点东西,记录一下

我有一个需求&#xff1a;在订单表里面查询指定时间的订单数据&#xff0c;如果要是没有订单的话&#xff0c;需要展示当天日期和数据&#xff0c;数据为0 先看一下效果&#xff1a; 话不多说&#xff0c;直接上SQL SELECTdate_range.date AS 日期,COUNT( oco.id ) AS 总订单…