首页 > 解决方案 > 动态注册的第三方 Bean 上的类似 Spring 的 PostProcessor Hook

问题描述

我在动态注册的第三方 bean 上使用什么 Spring Framework 挂钩?

我有一个BeanDefinitionRegistryPostProcessor用于动态类路径扫描和实例化多个第三方 bean(gRPCAbstractStub实例)的方法。我需要ClientInterceptors在存根上注册,以便增强AbstractStub的可以进行应用程序处理。我使用动态创建*Stub @Beans来消除所有@Bean样板并确保一致的通道配置。

约束

尝试

我尝试了三种方法:

方法一:BeanDefinitionBuilder+Supplier函数

BeanDefinitionBuilder.genericBeanDefinition(Class, Supplier)不允许注入Channel依赖项。

void registerBeanDefintion(final Class<S> clazz, final BeanDefinitionRegistry registry) {
    Supplier<S> stubSupplier = () -> {
        clazz.getConstructor({Channel.class});
        return BeanUtils.instantiateClass(constructor, null); // fails here; no Channel
    }
    BeanDefinitionBuilder builder =
        BeanDefinitionBuilder.genericBeanDefinition(clazz, stubSupplier);
    builder.addDependsOn(MANAGED_CHANNEL_BEAN_NAME);
    builder.addConstructorArgReference(MANAGED_CHANNEL_BEAN_NAME);
    registry.registerBeanDefinition(clazz.getName(), builder.getBeanDefinition());

方法2:BeanDefinitionBuilderCallOption钩子

无法ClientInterceptor在 BeanDefinition 上注册 a。

void registerBeanDefintion(final Class<S> clazz, final BeanDefinitionRegistry registry) {
    builder.addDependsOn(MANAGED_CHANNEL_BEAN_NAME);
    builder.addConstructorArgReference(MANAGED_CHANNEL_BEAN_NAME);
    CallOptions callOptions = CallOptions.DEFAULT;
    // no hook in CallOptions to register ClientInterceptor
    registry.registerBeanDefinition(clazz.getName(), builder.getBeanDefinition());

方法3:postProcessBeanFactory()

postProcessBeanFactory不在实例化的 bean 上运行,因此依赖关系不是预先解决的。

public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    Iterator<String> iterator = configurableListableBeanFactory.getBeanNamesIterator();
    while (iterator.hasNext()) {
        String beanName = iterator.next();
        if (beanName.endsWith("Stub")) {
            AbstractStub stub = (AbstractStub) configurableListableBeanFactory.getBean(beanName); //fails
            stub.withInterceptors(newClientInterceptor()); // never gets executed
        }
    }
}

标签: javaspringgrpcspring-beangrpc-java

解决方案


因为我有一些单独的模块,所以我有点过于复杂了:解决方案是使用简单的并仅对实例BeanPostProcessor调用:withInterceptors()AbstractStub

    @Override
    public Object postProcessAfterInitialization(final Object bean, final String beanName) throws BeansException {
        if (bean instanceof AbstractStub) {
            AbstractStub stub = (AbstractStub) bean;
            log.debug("modify bean '{}': add timeout client interceptor", beanName);
            ClientInterceptor timeoutClientInterceptor = this.newTimeoutClientInterceptor(stub);
            AbstractStub result = stub.withInterceptors(timeoutClientInterceptor);
            return result;
        }
        return bean;
    }

    ClientInterceptor newTimeoutClientInterceptor(final AbstractStub stub) {
        final Deadline deadline = this.getDeadlineTimeout(stub);
        return new ClientInterceptor() {
            @Override
            public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> method, CallOptions callOptions, Channel next) {
                final ClientCall<ReqT, RespT> clientCall = next.newCall(method, callOptions.withDeadline(deadline));
                return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(clientCall) {
                    @Override
                    protected void checkedStart(Listener<RespT> listener, Metadata metadata) {
                        log.debug("execute call with deadline {}", deadline);
                        delegate().start(listener, metadata);
                    }
                };
            }
        };
    }


推荐阅读