类似Spring的PostProcessor挂在动态注册的第三方Bean上



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

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

限制

  • AbstractStub实现是gRPC生成的类。我的课程扩展了AbstractStub
  • 首选的静态工厂方法是builder(Channel)方法;这是手动样板处理@Bean声明时使用的内容
  • 每个存根都需要一个Channel作为依赖项。存在多个Channel@Beans

尝试次数

我尝试了三种方法:

方法1: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挂钩

无法在BeanDefinition上注册ClientInterceptor

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
}
}
}

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

@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);
}
};
}
};
}

最新更新