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

发布时间 2023-05-31 15:55:39作者: lythen

        前天到昨天晚上,某开发报告了一个问题,我们的一个应用程序接入了腾讯的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,因此不会被覆盖。经测试,解决问题。

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