Spring5系列(八) | 静态代理和spring动态代理

简介: Spring5系列(八) | 静态代理和spring动态代理

从本篇文章开始我们就要开始研究spring的第二大特性AOP了,也就是面向切面编程。 在java开发过程中,我们把我们具体要实现的业务方法,可以称之为核心功能,比如注册,登陆,增删改查等,而除了额外功能以外,往往我们还需要一下额外功能。

什么是额外功能呢,他们本身不属于业务系统,可有可无,代码量小,如事务,日志和性能分析等。

那么我们在开发的时候,最好不要把这些额外功能和核心功能的代码写到一起,这样不利于维护。所以我们引入了代理模式。


一. 代理模式


代理模式是设计模式的一种,主要解决的问题就是以一种优雅的方式为上面所说的核心功能添加额外功能,并且不破坏核心功能的代码独立性。

代理设计模式: 通过代理类,为原始类(目标) 增加额外功能

名词解释: 很重要,一定要理解清楚,后面我们的动态代理和aop都会用到以下名词

  1. 目标类: 又称原始类

指的是业务类(核心功能),如业务运算,dao调用等

  1. 目标方法: 也称原始方法

目标类中的方法就是目标方法

  1. 额外功能: 也叫附加功能

日志,事务,性能等

代理模式开发的核心要素

代理类 = 目标类 + 附加功能 + 与原始类实现相同的接口


二. 静态代理


接下来我们通过一个静态代理的代码方式演示一下上面提到的代理模式。根据核心要素,我们需要有目标类,附加功能和 实现相同接口。

publicinterfaceUserService {
// 注册voidregister(Useruser);
// 登录booleanlogin(Stringname ,Stringpassword);
}
publicclassUserServiceImplimplementsUserService{
@Overridepublicvoidregister(Useruser){
System.out.println("用户注册");
    }  
@Overridepublicbooleanlogin(Stringname, Stringpassword){
System.out.println("用户登录");
    }
}
复制代码

上面的UserServiceImpl 就是我们的目标类,里边的两个方法就是我们的目标方法(也就是我们的核心功能)。现在我们要为这两个目标方法增加一个打印日志的额外功能。我们就可以通过代理模式实现,实现的方式,就是写一个代理类,让他和目标类实现相同的接口。

publicclassUserServiceProxyimplementsUserService{
privateUserServiceImpluserService=newUserServiceImpl();
@Overridepublicvoidregister(Useruser){
System.out.println("-----log------");
userService.register(user);
    }
@Overridepublicbooleanlogin(Stringname, Stringpassword){
System.out.println("------log------");
userService.login(name, password);
    }
}
复制代码

通过实现相同接口并持有目标类引用,我们就优雅的在不破坏原有类的基础上,为他们添加了额外功能。这就是静态代理的实现方式。但是静态代理也是存在一些弊端的

  1. 静态代理类文件过多,不利于项目管理(每为一个类添加额外功能就需要有一个代理类)
  2. 额外功能的维护性差,代理类中额外功能修改起来比较麻烦。

三. Spring动态代理

spring中也为我们提供了动态代理的实现。可以帮助我们为目标类添加额外功能。我们来看下如何实现。

3.1 引入依赖

<dependency><groupId>org.spring.framework</groupId><artifactId>spring-aop</artifactId><version>5.1.14.RELEASE</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>asprctjrt</artifactId><version>1.8.8</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>asprctjweaver</artifactId><version>1.8.3</version></dependency>

3.2 开发步骤

  1. 创建目标对象
publicclassUserServiceimplementsUserService{
@Overridepublicvoidregister(Useruser){
System.out.println("注册,,,,调用dao");
  }
@Overrridepublicbooleanlogin(Stringname, Stringpassword){
System.out.println("登录。。。。调用dao");
returntrue;
  }
}

  1. 装配bean
<beanid="userService"class = "com.xxx.UserServiceImpl"/>
  1. 提供额外功能

Spring为我们提供了一个MethodBeforeAdvice接口,额外功能写在该接口的实现方法中,会运行在原始方法之前

publicclassBeforeimplementsMethodBeforeAdvice{
@Overridepublicvoidbefore(Methodmethod, Object[] objects, Objecttarget){
System.out.println("proxy......");
  }
}

装配Bean

<beanid="before"class="com.xxx.Before"/>
  1. 定义切入点

切入点: 额外功能加入的位置

引入的目的:由程序员根据自己的需要决定额外功能加给哪个原始方法

简单测试: 给所有方法都作为切入点,都加入额外功能。

<aop:confg><aop:pointcutid="pc"expression="execution(* *(..))"/></aop:confg>
  1. 组装(额外功能和切入点的整合)

把切入点和额外功能进行整合。所有的方法

<aop:confg><aop:pointcutid="pc"expression="execution(* *(..))"/><aop:advisoradvice-ref="before"pointcut-ref="pc"/></aop:confg>

6.调用

获得spring工厂创建的动态搭理对象,并进行调用

注意:

  1. spring工厂通过原始对象的id值获得的是代理对象
  2. 获得代理对象后可以通过声明接口类型对代理对象进行接收
UserServiceuserService=(UserService)ctx.getBean("userService");// 代理对象userService.login();// 

打印结果:

proxy...

login...

3.3 动态代理细节分析


通过上面的方式,我们已经演示了如何通过Spring完成了一个动态代理的过程。 实现了将核心功能和额外功能分离开发,动态灵活组装的案例。其本质特点其实是和上面的静态代理的一样的,那么我们接来下来分析几个问题,加深一下我们对于动态代理的理解。


1. Spring创建动态代理的类在哪里?

我们在上面调用的时候,其实还是通过获取原始对象的方式来调用的,但其实此时的原始对象已经是一个代理对象了。

Spring框架运行时,会通过动态字节码技术,在JVM中创建的动态代理对象,运行在JVM内部,等程序结束后,会和jvm一起消失。

**这也是为什么叫做动态代理的原因,就是因为这个对象是动态生成出来的。不像静态代理我们必须自己创建。 **


2. 动态代理编程简化了代理的开发

我们上面为UserService中的方法,增加了一个额外功能(虽然只是打印了一句话),如果我们想给OrderService中也增加一个和UserService相同的额外功能,只需要把OrderService也配置到Spring的配置文件中即可,额外功能的代码都是可以复用的,无需额外配置。(主要是我们切入点的表达式是配置的所有方法都执行额外功能,如果想要指定部分方法执行,可以通过修改切入点表达式的方式实现,后面会详细讲解)

在额外功能不变的前提下,创建其他目标类的代理对象时,只需要执行目标对象即可。


3. 代理额外功能的可维护性增强了

想要修改额外功能,只需要执行新的before, 目标类无需修改。


目录
相关文章
|
2月前
|
Java 开发者 Spring
Spring AOP深度解析:探秘动态代理与增强逻辑
Spring框架中的AOP(Aspect-Oriented Programming,面向切面编程)功能为开发者提供了一种强大的工具,用以将横切关注点(如日志、事务管理等)与业务逻辑分离。本文将深入探讨Spring AOP的底层原理,包括动态代理机制和增强逻辑的实现。
49 4
|
3月前
|
存储 缓存 Java
Spring高手之路23——AOP触发机制与代理逻辑的执行
本篇文章深入解析了Spring AOP代理的触发机制和执行流程,从源码角度详细讲解了Bean如何被AOP代理,包括代理对象的创建、配置与执行逻辑,帮助读者全面掌握Spring AOP的核心技术。
57 3
Spring高手之路23——AOP触发机制与代理逻辑的执行
|
3月前
|
Java 数据安全/隐私保护 Spring
Spring进阶:初识动态代理
本文介绍了Spring框架中AOP切面编程的基础——动态代理。通过定义Vehicle接口及其实现类Car和Ship,展示了如何使用动态代理在不修改原代码的基础上增强功能。文章详细解释了动态代理的工作原理,包括通过`Proxy.newProxyInstance()`方法创建代理对象,以及`InvocationHandler`接口中的`invoke()`方法如何处理代理对象的方法调用。最后,通过一个测试类`TestVehicle`演示了动态代理的具体应用。
|
4月前
|
设计模式 Java 测试技术
spring复习04,静态代理动态代理,AOP
这篇文章讲解了Java代理模式的相关知识,包括静态代理和动态代理(JDK动态代理和CGLIB),以及AOP(面向切面编程)的概念和在Spring框架中的应用。文章还提供了详细的示例代码,演示了如何使用Spring AOP进行方法增强和代理对象的创建。
spring复习04,静态代理动态代理,AOP
|
4月前
|
设计模式 Java Spring
spring源码设计模式分析-代理设计模式(二)
spring源码设计模式分析-代理设计模式(二)
|
5月前
|
缓存 安全 Java
Spring AOP 中两种代理类型的限制
【8月更文挑战第22天】
44 0
|
5月前
|
Java Spring
|
5月前
|
安全 Java 开发者
|
Java Spring
Spring02——实现动态代理拦截器
实现动态代理的2种方式 第一种:  用JDK提供的Proxy代理类 和 InvocationHandler调用处理类  配合起来可以拦截一个接口下面的实现类,拦截它的方法,这样可以在它之前做点事情之后做点事情都可以。
|
3月前
|
人工智能 自然语言处理 前端开发
SpringBoot + 通义千问 + 自定义React组件:支持EventStream数据解析的技术实践
【10月更文挑战第7天】在现代Web开发中,集成多种技术栈以实现复杂的功能需求已成为常态。本文将详细介绍如何使用SpringBoot作为后端框架,结合阿里巴巴的通义千问(一个强大的自然语言处理服务),并通过自定义React组件来支持服务器发送事件(SSE, Server-Sent Events)的EventStream数据解析。这一组合不仅能够实现高效的实时通信,还能利用AI技术提升用户体验。
256 2