在应用中,当我们进行集成测试或者单元测试的时候,有些中间件因为涉及到了外部请求,所以想把测试拉起来,显得比较困难,但是由于spring中,我们可以对bean进行替换,所以这个事儿变得简单了。
我们需要基于BeanDefinitionRegistryPostProcessor 和 PriorityOrdered两个类,来对bean进行处理:
package org.tiny.upgrade.plugin.mock.mockbiz.mockbiz;//package com.jd.migration.service.replace; import com.alibaba.fastjson.JSON; import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanDefinition; import org.springframework.beans.factory.config.ConfigurableBeanFactory; import org.springframework.beans.factory.config.ConfigurableListableBeanFactory; import org.springframework.beans.factory.support.BeanDefinitionBuilder; import org.springframework.beans.factory.support.BeanDefinitionRegistry; import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor; import org.springframework.beans.factory.support.RootBeanDefinition; import org.springframework.core.Ordered; import org.springframework.core.PriorityOrdered; import org.springframework.stereotype.Component; //@Component public class BeanReplace implements BeanDefinitionRegistryPostProcessor, PriorityOrdered { @Override public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException { System.out.println(JSON.toJSONString("xxxx"+beanDefinitionRegistry)); for (String beanDefinitionName : beanDefinitionRegistry.getBeanDefinitionNames()) { String beanName = "redisClient"; if(beanDefinitionName.equals(beanName)){ //移除原有bean beanDefinitionRegistry.removeBeanDefinition(beanName); System.out.println("注册新的mock beanName:"+beanName); RootBeanDefinition beanDefinition = (RootBeanDefinition) BeanDefinitionBuilder.rootBeanDefinition(BeanFactory.class) .setFactoryMethod("mock") .addConstructorArgValue(loadClass("org.tiny.cli.Cluster", beanDefinitionRegistry)) .setLazyInit(false) .setScope(BeanDefinition.SCOPE_SINGLETON) .getBeanDefinition(); beanDefinition.setTargetType(loadClass("org.tiny.cli.Cluster", beanDefinitionRegistry)); //注入mock的bean beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition); } } } @Override public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException { } @Override public int getOrder() { return Ordered.LOWEST_PRECEDENCE - 10000; } public Class loadClass(String className, BeanDefinitionRegistry beanDefinitionRegistry) throws RuntimeException { ConfigurableBeanFactory cbf = (ConfigurableBeanFactory) beanDefinitionRegistry; Class clazz = tryLoadClass(cbf.getBeanClassLoader(), className); if (clazz != null) { return clazz; } return tryLoadClass(cbf.getTempClassLoader(), className); } private Class tryLoadClass(ClassLoader classLoader, String interfaceClassName) { try { return classLoader.loadClass(interfaceClassName); } catch (ClassNotFoundException e) { // 忽略 } return null; } }
从上面流程中,我们可以看到,我们先是移除了已经注册好的bean,之后创建了一个新的mock bean,并注册到spring的bean容器中。
由于这里面,我们用到了工厂方法:.setFactoryMethod("mock"), 所以我们需要定义一个工厂类:
public class BeanFactory { public static <T> T mock(Class<T> clazz) { System.out.println("创建mock的clazz:" + clazz.getName()); return Mockito.mock(clazz); } public static Object original(Object obj) { System.out.println("创建mock的对象:" + obj.getClass().getName()); return obj; } }
跑起项目,可以看到bean被替换了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 没有源码,如何修改代码逻辑?
· 分享4款.NET开源、免费、实用的商城系统
· 全程不用写代码,我用AI程序员写了一个飞机大战
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· 白话解读 Dapr 1.15:你的「微服务管家」又秀新绝活了
· 上周热点回顾(2.24-3.2)