深入解析Spring源码,揭示JDK动态代理的工作原理。

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 深入解析Spring源码,揭示JDK动态代理的工作原理。

JDK动态代理是Java中一种强大的机制,它允许在运行时创建代理对象,并拦截对这些对象方法的调用。Spring框架广泛使用JDK动态代理来实现AOP(Aspect-Oriented Programming)功能。下面将深入解析Spring源码,揭示JDK动态代理的工作原理。

 

JDK动态代理简介

 

JDK动态代理基于反射机制,它主要涉及两个核心接口:

1. `InvocationHandler`:定义了处理代理实例上的方法调用的逻辑。

2. `Proxy`:提供了静态方法来创建代理实例。

 

Spring 使用 JDK 动态代理的场景

 

Spring AOP在以下情况下会使用JDK动态代理:

- 目标对象实现了一个或多个接口。

- 没有强制使用CGLIB(即没有设置`proxyTargetClass=true`)。

 

JDK动态代理的核心类

 

`ProxyFactory`

 

`ProxyFactory`是Spring AOP框架中用于创建代理对象的重要类。它根据目标对象是否实现接口选择合适的代理策略。

 

```java
public class ProxyFactory extends AdvisedSupport implements AopProxyFactory {
    // 省略其他代码...
 
    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            return new CglibAopProxy(config);
        } else {
            return new JdkDynamicAopProxy(config);
        }
    }
 
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class<?>[] interfaces = config.getProxiedInterfaces();
        return (interfaces.length == 0 || (interfaces.length == 1 && SpringProxy.class.isAssignableFrom(interfaces[0])));
    }
}
```

 

在上面的代码中,如果目标对象实现了接口且未强制使用CGLIB,`createAopProxy`方法会返回一个`JdkDynamicAopProxy`实例。

 

`JdkDynamicAopProxy`

 

`JdkDynamicAopProxy`类负责使用JDK动态代理创建代理对象。

 

```java
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    private final AdvisedSupport advised;
 
    public JdkDynamicAopProxy(AdvisedSupport config) {
        Assert.notNull(config, "AdvisedSupport must not be null");
        this.advised = config;
    }
 
    @Override
    public Object getProxy(@Nullable ClassLoader classLoader) {
        return Proxy.newProxyInstance(classLoader, this.advised.getProxiedInterfaces(), this);
    }
 
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        MethodInvocation invocation = new ReflectiveMethodInvocation(proxy, this.advised.getTargetSource().getTarget(), method, args, this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, this.advised.getTargetClass()));
        return invocation.proceed();
    }
}
```

 

1. 在`getProxy`方法中,通过`Proxy.newProxyInstance`创建代理实例,该实例会将所有方法调用委托给`invoke`方法。

2. `invoke`方法是代理实例的核心逻辑。它创建一个`MethodInvocation`对象并调用其`proceed`方法,以执行链式拦截器和目标方法。

 

`ReflectiveMethodInvocation`

 

`ReflectiveMethodInvocation`是Spring AOP中具体的方法调用实现。

 

```java
public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    protected final Object proxy;
    protected final Object target;
    protected final Method method;
    protected Object[] arguments;
    private final List<Object> interceptorsAndDynamicMethodMatchers;
    private int currentInterceptorIndex = -1;
 
    public ReflectiveMethodInvocation(Object proxy, Object target, Method method, Object[] arguments, List<Object> interceptorsAndDynamicMethodMatchers) {
        this.proxy = proxy;
        this.target = target;
        this.method = method;
        this.arguments = arguments;
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }
 
    @Override
    public Object proceed() throws Throwable {
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            return this.method.invoke(this.target, this.arguments);
        }
 
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof MethodInterceptor) {
            MethodInterceptor interceptor = (MethodInterceptor) interceptorOrInterceptionAdvice;
            return interceptor.invoke(this);
        } else {
            return proceed();
        }
    }
}
```

 

1. `proceed`方法是拦截器链执行的核心。

2. 如果所有拦截器都已执行,则直接调用目标方法。

3. 否则,获取下一个拦截器并调用其`invoke`方法。

 

示例代码

 

让我们通过一个简单的例子来展示Spring中JDK动态代理的实际应用。

 

示例接口和实现

 

```java
public interface HelloService {
    void sayHello();
}
 
public class HelloServiceImpl implements HelloService {
    @Override
    public void sayHello() {
        System.out.println("Hello, World!");
    }
}
```

 

自定义拦截器

 

```java
public class CustomInterceptor 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;
    }
}
```

 

创建代理并使用

 

```java
public class Main {
    public static void main(String[] args) {
        HelloService target = new HelloServiceImpl();
 
        ProxyFactory proxyFactory = new ProxyFactory();
        proxyFactory.setTarget(target);
        proxyFactory.addAdvice(new CustomInterceptor());
 
        HelloService proxy = (HelloService) proxyFactory.getProxy();
        proxy.sayHello();
    }
}
```
 
#### 输出
 
```
Before method: sayHello
Hello, World!
After method: sayHello
```

 

总结

 

通过深入解析Spring的源码,我们了解了JDK动态代理是如何在Spring AOP中工作的。`ProxyFactory`根据目标对象的情况选择合适的代理实现,而`JdkDynamicAopProxy`通过`Proxy.newProxyInstance`创建代理对象,并在`invoke`方法中管理拦截器的执行。最后,通过`ReflectiveMethodInvocation`类,Spring实现了对方法调用的拦截和增强。这种设计使得Spring AOP能够灵活地处理各种切面需求,提供了强大的AOP功能。

目录
相关文章
|
17天前
|
数据采集 监控 前端开发
二级公立医院绩效考核系统源码,B/S架构,前后端分别基于Spring Boot和Avue框架
医院绩效管理系统通过与HIS系统的无缝对接,实现数据网络化采集、评价结果透明化管理及奖金分配自动化生成。系统涵盖科室和个人绩效考核、医疗质量考核、数据采集、绩效工资核算、收支核算、工作量统计、单项奖惩等功能,提升绩效评估的全面性、准确性和公正性。技术栈采用B/S架构,前后端分别基于Spring Boot和Avue框架。
|
26天前
|
存储 算法 Java
解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用
在Java中,Set接口以其独特的“无重复”特性脱颖而出。本文通过解析HashSet的工作原理,揭示Set如何利用哈希算法和equals()方法确保元素唯一性,并通过示例代码展示了其“无重复”特性的具体应用。
41 3
|
19天前
|
搜索推荐 Java Spring
Spring Filter深度解析
【10月更文挑战第21天】Spring Filter 是 Spring 框架中非常重要的一部分,它为请求处理提供了灵活的控制和扩展机制。通过合理配置和使用 Filter,可以实现各种个性化的功能,提升应用的安全性、可靠性和性能。还可以结合具体的代码示例和实际应用案例,进一步深入探讨 Spring Filter 的具体应用和优化技巧,使对它的理解更加全面和深入。
|
1天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
9 2
|
7天前
|
前端开发 Java 开发者
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
28 9
|
26天前
|
存储 SQL 数据挖掘
TDengine 流计算与窗口机制的深度解析:揭示计数窗口的关键作用
在 TDengine 3.2.3.0 版本中,我们针对流式计算新增了计数窗口,进一步优化了流式数据处理的能力。本文将为大家解读流式计算与几大窗口的关系,并针对新增的计数窗口进行详细的介绍,帮助大家进一步了解 TDengine 流式计算,以便更好地进行应用。
28 1
|
29天前
|
Java 关系型数据库 MySQL
【编程基础知识】Eclipse连接MySQL 8.0时的JDK版本和驱动问题全解析
本文详细解析了在使用Eclipse连接MySQL 8.0时常见的JDK版本不兼容、驱动类错误和时区设置问题,并提供了清晰的解决方案。通过正确配置JDK版本、选择合适的驱动类和设置时区,确保Java应用能够顺利连接MySQL 8.0。
120 1
|
1月前
|
Java Spring
Spring底层架构源码解析(三)
Spring底层架构源码解析(三)
104 5
|
28天前
|
XML Java 数据格式
Spring IOC容器的深度解析及实战应用
【10月更文挑战第14天】在软件工程中,随着系统规模的扩大,对象间的依赖关系变得越来越复杂,这导致了系统的高耦合度,增加了开发和维护的难度。为解决这一问题,Michael Mattson在1996年提出了IOC(Inversion of Control,控制反转)理论,旨在降低对象间的耦合度,提高系统的灵活性和可维护性。Spring框架正是基于这一理论,通过IOC容器实现了对象间的依赖注入和生命周期管理。
62 0
|
2月前
|
Java
安装JDK18没有JRE环境的解决办法
安装JDK18没有JRE环境的解决办法
293 3

推荐镜像

更多