【Spring】代理模式——动态代理

1、基本概念

  • 动态代理允许我们在运行时根据指定的接口动态地创建代理对象,这个代理对象与目标对象实现了相同的接口,因此可以完全替代目标对象执行相同的操作。
  • 通过动态代理,我们可以在不修改目标对象代码的情况下,为目标对象添加额外的功能或逻辑。
  • JDK动态代理和CGLIB动态代理是Java中两种常见的动态代理实现方式,它们各自有不同的特点和适用场景。

2、原理

  • 动态代理的实现原理主要基于Java的反射机制。
  • 在运行时,动态代理会根据指定的接口创建一个代理类,并在代理类中重写接口中的所有方法。
  • 当代理对象调用接口方法时,实际执行的是代理类中的对应方法。
  • 在代理类中,我们可以通过反射机制调用目标对象的方法,并在执行前后添加自己的逻辑。

3、应用场景

  • 动态代理在Spring框架中得到了广泛应用,主要用于实现AOP(面向切面编程)功能。
  • AOP是一种编程范式,用于处理系统中散布于各个模块之间的交叉关注点问题,如事务管理、日志记录、安全控制等。
  • 通过动态代理,Spring可以在运行时为目标对象创建代理对象,并在代理对象中织入切面逻辑,从而实现对这些交叉关注点问题的统一处理。

4、常见实现方式

4.1 JDK动态代理

4.1.1简介

  • JDK动态代理是Java标准库提供的一种动态代理实现方式,它基于Java的反射机制。
  • JDK动态代理只能代理实现了接口的类,通过动态生成代理类来实现对目标对象的代理。
  • 在JDK动态代理中,代理类是由Java运行时环境动态生成的,每个代理类都会实现与被代理对象相同的接口。
  • 通过使用Proxy、Method、InvocationHandler类库来完成动态代理
  • JDK动态代理的优点是简单易用,因为它是Java标准库的一部分,无需引入额外的依赖。

4.1.2代码示例

步骤1:先创建UserService接口

java 复制代码
public interface UserService {
void save();
void delete();
}

步骤2:创建一个接口的实现类UserServiceImpl(目标类对象)

java 复制代码
public class UserServiceImpl implements UserService {
@Override
public void save() {
System.out.println("主业务逻辑:增加用户管理");
}
@Override
public void delete() {
System.out.println("主业务逻辑:删除用户管理");
}
}

步骤3:创建动态代理(InvocationHandler接口的实现类)

java 复制代码
public class MyInvocationHandler implements InvocationHandler {
private Object obj;
public MyInvocationHandler(Object obj){
this.obj=obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws
Throwable {
        System.out.println("开始监控系统...");
long t1 = System.currentTimeMillis();//当前时间
try {
Thread.sleep((int) (Math.random() * 2000));
} catch (InterruptedException e) {
e.printStackTrace();
}
Object o = method.invoke(obj, args);
long t2 = System.currentTimeMillis();//当前时间
System.out.println("结束监控系统...");
System.out.println("一共耗费了" + (t2 - t1) + "毫秒");
//加日志处理
System.out.println(LocalDate.now() + "访问系统");
return o;
}
}

步骤4:使用Proxy,创建代理对象

java 复制代码
public class ProxyUtil {
public static Object getProxy(Object target, InvocationHandler handler)
{
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), handler);
}
}

步骤5:测试

java 复制代码
public static void main(String[] args) {
UserService service= new UserServiceImpl();
UserService proxy = (UserService) ProxyUtil.getProxy(service,
new MyInvocationHandler(service));
proxy.save();
System.out.println("------------------------------------");
proxy.delete();
}
}

4.2 CGLIB动态代理

4.2.1简介

  • CGLIB(Code Generation Library)是一个强大的、高性能的代码生成库,它可以扩展Java类和实现Java接口。
  • 与JDK动态代理不同,CGLIB动态代理是通过继承目标类来创建代理对象的,因此它可以代理没有实现接口的类。
  • CGLIB动态代理底层使用ASM(一个Java字节码操控和分析框架)来操作字节码生成新的类,为对象引入间接级别,以控制对象的访问。
  • CGLIB动态代理的优点在于它可以代理没有实现接口的类,提供了更多的灵活性。
  • CGLIB动态代理不能对final类及final方法进行代理。

4.2.2代码示例

步骤1:创建目标类

java 复制代码
public class AccountService {
public void save(){
System.out.println("保存账务管理业务");
}
public void pay(){
System.out.println("支持管理业务");
}
}

步骤2:编写增强类

java 复制代码
public class MyInterceptor implements MethodInterceptor {
private Object obj;
public MyInterceptor(Object obj) {
this.obj = obj;
}
@Override
public Object intercept(Object o, Method method, Object[] objects,
MethodProxy methodProxy) throws Throwable {
System.out.println("进入系统");
Object invoke = method.invoke(obj, objects);
System.out.println(LocalDate.now());
return invoke;
}
}

步骤3:测试

java 复制代码
public class Test {
public static void main(String[] args) {
AccountService service = new AccountService();
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(AccountService.class.getClassLoader());
enhancer.setSuperclass(AccountService.class);
enhancer.setCallback(new MyInterceptor(service));
AccountService accountService = (AccountService) enhancer.create();
accountService.save();
System.out.println("------------------------------");
accountService.pay();
}
}
相关推荐
毕设源码-朱学姐4 小时前
【开题答辩全过程】以 工厂能耗分析平台的设计与实现为例,包含答辩的问题和答案
java·vue.js
Spring AI学习5 小时前
Spring AI深度解析(9/50):可观测性与监控体系实战
java·人工智能·spring
java1234_小锋6 小时前
Spring IoC的实现机制是什么?
java·后端·spring
xqqxqxxq7 小时前
背单词软件技术笔记(V2.0扩展版)
java·笔记·python
消失的旧时光-19437 小时前
深入理解 Java 线程池(二):ThreadPoolExecutor 执行流程 + 运行状态 + ctl 原理全解析
java·开发语言
哈哈老师啊7 小时前
Springboot学生综合测评系统hxtne(程序+源码+数据库+调试部署+开发环境)带论文文档1万字以上,文末可获取,系统界面在最后面。
java·数据库·spring boot
4311媒体网7 小时前
帝国cms调用文章内容 二开基本操作
java·开发语言·php
zwxu_7 小时前
Nginx NIO对比Java NIO
java·nginx·nio
前端小端长8 小时前
Vue 中 keep-alive 组件的原理与实践详解
前端·vue.js·spring