Spring AOP(面向切面编程)

以下内容由ChatGPT生成

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在通过分离关注点来提高程序的模块化。Spring AOP 主要用于横切关注点(如日志记录、安全、事务管理等)的实现。在 Spring 中,AOP 的主要功能是为 Bean 增强功能,如添加额外的行为。

1. 静态代理与动态代理

静态代理动态代理是实现 AOP 的两种主要方式。

静态代理

  • 在编译时就已经知道代理的目标类,代理类在代码中显式地定义。
  • 静态代理的缺点是需要为每个代理的类手动编写代理类,导致代码冗余且难以维护。

动态代理

  • 动态代理是在运行时生成代理类的,Java 中有两种实现动态代理的方式:JDK 动态代理CGLIB
  • 动态代理的优点是可以为任意接口生成代理,不需要手动编写代理类。
JDK 动态代理
  • JDK 动态代理只代理实现了接口的类。它通过 java.lang.reflect.Proxy 类和 java.lang.reflect.InvocationHandler 接口实现。
  • InvocationHandler 接口中定义了 invoke 方法,当代理对象调用方法时,会执行该方法。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; public class JdkProxyExample {
public static void main(String[] args) {
Foo foo = new FooImpl();
Foo proxyFoo = (Foo) Proxy.newProxyInstance(
Foo.class.getClassLoader(),
new Class<?>[]{Foo.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置增强
System.out.println("Before method: " + method.getName());
Object result = method.invoke(foo, args);
// 后置增强
System.out.println("After method: " + method.getName());
return result;
}
});
proxyFoo.doSomething();
}
} interface Foo {
void doSomething();
} class FooImpl implements Foo {
public void doSomething() {
System.out.println("Doing something...");
}
}
CGLIB 动态代理
  • CGLIB 动态代理通过生成目标类的子类来实现代理,因此可以代理没有接口的类。CGLIB 使用 ASM 字节码操作库来生成代理类。
  • CGLIB 的代理类重写目标类的方法,通过调用父类的 super 方法来实现对目标方法的调用。
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; public class CglibProxyExample {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Foo.class);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
// 前置增强
System.out.println("Before method: " + method.getName());
Object result = proxy.invokeSuper(obj, args);
// 后置增强
System.out.println("After method: " + method.getName());
return result;
}
});
Foo fooProxy = (Foo) enhancer.create();
fooProxy.doSomething();
}
} class Foo {
public void doSomething() {
System.out.println("Doing something...");
}
}

2. Spring AOP 实现原理

Spring AOP 支持 JDK 动态代理CGLIB 两种代理机制。

  • JDK 动态代理:当目标类实现了一个或多个接口时,Spring 默认使用 JDK 动态代理来为目标类创建代理对象。
  • CGLIB:如果目标类没有实现任何接口,Spring 则会使用 CGLIB 来生成目标类的代理对象。

Spring 使用 AopProxy 接口和其两个实现类 JdkDynamicAopProxyCglibAopProxy 来分别处理这两种代理机制。

Bean 被包装成 Proxy
  1. Spring 容器启动时,解析配置文件或注解,生成 Bean 定义信息。
  2. 在 Bean 初始化后,Spring AOP 的 BeanPostProcessor 之一(如 AbstractAutoProxyCreator 的子类)会检查该 Bean 是否需要 AOP 增强。
  3. 如果需要增强,则会生成一个代理对象,替换掉原始的 Bean。这一过程是通过调用 getProxy() 方法来完成的。
创建 Proxy 对象

AopProxy 接口定义了 getProxy() 方法:

  • JdkDynamicAopProxy:通过 JDK 动态代理的 Proxy.newProxyInstance() 方法创建代理对象。
  • CglibAopProxy:通过 CGLIB 的 Enhancer 类创建代理对象。
获取代理对象

getProxy() 方法返回代理对象。代理对象的创建是在调用 getProxy() 方法时动态生成的,并且在这个方法中处理了所有的 AOP 增强逻辑。

InvocationHandler 的实现

在 JDK 动态代理中,InvocationHandlerinvoke() 方法包含了拦截器链的逻辑。CglibAopProxy 通过 CallbackMethodInterceptor 实现类似的功能。

public class MyInvocationHandler implements InvocationHandler {
private final Object target; public MyInvocationHandler(Object target) {
this.target = target;
} @Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 前置处理
System.out.println("Before method: " + method.getName()); // 调用目标对象的方法
Object result = method.invoke(target, args); // 后置处理
System.out.println("After method: " + method.getName()); return result;
}
}

invoke() 方法中:

  1. 执行前置增强逻辑。
  2. 使用反射调用目标对象的方法。
  3. 执行后置增强逻辑。

3. 拦截器链与方法链的执行

Spring AOP 中的拦截器链是由 AdvisorMethodInterceptor 组成的。Advisor 包含切点(Pointcut)和通知(Advice),切点定义了哪些方法需要拦截,通知则定义了拦截时执行的逻辑。

在代理对象调用方法时:

  1. AopProxy 调用链会依次调用拦截器链中的拦截器。
  2. 拦截器链通过责任链模式处理每一个拦截器。
  3. 如果拦截器链中的某个拦截器决定执行目标方法,则会调用 MethodInvocation.proceed() 方法。
public class MyMethodInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
// 前置处理
System.out.println("Before method: " + invocation.getMethod().getName()); // 调用目标对象的方法
Object result = invocation.proceed(); // 后置处理
System.out.println("After method: " + invocation.getMethod().getName()); return result;
}
}

invoke() 方法中,proceed() 方法用于继续执行下一个拦截器或目标方法。如果没有其他拦截器,则执行目标方法。

总结

Spring AOP 使用代理模式实现横切关注点的管理,主要通过 JDK 动态代理和 CGLIB 动态代理实现。代理对象是通过 AopProxy 创建的,其中的 InvocationHandlerMethodInterceptor 负责执行拦截器链的逻辑。Spring AOP 提供了强大的功能来增强 Bean 的行为,使得切面逻辑与核心业务逻辑分离,提升了代码的模块化和可维护性。

Spring AOP概念及原理的更多相关文章

  1. Spring aop的实现原理

    简介 前段时间写的java设计模式--代理模式,最近在看Spring Aop的时候,觉得于代理模式应该有密切的联系,于是决定了解下Spring Aop的实现原理. 说起AOP就不得不说下OOP了,OO ...

  2. Spring AOP 的实现 原理

    反射实现 AOP 动态代理模式实例说明(Spring AOP 的实现 原理)   比如说,我们现在要开发的一个应用里面有很多的业务方法,但是,我们现在要对这个方法的执行做全面监控,或部分监控.也许我们 ...

  3. Spring AOP异常捕获原理

    Spring AOP异常捕获原理:        被拦截的方法,须显式的抛出异常,且不能做任何处理, 这样AOP才能捕获到方法中的异常,进而进行回滚.        换句话说,就是在Service层的 ...

  4. 漫画 | Spring AOP的底层原理是什么?

    1.Spring中配置的bean是在什么时候实例化的? 2.描述一下Spring中的IOC.AOP和DI IOC和AOP是Spring的两大核心思想 3.谈谈IOC.AOP和DI在项目开发中的应用场景 ...

  5. Spring AOP动态代理原理与实现方式

    AOP:面向切面.面向方面.面向接口是一种横切技术横切技术运用:1.事务管理: (1)数据库事务:(2)编程事务(3)声明事物:Spring AOP-->声明事物   2.日志处理:3.安全验证 ...

  6. Spring AOP概念及作用

    一:SpringAOP概念 面向切面编程(Aspect Oriented Programming)提高了另一种角度来思考程序的结构,通过预编译方式和运行期间的动态代理实现程序功能的统一维护的一种技术. ...

  7. Spring技术内幕:Spring AOP的实现原理(二)

    **二.AOP的设计与实现 1.JVM的动态代理特性** 在Spring AOP实现中, 使用的核心技术时动态代理.而这样的动态代理实际上是JDK的一个特性.通过JDK的动态代理特性,能够为随意Jav ...

  8. Spring技术内幕:Spring AOP的实现原理(一)

    一.SpringAOP的概述 1.AOP概念 AOP是Aspect-Oriented Programming(面向切面编程)的简称.维基百科的解释例如以下: Aspect是一种新的模块化机制,用来描写 ...

  9. jdk动态代理与cglib代理、spring aop代理实现原理

    原创声明:本博客来源与本人另一博客[http://blog.csdn.net/liaohaojian/article/details/63683317]原创作品,绝非他处摘取 代理(proxy)的定义 ...

  10. jdk动态代理与cglib代理、spring aop代理实现原理解析

    原创声明:本博客来源为本人原创作品,绝非他处摘取,转摘请联系博主 代理(proxy)的定义:为某对象提供代理服务,拥有操作代理对象的功能,在某些情况下,当客户不想或者不能直接引用另一个对象,而代理对象 ...

随机推荐

  1. MySQL配置主从同步过程记录

    今天由于工作需要,配置了一下主从同步,这里记录一下配置过程,以备查阅. 事先度娘了一番,主从同步需要保证主从服务器MySQL版本一致(我的略有差别,主服务器版本5.5.31,从服务器版本5.5.19) ...

  2. 记一次 .NET某工业设计软件 崩溃分析

    一:背景 1. 讲故事 前些天有位朋友找到我,说他的软件在客户那边不知道什么原因崩掉了,从windows事件日志看崩溃在 clr 里,让我能否帮忙定位下,dump 也抓到了,既然dump有了,接下来就 ...

  3. 【Java编程教程】详解Java 中的对象和类

    在本页中,我们将了解 Java 对象和类.在面向对象的编程技术中,我们使用对象和类来设计程序. Java中的对象既是物理实体又是逻辑实体,而Java中的类只是逻辑实体. 什么是Java中的对象 具有状 ...

  4. Steam Epic 启动程序默认地址

    Steam Epic 启动程(启动器)序默认地址 "D:\Games\EpicAPP\Epic Games\Launcher\Portal\Binaries\Win32\EpicGamesL ...

  5. 记一下 localstorage sessionStorage cookie 不同

    localStorage.sessionStorage.cookie 使用整理 下面从这几方面进行梳理 存储形式 相同点 不同点 使用方法 用途 多标签之间通讯 一.存储形式 1.localStron ...

  6. 接口加密传输设计及AES加解密代码DEMO

    接口加密传输设计及AES加解密代码DEMO 接口加密的方案设计:可以将请求的json字符串aes加密,通过params字段传输,接口服务端接收到参数,先解密,然后转换成对象.继续业务逻辑的处理.(另外 ...

  7. Java代码规范及异常汇总 非空异常 NullPointerException

    Java规范及异常汇总1.java.lang.NullPointerException: nullorderReq.getId() != -1 修改为: orderReq.getId() != nul ...

  8. idea文件的编码设置,解决中文编码不一致问题,对RSA验签及文本比较的测试方法 -Dfile.encoding=UTF-8

    String reqContent = "abcdef中文"; //new String("abcdefee".getBytes()," GBK &q ...

  9. CountDownLatch demo演示裁判和选手赛跑

    # CountDownLatch demo演示裁判和选手赛跑 package com.example.core.mydemo; import java.util.concurrent.CountDow ...

  10. 中国电信登录RSA算法+分析图文

    Tips:当你看到这个提示的时候,说明当前的文章是由原emlog博客系统搬迁至此的,文章发布时间已过于久远,编排和内容不一定完整,还请谅解` 中国电信登录RSA算法+分析图文 日期:2016-9-30 ...