首页 > 其他分享 >一个由于不同微服务框架混搭导致BeanPostProcessors处理bean异常导致的问题

一个由于不同微服务框架混搭导致BeanPostProcessors处理bean异常导致的问题

时间:2023-05-31 15:55:42浏览次数:43  
标签:初始化 导致 factoryBuilder 框架 BeanPostProcessors bean sleuthProperties B3Propagation

        前天到昨天晚上,某开发报告了一个问题,我们的一个应用程序接入了腾讯的TSF微服务框架后,使用feign访问接口,会导致token丢失,无法解决。

        大体介绍下项目情况,我们的应用使用了某第三方微服务框架,不是源生的springcloud或springcloud alibaba框架,第三方厂家基于springcloud构建的微服务框架,这里我就不具体说公司名吧,我就叫E框架吧。

        为什么要这么混搭呢?首选,我们的应用选择的开发框架是E框架,这个是历史问题,我接手时就是这样了。其次,当前国产化要求,一定要把应用部署TSF平台中,并且一定要使用TSF的微服务框架。因此就有了该混搭。

        开发跟我描述的问题B3Propagation.FACTORY的bean没有被初始化,因为第三方框架实现了一个BeanPostProcessors,而这个BeanPostProcessors会对B3Propagation.FACTORY进行处理,处理后的B3Propagation.FACTORY重新实现了injector和extractor方法,而正是这两个方法,对请求进行处理,奖请求中的Authorization添加到了feign求请中header中,以及添加了E框架用于网关校验的其他参数。现在没必要去纠结为什么要这么做,毕竟我们用的是别人的框架,这是即成的事实,主要是解决问题。

       虽然他是这么说,但我还是持怀疑态度,我查看了日志,发现E框架涉及的bean都报了以下问题:

Bean 'xxxxxxx' of type [com.primeton.eos.dap.sdk.tracing.autoconfig.xxxxxxx] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)        其实我曾一度被这个问题带偏,以为这些bean都没有被初始化,也到网上查了相关的资料,但是经idea查看service中的bean发现,所有的bean都好好的初始化,一点问题都没有,这就奇了怪了,既然初始化了bean,那为何E框架的BeanPostProcessors没有对B3Propagation.FACTORY进行处理?        后来,干脆找到B3Propagation.FACTORY初始化bean的地方,Propagation.Factory sleuthPropagation(SleuthProperties sleuthProperties),进行踪后发现,这个bean初始化,被N个BeanPostProcessors处理了,但却没有进入E框架的BeanPostProcessors的postProcessAfterInitialization中。于是,我找到AbstractAutowireCapableBeanFactory的
@Override
	public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
		for (BeanPostProcessor processor : getBeanPostProcessors()) {
			Object current = processor.postProcessAfterInitialization(result, beanName);
			if (current == null) {
				return result;
			}
			result = current;
		}
		return result;
	}

  这里会使用getBeanPostProcessors获取所有继承了BeanPostProcessors的类,通过断点我发现,初始化B3Propagation.FACTORY后,E框架的所有BeanPostProcessors都不在AbstractAutowireCapableBeanFactory的beanPostProcessors中。到这里大概有点眉目了,应该就是两个框架都去初始化了B3Propagation.FACTORY,以下是org.springframework.cloud.sleuth.autoconfig.TraceAutoConfiguration初始化过程,可以看到,bean的初始化方法标记为“ConditionalOnMissingBean",意思是不存在该bean的时候,才会创建该bean。TSF框架对bean进行创建 后,E框架初始化时再进行创建时,发现bean存在,则不会再创建了。

@Bean
    @ConditionalOnMissingBean
    Propagation.Factory sleuthPropagation(SleuthProperties sleuthProperties) {
        if (sleuthProperties.getBaggageKeys().isEmpty()
                && sleuthProperties.getPropagationKeys().isEmpty()) {
            return B3Propagation.FACTORY;
        }
        ExtraFieldPropagation.FactoryBuilder factoryBuilder;
        if (this.extraFieldPropagationFactoryBuilder != null) {
            factoryBuilder = this.extraFieldPropagationFactoryBuilder;
        }
        else {
            factoryBuilder = ExtraFieldPropagation
                    .newFactoryBuilder(B3Propagation.FACTORY);
        }
        if (!sleuthProperties.getBaggageKeys().isEmpty()) {
            factoryBuilder = factoryBuilder
                    // for HTTP
                    .addPrefixedFields("baggage-", sleuthProperties.getBaggageKeys())
                    // for messaging
                    .addPrefixedFields("baggage_", sleuthProperties.getBaggageKeys());
        }
        if (!sleuthProperties.getPropagationKeys().isEmpty()) {
            for (String key : sleuthProperties.getPropagationKeys()) {
                factoryBuilder = factoryBuilder.addField(key);
            }
        }
        return factoryBuilder.build();
    }

        所以,第一个处理方案就是如何让bean在E框架初始化后再进行初始化,于是进行了第一轮修改,于是有了如下类,有些病急乱投医的感觉:

@Configuration
@AutoConfigureAfter(com.xxx.xxx.xxx.xxx.tracing.autoconfig.SDKTraceAutoConfiguration.class)
public class XxxBeanConfig implements CommandLineRunner {

    @Autowired
    TraceAutoConfiguration traceAutoConfiguration;
    @Autowired(required = false)
    ExtraFieldPropagation.FactoryBuilder extraFieldPropagationFactoryBuilder;
 
    @Bean
    @Primary
    @DependsOn("sdkPropagationFactoryPostProcessor")
    Propagation.Factory sleuthPropagation(SleuthProperties sleuthProperties, SDKTraceAutoConfiguration sdkTraceAutoConfiguration) {
       if (sleuthProperties.getBaggageKeys().isEmpty()
                && sleuthProperties.getPropagationKeys().isEmpty()) {
            return B3Propagation.FACTORY;
        }
        ExtraFieldPropagation.FactoryBuilder factoryBuilder;
        if (this.extraFieldPropagationFactoryBuilder != null) {
            factoryBuilder = this.extraFieldPropagationFactoryBuilder;
        }
        else {
            factoryBuilder = ExtraFieldPropagation
                    .newFactoryBuilder(B3Propagation.FACTORY);
        }
        if (!sleuthProperties.getBaggageKeys().isEmpty()) {
            factoryBuilder = factoryBuilder
                    // for HTTP
                    .addPrefixedFields("baggage-", sleuthProperties.getBaggageKeys())
                    // for messaging
                    .addPrefixedFields("baggage_", sleuthProperties.getBaggageKeys());
        }
        if (!sleuthProperties.getPropagationKeys().isEmpty()) {
            for (String key : sleuthProperties.getPropagationKeys()) {
                factoryBuilder = factoryBuilder.addField(key);
            }
        }
        return factoryBuilder.build();
    }
    /**
     * Callback used to run the bean.
     *
     * @param args incoming main method arguments
     * @throws Exception on error
     */
    @Override
    public void run(String... args) throws Exception {

    }
}

        我试图通过人工干预初始化顺序的方式来进行修改,除了上面已有代码,其实还用过@Order等,然并卵,断点发现,sleuthPropagation初始化后,其实E框架的SDKPropagationFactoryPostProcessor已经初始化了,但是并没有装到AbstractAutowireCapableBeanFactory的beanPostProcessors中。那这就不是初始化顺序问题了。这个时候,我本来是想解决为什么SDKPropagationFactoryPostProcessor初始化完成后,没有被装到AbstractAutowireCapableBeanFactory的beanPostProcessors里的,转念一想,这可能是框架问题,而这两个框架,我们都没有源码,就算是这个问题,也无法解决。那就手动使用SDKPropagationFactoryPostProcessor得了吧。好,得了吧,这个是内部类。。。但是这难不倒我,不就是个内部类么?我用你的接口不就行了么?于是有了以下的修改,主要看红色部分:


@Autowired
AbstractApplicationContext abstractApplicationContext;
Propagation.Factory sleuthPropagation(SleuthProperties sleuthProperties, SDKTraceAutoConfiguration sdkTraceAutoConfiguration) {
        BeanPostProcessor processor = (BeanPostProcessor)abstractApplicationContext.getBean("sdkPropagationFactoryPostProcessor");
        if (sleuthProperties.getBaggageKeys().isEmpty()
                && sleuthProperties.getPropagationKeys().isEmpty()) {
            return (Propagation.Factory) processor.postProcessAfterInitialization(B3Propagation.FACTORY,"sleuthPropagation");
        }
        ExtraFieldPropagation.FactoryBuilder factoryBuilder;
        if (this.extraFieldPropagationFactoryBuilder != null) {
            factoryBuilder = this.extraFieldPropagationFactoryBuilder;
        }
        else {
            factoryBuilder = ExtraFieldPropagation
                    .newFactoryBuilder(B3Propagation.FACTORY);
        }
        if (!sleuthProperties.getBaggageKeys().isEmpty()) {
            factoryBuilder = factoryBuilder
                    // for HTTP
                    .addPrefixedFields("baggage-", sleuthProperties.getBaggageKeys())
                    // for messaging
                    .addPrefixedFields("baggage_", sleuthProperties.getBaggageKeys());
        }
        if (!sleuthProperties.getPropagationKeys().isEmpty()) {
            for (String key : sleuthProperties.getPropagationKeys()) {
                factoryBuilder = factoryBuilder.addField(key);
            }
        }
        return (Propagation.Factory) processor.postProcessBeforeInitialization(factoryBuilder.build(),"sleuthPropagation");
    }

        我采用了getBean的方式获取类实例,使用接口BeanPostProcessor 进行转换,再调用postProcessAfterInitialization接口,并且该bean声明为@Primary,因此不会被覆盖。经测试,解决问题。

        以上就是解决问题的过程,其实解决问题的方法相当简单,分析问题比较难,也怪自己学艺不精。

标签:初始化,导致,factoryBuilder,框架,BeanPostProcessors,bean,sleuthProperties,B3Propagation
From: https://www.cnblogs.com/lythen/p/17446384.html

相关文章

  • Spring AOP错误:org.springframework.beans.factory.BeanNotOfRequiredTypeException:
    org.springframework.beans.factory.BeanNotOfRequiredTypeException:Beannamed'myCalculator'isexpectedtobeoftype'com.mashibing.service.MyCalculator'butwasactuallyoftype'com.sun.proxy.$Proxy19'atorg.springframew......
  • 浅谈 Spring Bean 的生命周期
    一、Bean的生命周期概述区别于普通的Java对象需要通过new创建对象,Spring的Bean由IoC容器进行实例化、组装以及管理的。也就是说 Bean的生命周期完全由IoC容器控制。Spring容器只能管理 单例(singleton) 作用域的Bean的完整生命周期,对于 原型(prototype) 作用域......
  • Could not autowire. No beans of 'AddressBookService' type found.
    错误:错误原因:Service实现类未继承Service接口解决方法: ......
  • 关于数据和处理器位宽不匹配导致的数据跳变问题分析
    关于数据和处理器位宽不匹配导致的数据跳变问题分析本问题来源于2023.5.31上海创景工程师所作讲座,仅作记录,用于参考。问题情景一个64位的数据(类似时钟,不断变化),在输入到32位处理器进行处理后,发现输出的数据并不和输入数据匹配,即出现跳变。错误分析32位处理器可以处理64位......
  • 基于SCCM Baseline修正Lenovo高通X55 WWAN过度记录导致C盘空间被占满的问题
    背景近期有大量使用LenovoThinkPad系列的计算机C盘磁盘空间被占满。经过分析发现:位于%ProgramData%\Qualcomm®Snapdragon™X555GModem\SVClog下的日志文件占用了大量磁盘空间。本文为微风原创文章.经实践,测试,整理发布.如需转载请联系作者获得授权,并注明转载地址。原因分......
  • Win下环境变量包含空格导致的坑
    例如JAVA_HOME=C:\ProgramFiles\java\这类环境变量中包含空格,其他使用Java的组件如Hadoop(win下懒得弄WSL,凑合用)会出现Error:JAVA_HOMEisincorrectlyset.此时,将环境变量的C:\ProgramFiles替换为C:\PROGRA~1其他同样的替换有:C:\ProgramFiles<---------->C:\PROGRA~......
  • Spring bean的循环引用问题
    循环依赖:两个或两个以上的bean循环引用。例如:A依赖B,B依赖A。Spring有三种循环依赖问题:(1)构造器的循环依赖:Spring无法解决构造器的循环依赖问题,但是可以使用@Lazy将bean声明为懒加载,什么时候用到这个bean在创建。(2)非单例bean的setter循环依赖:Spring无法解决非单例bean的循环依赖......
  • Spring中的单例bean是线程安全的吗?
    Spring并没有对单例bean作线程安全的处理,在并发条件下Spring的bean是否是线程安全的有如下两种情况:(1)无状态的bean:没有数据存储能力,例如service类和dao类都是无状态的bean,所以是线程安全的。(2)有状态的bean:有数据存储能力,在并发环境下会发生线程安全问题,需要自行保证线程安全问题,......
  • 循环依赖导致编译或者服务启动报错问题:The dependencies of some of the beans in the
    错误如图: 我的是服务器启动服务时报错:***************************APPLICATIONFAILEDTOSTART***************************Description:Thedependenciesofsomeofthebeansintheapplicationcontextformacycle报错原因:两个类相互引用对方,导致Spring在初始化b......
  • [20230517]建立索引导致的性能问题2.txt
    [20230517]建立索引导致的性能问题2.txt--//生产系统遭遇建立索引导致的性能问题,建立的sqlprofile里面包含索引名提示,很少见,改索引名导致sqlprofile失效,--//当然我遇到的情况有一点点不同,建立新索引,然后旧索引设置不可见(相当于改名),具体看下面的测试环境模拟.1.环境:SCO......