首页 > 其他分享 >Spring——AOP

Spring——AOP

时间:2023-03-12 12:55:05浏览次数:25  
标签:连接点 Spring 代理 public AOP Hello

Spring中的AOP

AOP 是 Aspect Oriented Programming(面向切面编程)的首字母缩写,是一种编程范式,它的目的是通过分离横切关注点(cross-cutting concerns)来提升代码的模块化程度。

AOP中提到的关注点,其实就是一段特定的功能,有些关注点出现在多个模块中,就称为横切关注点

AOP解决了两个问题:

  • 代码混乱:核心的业务逻辑代码还必须兼顾其他功能,这就导致不同功能的代码交织在一起,可读性很差
  • 代码分散:同一个功能的代码分散在多个模块中,不易维护。

AOP中几个重要概念

概念 说明
切面(aspect) 按关注点进行模块分解时,横切关注点就表示为一个切面
连接点(join point) 程序执行的某一刻,在这个点上可以添加额外的动作
通知(advice) 切面在特定连接点上执行的动作
切入点(pointcut) 切入点是用来描述连接点的,它决定了当前代码与连接点是否匹配

aop的具体流程:通过切入点来匹配程序中的特定连接点,在这些连接点上执行通知,这种通知可以是在连接点前后执行,也可以是将连接点包围起来

Spring AOP的实现原理

在Spring中,AOP背后的实现原理是基于动态代理技术(Dynamic Proxy),代理模式是GoF提出的23种经典设计模式之一,我们可以对某个对象提供一个代理,控制对该对象的访问,代理可以在两个有调用关系的对象之间起到中介作用——代理封装了目标对象,调用者调用了代理的方法,代理再去调用实际的目标对象
代理模式示意图
动态代理就是在运行时动态地为对象创建代理的技术,在Spring中,由AOP框架创建、用来实现切面的对象被称为AOP代理(AOP Proxy),一般采用JDK动态代理或者是CGLIB代理;二者区别如下:

必须实现接口 支持拦截public方法 支持拦截protected方法 拦截默认作用域方法
JDK动态代理
CGLIB代理

Spring容器在为Bean注入依赖时,会自动将被依赖Bean的AOP代理注入进来,这就让我们感觉是在使用原始的Bean,实则不然。

被切面拦截的对象称为目标对象(Target Object)或通知对象(Advised Object),因为Spring用了动态代理,所以目标对象就是要被代理的对象。

以JDK代理为例,假设我们想在say()方法前后增加两条日志,可以采用下面的代码

点击查看代码
/**
 * TODO 要被动态代理的Hello接口及其实现片段
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/3/12 10:45
 */
interface Hello {
    void say() throws NoSuchMethodException;
}

public class SpringHello implements Hello {
    @Override
    public void say() throws NoSuchMethodException {
        System.out.println(this.getClass().getName() + ": " + this.getClass().getMethod("say") + "Hello SpringAOP!");
    }
}

随后,我们再实现一个InvocationHandler,于是对代理对象的调用都会转为调用invoke方法,传入的参数中就会包含了所调用的方法和实际的参数
点击查看代码
/**
 * TODO 在Hello.say()前后打印日志的InvocationHandler
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/3/12 10:47
 */
public class LogHandler implements InvocationHandler {
    private Hello source;

    public LogHandler(Hello source) {
        this.source = source;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("Ready to say something");
        try{
            return method.invoke(source,args);
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            System.out.println("Already say something");
        }
        return method.invoke(source,args);
    }
}
最后,再通过Proxy.newProxyInstance()为Hello实现类的Bean实例创建使用LogHandler的代理
点击查看代码
/**
 * TODO 使用Proxy.newProxyInstance()获取代理的目标对象
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/3/12 10:50
 */
public class AopApplication {
    public static void main(String[] args) {
        SpringHello original = new SpringHello();
        Hello target =(Hello) Proxy.newProxyInstance(Hello.class.getClassLoader(),original.getClass().getInterfaces(),new LogHandler(original));
        try {
            target.say();
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }
    }
}
运行结果如下:

image
Spring AOP的实现方式:

  • JDK动态代理:AopProxyFactory会创建JdkDynamicAopProxy
  • CGLIB代理:创建ObjenesisCglibApoProxy

基于@AspectJ的配置

Spring Framework同时支持@AspectJ注解和XML Schema两种方式来使用AOP。

基于注解的方式

首先,需要引入org.springframework:spring-aspects依赖,以便使用AspectJ相关的注解和功能。

 	<dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>6.0.3</version>
	</dependency>

要开启@AspectJ支持,可以在Java配置类上增加@EnableAspectJAutoProxy注解

/**
 * TODO 基于注解的方式
 *
 * @author ss_419
 * @version 1.0
 * @date 2023/3/12 12:10
 */
@Configuration
@EnableAspectJAutoProxy
public class Config {
}

@EnableAspectJAutoProxy有两个属性,两者默认值都是false

  • proxyTargetClass用于选择是否开启基于类的代理(是否使用CGLIB来做代理)
  • exposeProxy用于选择是否将代理对象暴露到AopContext中
<?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: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/beans/spring-aop.xsd">
    <aop:aspectj-autoproxy/>
</beans>

注解方式的切入点声明由两部分组成——切入点表达式和切入点方法签名。
前者用来描述要匹配的连接点,后者可以用来引入切入点,方便切入点的复用。

@Pointcut注解中使用的就是AspectJ5的表达式,其中一些常用的PCD(pointcut designator,切入点标识符)

PCD 说明
execution 最常用的一个PCD,用来匹配特定方法的执行
within 匹配特定范围内的类型,可以用通配符来匹配某个Java包内的所有类
this Spring AOP代理对象这个Bean本身要匹配某个给定的类型
target 目标对象要匹配某个给定的类型,比this更常用一些
args 传入的方法参数要匹配给定的类型,它也可以用于绑定请求参数
bean Spring AOP 特有的一个PCD,匹配Bean的ID或名称,可以用通配符

execution常见表达式:
每个部分都可以使用*通配符

类名中使用.表示包中的所有类,..表示当前包与子包中的所有类

参数情况:

  • ()表示方法无参数
  • (..)表示有任意个参数
  • (*) 表示有一个任意类型的参数
  • (String表示有一个String类型参数
  • (String,String)代表有两个String类型的参数

前置通知:@Before()
后置通知:@AfterReturning()
环绕通知:@Around()

标签:连接点,Spring,代理,public,AOP,Hello
From: https://www.cnblogs.com/atwood-pan/p/17207995.html

相关文章

  • springcloud介绍
    一、微服务1、总览-微服务的技术栈注册中心,管理服务的IP和端口等配置中心,实现配置热部署消息队列,通过发送消息实现异步通知,避免服务链路过长带来的时间损失服务路由......
  • SpringBoot中使用POI导出Excel时怎样循环数据库数据赋值
    场景在已经实现简单的Excel导出的前提下,要结合具体业务实现查询数据库,并遍历赋值到excel上。实现使用MyBatisPlus从数据库查询数据Map<String,Object>param=newHashMap<St......
  • IDEA中进行SpringBoot整合spring-ws开发webservice接口后期要修改xsd文件流程
    场景SpringBoot整合spring-ws开发webservice接口(全流程详细教程)现在接口已经开发完毕,但是在后期进行调试时发现在C#程序中进行调用时某个接口没有响应。原因是不同接口中存......
  • SpringCloud-使用路由网关统一访问接口(附代码下载)
    上面在实现了使用熔断仪表盘进行监控熔断后,使用路由网关统一访问接口。API网关API网关负责请求路由、组合和协议转发。所有的客户端请求首先要通过API网关,之后请求被路由到......
  • SpringCloud-创建服务消费者-Feign方式(附代码下载)
    场景在上面已经实现服务注册中心、服务提供者和以Ribbon方式实现服务消费者的前提下,使用另一种Feign方式实现服务消费者。FeignFeign是一个声明式的伪Http客户端,它使得写......
  • SpringCloud -创建统一的依赖管理
    场景SpringCloud为开发者提供了在分布式系统(配置管理,服务发现,熔断,路由,微代理,控制总线,一次性Token,全居琐,Leader选举,分布式Session,集群状态)中快速构建的工具,使用Spring......
  • aop+自定义注解实现数据源切换
    pom.xml依赖<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"......
  • SpringCloud第一部分(认识微服务、RestTemplate、Eureka、Ribbon、Nacos、Feign)
    认识微服务单体架构将业务的所有功能集中在一个项目中开发打成一个包部署优点:架构简单部署成本低缺点:耦合度高分布式架构根据业务功能对系统进行拆分,每个业......
  • SpringSecurity
    SpringSecurity框架简介1.1概要Spring是非常流行和成功的Java应用开发框架,SpringSecurity正是Spring家族中的成员。SpringSecurity基于Spring框架,提供......
  • 【书】【看透 Spring MVC】
    1  集群与分布式集群和分布式处理都是使用多台服务器进行处理的,集群是每台服务器都具有相同的功能,处理请求时调用哪台服务器都可以,主要起分流的作用,分布式是将不同的业......