Spring之Aop代理对象的产生(二)
目录
- 1. 前言
- 2. `Aop` 代理对象的产生
- 2.1. `applyBeanPostProcessorsAfterInitialization()`
- 2.1.1. `postProcessAfterInitialization()`
- 2.1.2. `postProcessAfterInitialization()` 的具体实现
- 2.1.2.1. `wrapIfNecessary()`
- 2.1.2.1.1. `createProxy()` 创建代理对象
- 2.1.2.1.1.1. `getProxy()`
- 2.1.2.1.1.2. `createAopProxy()`
- 2.1.2.1.1.3. `createAopProxy()`
- 2.1.2.1.1.4. 使用 `JDK` 动态代理生成代理对象
- `Aop` 代理对象产生流程步骤
1. 前言
我们接着 Spring Aop代理对象的产生(一) 来分析 Aop
代理对象的产生,上篇文章解读到了 AbstractAutowireCapableBeanFactory
的 initializeBean()
,我们继续
2. Aop
代理对象的产生
initializeBean()
方法重点关注 applyBeanPostProcessorsAfterInitialization
方法
Aop
的原理和实现就在其中,来到了AbstractAutowireCapableBeanFactory
的applyBeanPostProcessorsAfterInitialization
方法
2.1. applyBeanPostProcessorsAfterInitialization()
@Override
public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)throws BeansException {// 初始化返回结果为existingBeanObject result = existingBean;// 遍历该工厂创建的所有实现了 BeanPostProcessors 接口的列表的 beanfor (BeanPostProcessor processor : getBeanPostProcessors()) {// 回调BeanPostProcessor#postProcessAfterInitialization来对现有的bean实例进行包装Object current = processor.postProcessAfterInitialization(result, beanName);// 一般processor对不感兴趣的bean会回调直接返回result,使其能继续回调后续的BeanPostProcessor// 但有些processor会返回null来中断其后续的BeanPostProcessorif (current == null) {// 直接返回result,中断其后续的BeanPostProcessor处理return result;}result = current;}return result;
}
2.1.1. postProcessAfterInitialization()
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {return bean;
}
查看 getBeanPostProcessors()
方法
查看 AnnotationAwareAspectJAutoProxyCreator
的类层次结构(查看),可知,其实现了 beanPostProcessor
接口,实现类为 AbstractAutoProxyCreator
2.1.2. postProcessAfterInitialization()
的具体实现
主要看这个方法,在 bean
初始化之后对生产出的 bean
进行包装代理
@Override
public Object postProcessAfterInitialization(@Nullable Object bean, String beanName) {if (bean != null) {// 如果是普通bean,则返回beanName,如果是FactoryBean,则返回加上前缀&的&beanNameObject cacheKey = getCacheKey(bean.getClass(), beanName);// earlyProxyReferences中缓存的是已经创建好的代理对象if (!this.earlyProxyReferences.contains(cacheKey)) {return wrapIfNecessary(bean, beanName, cacheKey);}}return bean;
}
2.1.2.1. wrapIfNecessary()
判断 bean
是否需要被代理
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {// 也是看看有没有缓存,有缓存对象就直接返回了if (StringUtils.hasLength(beanName) && this.targetSourcedBeans.contains(beanName)) {return bean;}// 如果该bean不需要被代理,则直接返回原始的bean对象if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {return bean;}if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;}// 获取 bean 的 advices(通知或增强器)Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);if (specificInterceptors != DO_NOT_PROXY) {// 加入缓存中this.advisedBeans.put(cacheKey, Boolean.TRUE);// 通过createProxy方法创建代理对象Object proxy = createProxy(bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));this.proxyTypes.put(cacheKey, proxy.getClass());return proxy;}this.advisedBeans.put(cacheKey, Boolean.FALSE);return bean;
}
2.1.2.1.1. createProxy()
创建代理对象
类 AbstractAutoProxyCreator
的 createProxy()
创建代理对象
protected Object createProxy(Class<?> beanClass, @Nullable String beanName,@Nullable Object[] specificInterceptors, TargetSource targetSource) {if (this.beanFactory instanceof ConfigurableListableBeanFactory) {AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);}// 创建一个ProxyFactoryProxyFactory proxyFactory = new ProxyFactory();// 初始化ProxyFactoryproxyFactory.copyFrom(this);// 确定代理方式是使用JDK代理,还是使用Cglibif (!proxyFactory.isProxyTargetClass()) {if (shouldProxyTargetClass(beanClass, beanName)) {// proxyTargetClass默认是false使用JDK代理,反之使用CglibproxyFactory.setProxyTargetClass(true);}else {evaluateProxyInterfaces(beanClass, proxyFactory);}}// 就是把specificInterceptors中的advisors和commonInterceptors中的拦截器合并(如果有的话)在一起封装成Advisor返回Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);// 将advisors(本案例的四个通知)和源对象设置到proxyFactory上proxyFactory.addAdvisors(advisors);proxyFactory.setTargetSource(targetSource);customizeProxyFactory(proxyFactory);proxyFactory.setFrozen(this.freezeProxy);if (advisorsPreFiltered()) {proxyFactory.setPreFiltered(true);}// 真正去创建代理对象了return proxyFactory.getProxy(getProxyClassLoader());
}
2.1.2.1.1.1. getProxy()
在类 ProxyFactory
中
public Object getProxy(@Nullable ClassLoader classLoader) {return createAopProxy().getProxy(classLoader);
}
2.1.2.1.1.2. createAopProxy()
继续 ProxyCreatorSupport
类中的 createAopProxy()
方法
protected final synchronized AopProxy createAopProxy() {if (!this.active) {activate();}return getAopProxyFactory().createAopProxy(this);
}
2.1.2.1.1.3. createAopProxy()
获得被代理类的类型,以确定代理的方式
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {// 获得被代理类的类型,以确定代理的方式Class<?> targetClass = config.getTargetClass();// 如果对象类型是接口,或者是JAVA的动态代理类,那么就调用JDK的动态代理方法生成代理对象if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {return new JdkDynamicAopProxy(config);}// 否则使用CGLIB生成代理对象return new ObjenesisCglibAopProxy(config);}else {return new JdkDynamicAopProxy(config);}
}
2.1.2.1.1.4. 使用 JDK
动态代理生成代理对象
JdkDynamicAopProxy
类实现了 InvocationHandler
接口,则必定有 invoke
方法,来被调用,也就是用户调用 bean
相关方法时,此 invoke()
被真正调用
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializablepublic Object getProxy(ClassLoader classLoader) {if (logger.isDebugEnabled()) {logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());}Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);// JDK 动态代理的标准用法return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
Aop
代理对象产生流程步骤
- 在
IOC
容器启动初始化时,首先会去一级缓存singletonObjects
中去获取(肯定没有) - 在根据当前
bean
的具体作用域,去初始化bean
- 在做完
bean
的一些校验之后,会进行bean
的实例化,即调用createBeanInstance()
方法 - 如果存在
bean
的循环依赖的情况,会将当前已实例化的bean put
进三级缓存singletonFactories
中 - 接着会进行
bean
的相关属性填充,即调用populateBean()
方法,注意此时还并没有产生代理对象 - 再接着会进行
bean
的初始化操作,即调用initializeBean()
方法 - 遍历该工厂创建的所有实现了
BeanPostProcessors
接口的列表的bean
- 判断这些
bean
需不需要被代理,如果不需要,则直接返回原始单例bean
,此时单例bean
已完成向IOC
容器的注册工作 - 如果需要,再确定代理方式是使用
JDK
代理,还是使用Cglib
- 获取当前
bean
的所有advices
(可理解为通知或增强器
) - 根据代理方式,正式的去创建代理对象,此时代理对象就产生了
参考:https://blog.csdn.net/wuyuwei/article/details/88357698
Spring之Aop代理对象的产生(二)相关推荐
- 大数据WEB阶段Spring框架 AOP面向切面编程(二)
Spring AOP面向切面编程(二) 一.切入点的execution表达式 execution的表达形式: execution(修饰符? 返回值类型 所在包类? 方法名(参数列表) 异常?) ?表示 ...
- Spring之AOP代理模式
代理模式分类: 静态代理 动态代理 你要租房,不找房东,找中介,中介是房东的代理. 1.1静态代理 角色分析 抽象角色:一般会使用接口或者抽象类来解决 /*** @author LongXi* @cr ...
- 【java】通过spring通过AOP实现日志打印(二)
本人菜鸡一个,上一篇文章说了说自己对AOP的理解,并留下了一个用spring注解实现AOP的坑,本文就来填填这个坑 该系列暂时有两篇文章: [java]java中的AOP思想(一):https://b ...
- Spring AOP 源码分析 - 创建代理对象
1.简介 在上一篇文章中,我分析了 Spring 是如何为目标 bean 筛选合适的通知器的.现在通知器选好了,接下来就要通过代理的方式将通知器(Advisor)所持有的通知(Advice)织入到 b ...
- Spring AOP源码(2)—AspectJAwareAdvisorAutoProxyCreator创建代理对象【两万字】
基于最新Spring 5.x,介绍了Spring AOP中的AspectJAwareAdvisorAutoProxyCreator自动代理创建者的工作流程,对于创建代理对象的源码进行了深度分析! ...
- spring事务--使用aop事务代理对象调用方法示例
第一种获取aop代理对象的方式: 第二种方式获取aop代理对象:
- 动态代理以及对应Spring中AOP源码分析
AOP(面向切面编程)在Spring中是被广泛应用的(例如日志,事务,权限等),而它的基本原理便是动态代理. 我们知道动态代理有两种:基于JDK的动态代理以及基于CGlib动态代理.以下是两种动态代理 ...
- Spring AOP源码解析(二)—— AOP引入
目录 配置类 AopAutoConfiguration AspectJAutoProxyingConfiguration ClassProxyingConfiguration @EnableAspec ...
- spring的aop的动态代理机制都有哪些_Spring学习(4):Spring AOP
Spring AOP说明 AOP(Aspect Oriented Pragraming)面向切面编程,AOP采用横向抽取机制,取代了传统纵向继承体系的重复性代码(性能监视.事务管理.安全检查.缓存). ...
- Spring通知类型及使用ProxyFactoryBean创建AOP代理
Spring 通知类型 通知(Advice)其实就是对目标切入点进行增强的内容,Spring AOP 为通知(Advice)提供了 org.aopalliance.aop.Advice 接口. Spr ...
最新文章
- linux的变量用法
- 汇编语言-环境安装及各个寄存器介绍
- 虚数有物理意义吗?潘建伟范靖云团队最新量子力学研究同日登顶刊,引发基础数理热议...
- 【Linux C 多线程编程】互斥锁与条件变量
- POJ 1172 DFS
- 数据结构与算法 —— 链表linked list(01)
- android 和ios 混合式开发环境安装
- JavaScript中的.trim()无法在IE中运行
- shell中引号的应用
- 基于auto.js的网课自动签到软件以及facerig控制摄像头内容及auto.js新手教学
- NLP - AIML
- c语言蝴蝶图案代码,通达信指标公式,临界点蝴蝶图案出现,暴涨趋势出现(附源码)...
- CNVD-2022-10270/CNVD-2022-03672 向日葵RCE复现
- 基于vue的电商后台管理系统
- C语言基础and进阶——猜拳游戏(6个版本)
- 点击pv转化率_互联网中一些常用指标(PV、UV、蹦失率、转换率、退出率)
- 行测 加强题型 加强论证
- 中国天网系统有多牛叉?BBC 记者体验了一把
- 软件构造实验一问题解决方法及经验教训
- 汇编语言 贪吃蛇/鱼/变色/时间周期
热门文章
- 搜索算法(DFS,BFS等)
- python给每个key添加数据_一文看懂Python collections模块的高效数据类型
- TextView用法及实例
- Pgsql登录连接失败原因及解决方法
- 装tensorflow未果
- 计算机组成原理完整学习笔记(二):系统总线
- 小红帽系统进入oracle,11G RAC 安装在红帽6上,grid跑root.sh报错
- 西门子S7系列中间人攻击:防御和流量异常检测(三)
- 快速突破面试算法之排序篇
- android手机和荣耀哪个版本好,【求测评】荣耀v40轻奢版与荣耀X10哪款更好?图文爆料分析...