Spring5系列(十) | 动态代理底层实现

简介: Spring5系列(十) | 动态代理底层实现

我们在上面的几篇文章中已经了解了如何使用spring进行aop的开发,本篇文章我们来介绍一下动态代理的底层实现。

一. AOP编程概念

AOP: Aspect oriented programming: 面向切面编程 = spring动态代理开发。以切面为基本单位的程序开发,通过切面间的批次协同,相互调用,完成程序构建。  切面 = 切入点 + 额外功能
OOP: Object Oriented Programming: 面向对象编程,以对象为基本单位的程序开发,通过过程间的批次协同,相互调用,完成程序构建
POP: Procedure Oriented Programming: 面向过程(函数,方法)编程,以过程为基本单位的程序开发,通过过程间彼此协同,相互调用,完成程序构建
AOP编程的本质就是Spring动态代理开发,通过代理类为原始类增加额外功能。好处就是利于原始类的维护
注意: aop编程不可能取代oop功能,是一种有力的补充。

回顾AOP编程的开发步骤:

  • 原始对象
  • 额外功能(MethodBeforeAdvice, MethodInterceptor)
  • 切入点(切入点表达式)
  • 组装
切面 = 切入点 + 额外功能

核心问题:

1. AOP如何创建代理类:
  通过动态字节码技术
2. Spring工厂如何加工创建代理对象
  通过原始对象的id, 获得的是代理对象

二. 动态代理实现

spring底层的动态代理有两种实现方式,一是JDK的动态代理技术,而是Cglib开源框架提供的动态代理技术。

2.1 JDK动态代理

jdk的动态代理,必须是基于接口进行代理,也就是我们的目标类必须实现一个接口,才能进行代理。我们给出案例,这里省略了UserService, 和 UserServiceImpl.

创建代理三个要素: 
  1. 原始对象
  2. 额外功能
  3. 代理对象和原始对象实现相同的接口
JDK为我们了提供了Proxy.newInstance(ClassLoader var0, Class<?>[] var1, InvocationHandler var2) 方法类实现动态代理技术。
参数介绍  
@param: ClassLoader var0: 创建代理对象所需的类加载器
@param: interfaces: 和原始对象实现的接口数组
@param: InvocationHandler: 额外功能
这里InvocatioHandler也是一个接口,所以我们需要传如一个实现。该接口有一个方法需要实现:  Object invoke(Object proxy, Method method, Object[] args);
@param Object proxy:代表代理对象,忽略,不要使用
@param Methdod method: 代表额外功能增加给的原始方法
@param Object[] args: 原始方法的参数
@return: Object: 原始方法的返回值
这种写法和我们之前的MethodInterceptor很像,毕竟底层就是这么实现的。我们直接程序应该怎么写
public class JDKProxyTest{
  public static void main(String[] args){
    // 1. 创建原始对象
    Userservice userService = new UserServiceImpl();
    // 2. 创建动态代理类
      UserService proxy = (UserService)Proxy.newInstance(userService.getClass.getClassLoader() ,userService.getClass.getInterfaces() , new InvocationHandler(){
      public Object invoke(Object proxy, Method method, Object[]args){
        // 前置额外功能
        Object obj =  method.invoke(userService, args);
        // 后置额外功能
        return obj;
      }
    });
    proxy.login("abc", "123456");
  }
}

我们在InvocationHandler接口中的实现方法里加入了我们想要的额外功能,并通过调用method.invoke() 完成原始方法的调用。同时将原始方法的返回值返回,此时我们需要使用接口来接收代理对象(因为代理对象和原始对象实现了同一个接口),要注意的是这个代理对象是动态生成的,所以我们可能找不到他的具体源码,当我们使用他调用方法的时候,额外功能就可以执行了。

注意事项:

类加载器的作用:
1. 通过类加载器吧对应的类字节码文件加载到JVM中
2. 通过类加载器创建类的Class对象进而创建这个类的对象
如何获得类加载器:
虚拟机为每一个类的.class文件自动分配与之对应的ClassLoader,动态代理类没有源文件,它是通过动态字节码技术生成,把字节码直接写入jvm.
此时在动态代创建的过程中,需要ClassLoader创建代理类的Class对象,可是因为动态代理类没有.classs文件,JVM也就不会为他分配ClassLoader,但是又需要,就只能借用一个。所以找一个我们自己写的类获取Class对象在调用getClassLoader()即可,这里注意不要使用JDK的类获取,因为不是一个类加载器。
复制代码

2.2 CgLib动态代理

上面说了JDK的动态代理技术的实现。但是JDK的动态代理技术有一个弊端,就是原始类必须要实现一个接口,如果原始类没有实现任何接口,此时想要给他创建动态代理类,JDK的动态代理就实现不了了。而Cglib可以实现。

cglib动态代理原理:
  cglib所创建的代理类是通过继承的方式实现的,他会继承原始类。原始类作为父类,代理类作为子类,这样就可以保证二者方法相同。而不需要实现接口。

代码实现:

publicclassUserService{
publicbooleanlogin(Stringname, Stringpassword){
System.out.println("login...");
  }
publicvoidregister(Useruser){
System.out.println("register...");
  }
}
// 测试类classTest{
/**Enhancer.setClassLoader();*/publicstaticvoidmain(String[] args){
UserServiceuserService=newUserService();
Enhancerenhancer=newEnhancer();
enhander.setClassLoader(Test.class.getClassLoader());
enhander.setSuperClass(userService.class);
MethodInteceptorinterceptor=newMethodInterceptor(){
@OverridepublicObject(Objecto, Methodmethod, Object[] args, MethodProxymethodProxy) throwsThrowable{
System.out.println("----log-----");
Objectobj=method.invoke(userService, args);
returnobj;
        }
      };
enhancer.setCallBack(interceptor);
UserServiceproxy= (UserService)Enhancer.create();
proxy.login("abc", "123");
proxy.register(newUser());
  }
}
复制代码

总结:

  1. JDK动态代理,Proxy.newInstance : 通过接口创建代理的实现类
  2. CGlib: 动态代理, Enhancer, 通过父子类继承

三. spring工厂如何创建代理对象

上面我们讲述了spring中两种动态代理的实现。通过动态代理技术,就可以创建出代理对象。那么在spring中,为什么我们通过原始bean的id就可以得到代理对象呢。我们来浅析一下他的原理。其实他主要还是通过BeanPostProcessor这个接口实现的。这个接口我们在前面介绍过。

image.png

相当于我们在加工的过程中,创建了他的动态代理对象,进行了返回。这样我们获取的对象就是动态代理对象了。我们来写个案例。

publicinterfaceUserService{
voidregister(Useruser);
booleanlogin(Stringname, Stringpassword)
}
publicclassUserServiceImplimplementsUserService{
@Overridepublicvoidregister(Useruser){
System.out.println("registe----")
  }
@Overridepublicbooleanlogin(Stringname, Stringpassword){
System.out.println("login-----")
  }
}
publicclassProxyBeanPostProcessorimplementsBeanPostProcessor{
@OverridepublicObjectpostProcessBeforeInitialization(Objectbean, StringbeanName) throwsBeansException{
returnbean;
  }
@OverridepublicObjectpostProcessAfterInitialization(Objectbean, StringbeanName) throwsBeansException{
returnProxy.newInstance(this.getClass.getClassLoader(), bean.getClass.getInterfaces,newInvocationHandler(){
publicObjectinvoke(Objectproxy, Methodmethod, Object[] args){
System.out.println("---log advice ---");
Objectret=method.invoke(bean, args);
returnret;
      }
    });
  }
}
<beanid="userService"class="com.xxx.UserServiceImpl"/><beanid="proxy"class="com.xxx.ProxyBeanPostProcessor"/>

而在spring的源码中,是通过一个叫做AbstractAutoProxyCreator,这个类就是专门用来创建代理对象的,而他的本质就是实现了BeanPostProcessor接口,在方法中创建了代理对象。

image.png


image.png



好了关于动态代理的一些概念和底层实现我们就先介绍到这里.



目录
相关文章
|
6月前
|
监控 Java 开发者
Spring AOP动态代理
Spring AOP动态代理
101 1
|
6月前
|
运维 Java 程序员
Spring5深入浅出篇:Spring动态代理详解
# Spring动态代理详解 本文探讨了Spring中的MethodBeforeAdvice和MethodInterceptor在动态代理中的应用和差异。MethodBeforeAdvice在方法执行前执行额外功能,而MethodInterceptor则可在方法执行前后或抛出异常时运行额外逻辑。MethodInterceptor还能影响原始方法的返回值。
|
3月前
|
Java
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
这篇文章是Spring5框架的实战教程,深入讲解了AOP的基本概念、如何利用动态代理实现AOP,特别是通过JDK动态代理机制在不修改源代码的情况下为业务逻辑添加新功能,降低代码耦合度,并通过具体代码示例演示了JDK动态代理的实现过程。
Spring5入门到实战------9、AOP基本概念、底层原理、JDK动态代理实现
|
1月前
|
Java 数据安全/隐私保护 Spring
Spring进阶:初识动态代理
本文介绍了Spring框架中AOP切面编程的基础——动态代理。通过定义Vehicle接口及其实现类Car和Ship,展示了如何使用动态代理在不修改原代码的基础上增强功能。文章详细解释了动态代理的工作原理,包括通过`Proxy.newProxyInstance()`方法创建代理对象,以及`InvocationHandler`接口中的`invoke()`方法如何处理代理对象的方法调用。最后,通过一个测试类`TestVehicle`演示了动态代理的具体应用。
|
2月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
5月前
|
XML Java 数据格式
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
Spring5系列学习文章分享---第三篇(AOP概念+原理+动态代理+术语+Aspect+操作案例(注解与配置方式))
52 0
|
6月前
|
监控 Java 数据库连接
Spring高手之路17——动态代理的艺术与实践
本文深入分析了JDK和CGLIB两种动态代理技术在Spring框架中的应用。讨论了动态代理的基础概念,通过实例展示了如何实现和应用这两种方法,并比较了它们的性能差异及适用场景。进一步,探讨了在动态代理中实现熔断限流和日志监控的策略,以及如何利用动态代理优化Spring应用的设计和功能。
123 6
Spring高手之路17——动态代理的艺术与实践
|
5月前
|
Java Spring
深入解析Spring源码,揭示JDK动态代理的工作原理。
深入解析Spring源码,揭示JDK动态代理的工作原理。
61 0
|
6月前
|
Java 数据库 Spring
切面编程的艺术:Spring动态代理解析与实战
切面编程的艺术:Spring动态代理解析与实战
62 0
切面编程的艺术:Spring动态代理解析与实战
|
6月前
|
设计模式 运维 Java
Spring5深入浅出篇:Spring中静态代理与动态代理
Spring框架中的代理模式分为静态代理和动态代理。在JavaEE分层开发中,Service层最为重要,包含核心业务逻辑和额外功能。静态代理通过手动创建代理类来增加原始类的额外功能,但当代理类数量多时管理不便且不易于维护。动态代理则解决了这一问题,通过Spring的AOP(面向切面编程)实现,无需手动创建代理类,只需定义切点和增强(额外功能),在运行时动态生成代理对象,提高了代码的灵活性和可维护性。动态代理主要利用了JVM的字节码技术,在运行过程中创建代理类,执行完毕后随着虚拟机的结束而销毁,不会产生持久化的代理类。