spring boot 动态代理
springboot团队之所以默认的代理模式设置成cglib代理,看看spring的官方团队是怎么解释的
This was changed in 1.4 (see https://github.com/spring-projects/spring-boot/issues/5423). We’ve generally found cglib proxies less likely to cause unexpected cast exceptions.
他们认为使用cglib更不容易出现转换错误
整体逻辑
先捋一下整体逻辑哈
代码演示:
interface IUserService{void getUser();
}
class UserServiceImpl implements IUserService{@Overridepublic void getUser() {System.out.println("usersevice的getUser方法");}
}
jdk动态代理
通过上面的图,在bean后置处理器的时候拿到当前的bean对象然后进行代理,最终返回代理对象;
//创建jdk代理的方法
/*** 第一种 jDk*/public static Object createJdkProxy(Object currentObj){return Proxy.newProxyInstance(SpringProxyDemo.class.getClassLoader(),currentObj.getClass().getInterfaces(),new Invoke(currentObj));}
handler 在方法前后需要增强的功能 ;
class Invoke implements InvocationHandler {private Object o;//真实的对象public Invoke(Object object){this.o = object;}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("方法前后打印日志:--------before");Object invoke = method.invoke(o, args); //执行对象的方法System.out.println("方法前后打印日志--------after");return invoke;}
}
模拟一下:
通过反射创建对象 : userService
aop增强打印日志: userService对象传入handler里面 ,该对象才是真正执行方法的对象,返回代理对象
进行方法调用
public static void main(String[] args) throws Exception{//1.这里类似于spring,简写哈:Spring - BeanDefine 根据里面的class信息进行反射创建对象Class<UserServiceImpl> userServiceClass = UserServiceImpl.class;UserServiceImpl userService = userServiceClass.newInstance();//这里相当于spring的bean对象,现在要在service方法前后增加日志,所以要用aop, 调用bean的后置处理器//创建代理对象 - 并返回,此时bean工厂里面的实例就是该代理对象IUserService userServiceProxy = (IUserService)createJdkProxy(userService);//调用方法userServiceProxy.getUser();}
看一下执行结果:
CGLB:
通过上面的图,在bean后置处理器的时候拿到当前的bean对象然后进行代理,最终返回代理对象;
class Inteceptor implements MethodInterceptor{private Object obj;public Inteceptor(Object object){this.obj = object;}@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("CGLB-方法前后打印日志:--------before");Object invoke = methodProxy.invoke(obj, objects); //执行对象的方法System.out.println("CGLB-方法前后打印日志--------after");return invoke;}
}
public static Object createCGLBProxy(Object currentObj){Enhancer enhancer = new Enhancer();// 设置enhancer对象的父类enhancer.setSuperclass(currentObj.getClass());// 设置enhancer的回调对象enhancer.setCallback(new Inteceptor(currentObj));// 创建代理对象return enhancer.create();}
public static void main(String[] args) throws Exception{//1.这里类似于spring,简写哈:Spring - BeanDefine 根据里面的class信息进行反射创建对象Class<UserServiceImpl> userServiceClass = UserServiceImpl.class;UserServiceImpl userService = userServiceClass.newInstance();//这里已经创建对象了,现在要在service方法前后增加日志,所以要用aop, 调用bean的后置处理器//创建代理对象 - 并返回,此时bean工厂里面的实例就是该代理对象UserServiceImpl cglbProxy = (UserServiceImpl)createCGLBProxy(userService);cglbProxy.getUser();}
容易出现转换错误
原因: jdk动态生成的代理类, 是实现了接口,所以返回的类型是我们实现类的接口类型,如果我们在日常使用spring中,使用的是实现类的类型的话就会报错,如下:
看下面的例子可以看到,我使用的是jdk代理,custDeadLineWarnService创建了代理对象,返回的是
custDeadLineWarnService实现的接口类型
所以我们如果直接写CustDeadLineWarnServiceImpl就会报错:该类型不能转为接口类型
CGLB:
而 CGLIB 就不存在这个问题。因为 CGLIB 是通过继承生成子类来实现的,代理对象无论是赋值给接口还是实现类这两者都是代理对象的父类
spring boot 动态代理相关推荐
- Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题
Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代理的问题 参考文章: (1)Spring AOP动态代理实现,解决Spring Boot中无法正常启用JDK动态代 ...
- spring的动态代理,碰到了一个类型转换的问题:java.lang.ClassCastException: com.sun.proxy.$Proxy16 cannot be cast to com.
spring的动态代理,碰到了一个类型转换的问题: java.lang.ClassCastException: com.sun.proxy.$Proxy16 cannot be cast to com ...
- spring boot 动态切换数据源实现多租户开发
之前的文章有介绍过spring boot 动态切换数据源spring boot 动态切换数据源(数据源信息从数据库中读取)_lgq2016的博客-CSDN博客,今天简单介绍一下动态数据源切换实战,主要 ...
- Spring Boot 动态数据源(多数据源自己主动切换)
本文实现案例场景: 某系统除了须要从自己的主要数据库上读取和管理数据外.另一部分业务涉及到其它多个数据库,要求能够在不论什么方法上能够灵活指定详细要操作的数据库. 为了在开发中以最简单的方法使用,本文 ...
- Spring Boot 动态数据源(Spring 注解数据源)
本文实现案例场景: 某系统除了需要从自己的主要数据库上读取和管理数据外,还有一部分业务涉及到其他多个数据库,要求可以在任何方法上可以灵活指定具体要操作的数据库. 为了在开发中以最简单的方法使用,本文基 ...
- Spring CGLlB动态代理
JDK 动态代理使用起来非常简单,但是有一定的局限性,这是因为 JDK 动态代理必须要实现一个或多个接口,如果不希望实现接口,则可以使用 CGLIB 代理. CGLIB(Code Generation ...
- Spring JDK动态代理
JDK 动态代理是通过 JDK 中的 java.lang.reflect.Proxy 类实现的.下面通过具体的案例演示 JDK 动态代理的使用. 1. 创建项目 在 MyEclipse 中创建一个名称 ...
- Spring Boot 动态修改定时任务cron参数
动态修改定时任务cron参数 不需要重启应用就可以动态的改变Cron表达式的值不能使用@Scheduled(cron = "${jobs.cron}")实现 动态定时任务类Dyna ...
- Spring AOP动态代理
导入依赖: <dependency><groupId>org.springframework</groupId><artifactId>spring-a ...
- Spring的动态代理原理
Spring动态代理原理 Spring动态代理有两种:CGLIB动态代理和JDK动态代理. JDK动态代理可以代理接口,不能代理没有实现接口的类:而CGLIB通过字节码技术可以动态生成被代理类的子类, ...
最新文章
- python升级版本命令-pythonpip命令版本过低问题版本升级问题
- C/C++程序基础 (九)排序算法简述
- STM32 KEIL 串口打印printf使用详解
- 【c++手记】句柄类智能指针
- python 函数前有一个下划线_【Python】怎么写好一个 Python 函数?
- 从Docker 到Jenkins 到Ansible的部署经验 1
- 12 组合与继承、CSS Module
- 鸟哥学习笔记---网络驱动器设备iSCSI
- nginx fastcgi python_Nginx + webpy 和FastCGI搭建webpy环境
- 【渝粤题库】陕西师范大学200991教育统计学作业(高起本)
- Mac文本操作实用技巧,快速提升你的工作效率!
- 【直播预告】腾讯广告实时策略数据框架建设
- [第五组] 典型用户 +用例+功能说明书+技术说明书 2017.07.25版
- html武侠文字游戏源码,执剑行!最新武侠文字mud游戏
- 解决aspx页面中关键词(keywords)和描述(descript)不显示问题
- Android集成环信IM,实现聊天置顶功能
- 展翅翱翔之时 (はばたきのとき)
- 某音漂亮小姐姐视频合集一键下载,想看就看!
- 计算机专业实习目的与意义,计算机专业实习目的及意义
- 彩票走势图xcode源码