- 浏览: 1597896 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
jsrgzhangzhiyong:
关于null值的转换还是感觉不太友好,就像 mapstruct ...
我也造了个轮子:BeanMapping(属性拷贝) -
he037:
a417930422 写道引用使用EPHEMERAL会引出一个 ...
基于zookeeper的分布式lock实现 -
seancheer:
qianshangding 写道首先节点启动后,尝试读取本地的 ...
zookeeper学习记录三(session,watcher,persit机制) -
雪夜归人:
您好,我想咨询一下,开源的canal都能支持mysql的哪些版 ...
Canal BinlogChange(mysql5.6) -
zhoudengyun:
copy 一份做记录,后续学习,请知悉
阿里巴巴开源项目: 基于mysql数据库binlog的增量订阅&消费
背景
最近在实施并行加载,遇到一个问题: 重复代理,或者说是两次cglib代理。
主要是并行加载技术本身是采用了cglib+拦截的技术进行控制,所以势必会要求进行一次代理配置那
1. 如果需要代理的原始对象已经是一个cglib代理后的对象,比如性能监控,日志记录等等。
2. 其他同事在做的自动路由,按需加载都会要求进行一次cglib代理
如何平衡多次代理的问题,就冒出来了。
思路
接近于spring的autoProxyCretor的一套机制,利用了BeanPostProcessor,就是在bean的生命周期上做点文章。
spring默认提供的几种auto-proxy:
- BeanNameAutoProxyCreator : 可以配置需要被进行auto-proxy的bean names列表,它控制的是需要代理的bean列表
- InfrastructureAdvisorAutoProxyCreator
- DefaultAdvisorAutoProxyCreator : 将对应匹配的advisor,自动添加到spring的bean。它控制的是advisor的匹配,所有的bean都会被自动代理
切入代码:
public Object postProcessBeforeInitialization(Object bean, String beanName) { // 不做处理 return bean; } public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { if (bean != null) { Object cacheKey = getCacheKey(bean.getClass(), beanName); return wrapIfNecessary(bean, beanName, cacheKey); } return bean; }
if (ProxyFactoryBean.class.isAssignableFrom(bean.getClass())) { ProxyFactoryBean proxyFactoryBean = (ProxyFactoryBean) bean; String[] orignInterceptorNames = getInterceptorFromProxyFactoryBean(proxyFactoryBean); String[] newInterceptorNames = new String[orignInterceptorNames.length + interceptorNames.length]; if (applyCommonInterceptorsFirst) {// 如果是true,则将Auto-proxy的拦截器定义到最前面 // 构造新的的拦截器列表 System.arraycopy(interceptorNames, 0, newInterceptorNames, 0, interceptorNames.length); System.arraycopy(orignInterceptorNames, 0, newInterceptorNames, interceptorNames.length, orignInterceptorNames.length); } else { System.arraycopy(orignInterceptorNames, 0, newInterceptorNames, 0, orignInterceptorNames.length); System.arraycopy(interceptorNames, 0, newInterceptorNames, orignInterceptorNames.length, interceptorNames.length); } // 重新设置新的inteceptorNames proxyFactoryBean.setInterceptorNames(newInterceptorNames); return proxyFactoryBean; } else { // 如果是单例,对应的代理bean对象为同一个 ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean(); proxyFactoryBean.setBeanFactory(beanFactory); proxyFactoryBean.setBeanClassLoader(proxyClassLoader); proxyFactoryBean.setInterceptorNames(interceptorNames); proxyFactoryBean.copyFrom(this); // 拷贝对应的一些Proxy config proxyFactoryBean.setTarget(bean); return proxyFactoryBean.getObject(); }
<!-- 多例测试 --> <bean id="asyncLoadTestServiceForCompsitePrototype" class="com.agapple.asyncload.domain.AsyncLoadTestServiceImpl" scope="prototype" /> <!-- 单例测试 --> <bean id="asyncLoadTestServiceForCompsiteSingleton" class="com.agapple.asyncload.domain.AsyncLoadTestServiceImpl" scope="singleton" /> <!-- 原本是ProxyFactoryBean --> <bean id="logInteceptor" class="com.agapple.asyncload.spring.LogInteceptor" /> <bean id="asyncLoadTestServiceForCompsiteFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean" scope="prototype"> <property name="interceptorNames"> <list> <value>logInteceptor</value> </list> </property> <property name="targetName" value="asyncLoadTestService" /> <property name="proxyTargetClass" value="true" /> <!-- 强制申明为cglib代理 --> </bean> <!-- 第一次融合代理 --> <bean class="com.agapple.asyncload.impl.spring.CompositeAutoProxyCreator"> <property name="beanNames"> <list> <value>asyncLoadTestServiceForCompsitePrototype</value> <value>asyncLoadTestServiceForCompsiteSingleton</value> <value>asyncLoadTestServiceForCompsiteFactoryBean</value> <!-- 代理的对象原本已经是一个proxyFactoryBean的final cglib--> </list> </property> <property name="interceptorNames"> <list> <value>asyncLoadInterceptor</value> </list> </property> </bean> <!-- 多次的代理会只作用于一个代理对象 --> <bean class="com.agapple.asyncload.impl.spring.CompositeAutoProxyCreator"> <property name="applyCommonInterceptorsFirst" value="true"/> <property name="beanNames"> <list> <value>asyncLoadTestServiceForCompsitePrototype</value> <value>asyncLoadTestServiceForCompsiteSingleton</value> <value>asyncLoadTestServiceForCompsiteFactoryBean</value> <!-- 代理的对象原本已经是一个proxyFactoryBean的final cglib--> </list> </property> <property name="interceptorNames"> <list> <value>logInteceptor</value> </list> </property> </bean>
代码
配置文件:https://code.google.com/p/asyncload/source/browse/trunk/src/test/resources/asyncload/applicationContext.xml,查找对应的Compsite
最后
在查找具体的解决方案是一个比较曲折的过程,基本上把ProxyFactoryBean机制,auto-proxy机制代码实现都看了一遍。
过程1 : 原先是寄希望于spring可以提供类似的一个global advisor的概念,每个ProxyFatoryBean除了自己配置的inteceptorNames的拦截器之外,还回从一些global的定义中获取一些大家公用的advisor。找了一圈发现没有,曾经的GlobalAdvisorAdapterRegistry给了我一些希望,最后发现是一个绝望的内容。
过程2:在看AutoProxyCreator那套机制时,其实它预留了一些扩展点,主要是根据bean name获取对应的auto-proxy信息。bean name到具体的bean的处理,因为是在BeanPostProcessor,处于getBean()生命周期的最后一步,如果此时进行this.beanFactory.getBean()就是一个死循环,此路不通,所以原先的auto-proxy相关的扩展点基本走不同。
过程3: 在2走不通后,一直在琢磨是否可以通过直接处理生成后的object,获取原始object对应的ProxyFactoryBean.getAdvsisor()方法。后来看了半天代码,发现也是条思路,因为proxyFactoryBean生成的proxy对象完全和ProxyFactoryBean无关,也就不会有getAdvisor()方法,因为生成的cglib代理或者jdk代理,cglib代理到还有对advised的引用持有,有办法通过反射获取。而jdk那个压根没则,所以有是一条思路。
过程4: 2,3都走不通了,今天在debug另一个问题时,发现BeanPostProcessor的相应callback方法中传递的bean object居然是原生的ProxyFactoryBean,也就是说未进行getObject()调用之前的原始对象。大喜,总于找到突破口,最后就是自己实现了一套auto-proxy机制,因为原先的扩展点不支持传递bean object对象。
最后只能说自己对spring的一些机制还不够了解,需要持续加强。发现去扩展spring的一些点,是学习spring最快的一种方式,找扩展点的过程是对spring的一个总体把握的过程
悟了3天的问题,总于有了解决方案,仅以此文几年一下我那3天死去的脑细胞!!
发表评论
-
yugong QuickStart
2016-03-05 01:52 0几点说明 a. 数据迁移的方案可参见设计文档,oracl ... -
阿里巴巴开源项目: 阿里巴巴去Oracle数据迁移同步工具
2016-03-05 18:29 6546背景 08年左右,阿里巴巴开始尝试MySQL的相关 ... -
愚公performance
2016-03-02 17:29 0性能测试 全量测试 场景1 (单主键, ... -
yugong AdminGuide
2016-03-02 16:40 0环境要求 操作系统 数据库 迁移方案 部署 ... -
Tddl_hint
2014-01-27 13:52 0背景 工作原理 Hint格式 direct模 ... -
tddl5分库规则
2014-01-26 14:41 0背景 工作原理 构建语法树 元数据 基于 ... -
tddl5优化器
2014-01-22 15:12 0背景 工作原理 构建语法树 元数据 抽象语 ... -
Canal BinlogChange(mariadb5/10)
2014-01-20 17:25 4627背景 先前开源了一个 ... -
asynload quickstart
2013-10-08 22:49 0几点说明: 1. asyncload是做为一个j ... -
网友文档贡献
2013-09-18 15:50 01. Otter源代码解析系列 链接:http://e ... -
Manager配置介绍
2013-09-16 13:00 0通道配置说明 多种同步方式配置 a. 单向同步 ... -
canal&otter FAQ
2013-09-05 17:30 0常见问题 1. canal和 ... -
阿里巴巴开源项目:分布式数据库同步系统otter(解决中美异地机房)
2013-08-22 16:48 40476项目背景 阿里巴巴B2B公司,因为业务的特性 ... -
Otter AdminGuide
2013-08-19 11:06 0几点说明 otter系统自带了manager,所以简化了一 ... -
Otter高可用性
2013-08-17 23:41 0基本需求 网络不可靠,异地机房尤为明显. man ... -
Otter数据一致性
2013-08-17 23:39 0技术选型分析 需要处理一致性的业务场景: 多地修改 ( ... -
Otter扩展性
2013-08-17 22:20 0扩展性定义 按照实现不同,可分为两类: 数据处理自定 ... -
Otter双向回环控制
2013-08-17 21:37 0基本需求 支持mysql/oracle的异构数据库的双 ... -
Otter调度模型
2013-08-17 20:13 0背景 在介绍调度模型之前,首先了解一下otter系统要解 ... -
Otter Manager介绍
2013-08-16 11:16 0背景 otter4.0发布至 ...
相关推荐
4. **错误处理**:当代理过程中发生错误时,`http-proxy-middleware` 提供了错误处理机制,可以捕获并处理这些错误,避免应用程序崩溃。 5. **浏览器同步**:对于前端开发环境,`http-proxy-middleware` 可以与 ...
本文将详细探讨InfluxDB的核心特性和Influx-proxy的功能,并结合"Influx-proxy-2.5.7-linux-amd64.tar.gz"这个压缩包文件,解析其在Linux AMD64平台上可能的部署与使用。 首先,InfluxDB以其高效的存储和查询机制而...
Sharding-Proxy 是一个数据库中间件,它扮演着数据库代理的角色,位于应用程序与真实数据库之间。其主要功能是实现数据分片逻辑,使得应用程序无需感知复杂的分片规则,即可透明地访问分片后的数据库。Sharding-...
`dma-proxy.c`、`dma-proxy-test.c`、`dma-proxy.h` 这些文件名暗示了它们在实现或测试dma-proxy的功能中起到的作用: 1. `dma-proxy.c`: 这通常是一个C语言源代码文件,其中包含了dma-proxy的主要实现逻辑。它可能...
node-https-proxy-agent, HTTPS端点的HTTP代理 `http.Agent` 实现 https-proxy-agent HTTPS的HTTP代理 http.Agent 实现 这个模块为连接到指定的HTTP或者HTTPS代理服务器提供了 http.Agent 实现,并且可以与内置的...
docker-letsencrypt-nginx-proxy-companion-examples, 结合 Docker gen和 letsencrypt Nginx 代理伙伴的示例 docker-letsencrypt-nginx-proxy-companion-examples这个库是使用 nginx代理插件, docker gen和 docker-...
aws-kube-proxy1.16.8版本示例文件
在Kubernetes环境中,传统的服务发现和网络代理方案是通过kube-proxy来实现的,它提供了iptables、ipvs等不同的工作模式。然而,随着云原生应用的发展,对网络性能、安全性和可观测性的需求日益增强,这催生了Cilium...
其中,`--proxy-backend-addresses` 指定的是主数据库的地址和端口,而 `--proxy-read-only-backend-addresses` 指定的是从数据库的信息。 5. **启动mysql-proxy**:通过上述命令启动mysql-proxy后,它将会根据...
java运行依赖jar包
browsermob-proxy-2.1.4,与selenium一起进行爬虫,获取network中的链接资源
MJ-PROXY-PLUS-3.8.6免授权,功能和商用版本相同,最新版本,由于MJ官网更新,老版本已无法使用MJ-PROXY-PLUS,安装方法和老版本一样,详细可参考MJ-PROXY-PLUS配置教程。 使用自己的MJ账号,支持GPT3.5自动翻译等。...
- `--proxy-address`: 设置代理服务监听的IP和端口,默认为本地的4040端口。 - `--proxy-read-only-backend-addresses`: 设置只读数据库服务器的地址,用于实现读写分离。 - `--proxy-backend-addresses`: 主...
`mysql-proxy-0.8.5-windows-x86-34bit` 是 MySQL Proxy 的一个特定版本,适用于32位Windows操作系统。 MySQL Proxy 的主要功能和优势包括: 1. **透明代理**:MySQL Proxy 可以悄无声息地插入到客户端和服务器...
`superagent-proxy`是基于流行的`superagent`库的一个扩展,它为`superagent`提供了代理支持,从而帮助开发者绕过跨域问题,实现更加灵活的数据请求。 ### 1. 超级代理superagent-proxy简介 `superagent-proxy`是`...
charles 解压就能用 charles-proxy-4.5.6-win64
gcr.io/kubebuilder/kube-rbac-proxy:v0.13.0 镜像
通过这种方式,我们可以利用Spring Boot和`ProxyServlet`实现反向代理,使得客户端无需关心后端微服务的具体部署情况,同时还能对所有服务的请求和响应进行集中管理,提高系统的可维护性和扩展性。在实际项目中,还...
php-http-proxy, 在基于workerman的PHP中,HTTP代理 php-http-proxy基于workerman的PHP编写的HTTP代理。启动。php start.php 启动 -d停止停止。php start.php 停止状态。php start.php 状态其他链接https