当前位置: 首页 > news >正文

后端:Spring AOP原理--动态代理

文章目录

    • 1. Spring AOP底层原理
    • 2. 代理模式
    • 3. 静态代理
    • 4. 动态代理
      • 4.1 jdk 实现动态代理
      • 4.2 cglib 实现动态代理
      • 4.3 jdk、cglib动态代理两者的区别

1. Spring AOP底层原理

  • 创建容器 new applicationContext();
  • Spring把所有的Bean进行创建,进行依赖注入;
  • ioc.getBean(UserService.class)此时获取得到Bean并不是原本的UserService类,而是通过动态代理生成一个代理类,这个代理类继承自UserService类。

在这里插入图片描述

2. 代理模式

代理模式是一种比较好的设计模式;

  • 使用代理对象来增强目标对象(target object),这样就可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能;
  • 将核心业务代码和非核心的公共代码分离解耦,提高代码的可维护性,让被代理类专注业务降低代码复杂度。
    • 被代理类专注业务;
    • 代理类非核心的公共代码;

通常使用代理实现比如拦截器、事务控制,还有测试框架 mock、用户鉴权、日志、全局异常处理等。

3. 静态代理

代理类:

package com.lize.demo.aop.static1;public class CeoProxy extends Ceo{@Overridepublic void meeting(String name) {if(name.equals("张三")){super.meeting(name);}else{System.out.println("登记:"+name);}}
}

被代理类:

package com.lize.demo.aop.static1;public class Ceo {public void meeting(String name){System.out.println("接见客户:"+name);}
}

测试:

package com.lize.demo.aop.static1;import org.junit.jupiter.api.Test;
public class TestProxy {@Testpublic void test(){Ceo ceo = new CeoProxy();ceo.meeting("张三");ceo.meeting("李四");}
}

运行结果:
在这里插入图片描述

使用静态代理的弊端:一个代理类只能代理一个类型。

4. 动态代理

4.1 jdk 实现动态代理

jdk自带的,不需要额外导入其他依赖;
Proxy类中使用频率最高的方法是:newProxyInstance(),Proxy这个方法主要用来生成一个代理对象。

public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h
)

三个参数分别表示的意思是:

  • loader:类加载器,用于加载代理对象,传入被代理类的类加载器;
  • interfaces:被代理类实现的一些接口;被代理的类需要实现接口;
  • h:实现了InvocationHandler接口的对象;
package com.lize.demo.aop.autoProxy;public interface IUserService {void add();
}
package com.lize.demo.aop.autoProxy;// 被代理的类
public class UserService implements IUserService{@Overridepublic void add() {System.out.println("增加。。。");}
}
package com.lize.demo.aop.autoProxy;import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class MyHandler implements InvocationHandler {private Object target;public MyHandler(Object target){this.target = target;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("前置通知");// args 传递过来的参数Object res = method.invoke(target, args);System.out.println("后置通知");return res;}}
package com.lize.demo.aop.autoProxy;import org.junit.jupiter.api.Test;import java.lang.reflect.Proxy;public class TestProxy {@Testpublic void test(){IUserService userService = (IUserService) Proxy.newProxyInstance(UserService.class.getClassLoader(),UserService.class.getInterfaces(),new MyHandler(new UserService()));userService.add();System.out.println(userService.getClass());}
}

运行结果:
在这里插入图片描述

4.2 cglib 实现动态代理

package com.lize.demo.aop.autoProxy2;
// 被代理的类
public class UserService {public void add() {System.out.println("增加。。。");}
}
package com.lize.demo.aop.autoProxy2;import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;// 做增强处理
public class MyCallback implements MethodInterceptor {private Object target;public MyCallback(Object target) {this.target = target;}@Overridepublic Object intercept(Object o, Method method, Object[] args, MethodProxy proxy) throws Throwable {System.out.println("前置通知");Object res = proxy.invoke(target, args);System.out.println("后置通知");return res;}
}
package com.lize.demo.aop.autoProxy2;import org.junit.jupiter.api.Test;
import org.springframework.cglib.proxy.Enhancer;public class TestProxy {@Testpublic void test(){Enhancer enhancer = new Enhancer();// 设置被代理的类enhancer.setSuperclass(UserService.class);enhancer.setCallback(new MyCallback(new UserService()));UserService userService = (UserService) enhancer.create();// 代理的类userService.add();System.out.println(userService.getClass());}
}

在这里插入图片描述

4.3 jdk、cglib动态代理两者的区别

  • jdk动态代理只能代理实现了接口的类;而cglib可以代理未实现任何接口的类;
  • cglib动态代理是通过生成一个被代理类的子类来拦截被代理类的方法调用,因此不能代理声明为finnal类型的类和方法;
  • 在Spring中默认使用jdk动态代理,判断目标类是否实现了接口,如果实现了接口使用jdk动态代理,否则使用cglib;在Spring Boot中默认使用的是cglib动态代理。

在Spring中,如果想修改动态代理方式,可以通过注解的方式进行修改。

@EnableAspectJAutoProxy(proxyTargetClass = true) // cglib
@EnableAspectJAutoProxy(proxyTargetClass = false) // jdk

在Spring Boot中,如果想修改动态代理方式,可以通过在配置文件application.properties中添加配置即可。

spring.aop.proxy-target-class=false

http://www.mrgr.cn/news/75308.html

相关文章:

  • 【多线程】伪共享的概念
  • 大语言模型理论基础
  • Hbase Shell
  • Mysql数据库里的SSH连接
  • XXL JOB DockerCompose部署
  • 基于yolov8、yolov5的番茄成熟度检测识别系统(含UI界面、训练好的模型、Python代码、数据集)
  • windows C#-查询表达式基础(三)
  • datawhale2411组队学习之模型压缩技术1:模型剪枝(上)
  • 科研绘图系列:R语言极坐标柱状图(barplot)
  • pgAdmin简单介绍
  • 数据结构-二叉搜索树(Java语言)
  • 基于8.0 Update 3b 的ESXi-Arm Fling
  • Docker与Podman全面比较
  • 蓝队知识浅谈(下)
  • 算法学习blog:day2 继续记日记
  • 内网穿透任意TCP端口,高并发多线程,让家庭电脑秒变服务器
  • 不安全 Rust
  • PostgreSQL物化视图详解
  • 陆军应恢复连排班建制
  • IPv6基础知识
  • 【数据分享】空间天气公报(2004-2021)(又名太阳数据活动公报) PDF
  • 跨域请求解决的核心
  • Rust 布尔类型
  • Kubernetes 中的存储探讨:PV、PVC 体系与本地持久化卷
  • PGMP练-DAY24
  • 力扣经典面试题