Native compilation changes required in SCSt apps

- Instead of injecting `AbstractMappingMessageRouter[]`, inject it as a container
  type using `List<>`. This is because the former uses reflection behind the scenes
  and causes issues with graal native compilation (unless provided as a native hint).

- Instead of autowiring `Map<String, BindingTargetFactory>` in
  `AbstractBindableProxyFactory`, programmatically populate `BindingTargetFactory`
  beans by doing a `BeanFactory` lookup in a new method. Then the subclasses of
  `AbstractBindableProxyFactory` call this method to pouplate the avaialble
  `BindingTargetFactory` beans in their `afterPropertiesSet` method.

- Convert array injection of `BindableProxyFactory[]` in functionInitailzer bean
  in `FunctionConfiguration` to use container based injejction (`List<>`).

- Cleanup unused injection in functionInitializer bean in `FunctionConfiguration`.

Resolves https://github.com/spring-cloud/spring-cloud-stream/issues/2154

Resolves #2155
This commit is contained in:
Soby Chacko
2021-04-21 19:28:59 -04:00
committed by Oleg Zhurakousky
parent 1cd165df46
commit ae017e222f
6 changed files with 41 additions and 19 deletions

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019-2019 the original author or authors.
* Copyright 2019-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,7 +26,8 @@ import java.util.Set;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.ListableBeanFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.stream.binder.Binding;
import org.springframework.cloud.stream.internal.InternalPropertyNames;
@@ -48,7 +49,6 @@ public class AbstractBindableProxyFactory implements Bindable {
@Value("${" + InternalPropertyNames.NAMESPACE_PROPERTY_NAME + ":}")
private String namespace;
@Autowired
protected Map<String, BindingTargetFactory> bindingTargetFactories;
protected Map<String, BoundTargetHolder> inputHolders = new LinkedHashMap<>();
@@ -57,10 +57,16 @@ public class AbstractBindableProxyFactory implements Bindable {
protected Class<?> type;
private BeanFactory beanFactory;
public AbstractBindableProxyFactory(Class<?> type) {
this.type = type;
}
protected void populateBindingTargetFactories(BeanFactory beanFactory) {
this.bindingTargetFactories = ((ListableBeanFactory) beanFactory).getBeansOfType(BindingTargetFactory.class);
}
protected BindingTargetFactory getBindingTargetFactory(Class<?> bindingTargetType) {
List<String> candidateBindingTargetFactories = new ArrayList<>();
for (Map.Entry<String, BindingTargetFactory> bindingTargetFactoryEntry : this.bindingTargetFactories

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 the original author or authors.
* Copyright 2015-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -26,6 +26,9 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.BeanFactoryAware;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.cloud.stream.annotation.EnableBinding;
@@ -45,10 +48,11 @@ import org.springframework.util.ReflectionUtils;
* @author David Syer
* @author Ilayaperumal Gopinathan
* @author Oleg Zhurakousky
* @author Soby Chacko
* @see EnableBinding
*/
public class BindableProxyFactory extends AbstractBindableProxyFactory
implements MethodInterceptor, FactoryBean<Object>, InitializingBean {
implements MethodInterceptor, FactoryBean<Object>, InitializingBean, BeanFactoryAware {
private static Log log = LogFactory.getLog(BindableProxyFactory.class);
@@ -56,6 +60,8 @@ public class BindableProxyFactory extends AbstractBindableProxyFactory
private Object proxy;
private BeanFactory beanFactory;
public BindableProxyFactory(Class<?> type) {
super(type);
this.type = type;
@@ -112,6 +118,7 @@ public class BindableProxyFactory extends AbstractBindableProxyFactory
@Override
public void afterPropertiesSet() {
populateBindingTargetFactories(this.beanFactory);
Assert.notEmpty(BindableProxyFactory.this.bindingTargetFactories,
"'bindingTargetFactories' cannot be empty");
ReflectionUtils.doWithMethods(this.type, method -> {
@@ -159,4 +166,8 @@ public class BindableProxyFactory extends AbstractBindableProxyFactory
return true;
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2019 the original author or authors.
* Copyright 2015-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -170,6 +170,7 @@ public class BinderFactoryAutoConfiguration {
ClassLoader classLoader = configurableApplicationContext.getClassLoader();
try {
Enumeration<URL> resources = classLoader.getResources("META-INF/spring.binders");
// see if test binder is available on the classpath and if so add it to the binderTypes
try {
BinderType bt = new BinderType("integration", new Class[] {

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2015-2018 the original author or authors.
* Copyright 2015-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -70,6 +70,7 @@ import org.springframework.messaging.MessageChannel;
import org.springframework.messaging.core.DestinationResolver;
import org.springframework.scheduling.TaskScheduler;
import org.springframework.util.Assert;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;
/**
@@ -198,7 +199,6 @@ public class BindingServiceConfiguration {
public BinderFactory binderFactory(BinderTypeRegistry binderTypeRegistry,
BindingServiceProperties bindingServiceProperties,
ObjectProvider<BinderCustomizer> binderCustomizerProvider) {
DefaultBinderFactory binderFactory = new DefaultBinderFactory(
getBinderConfigurations(binderTypeRegistry, bindingServiceProperties),
binderTypeRegistry, binderCustomizerProvider.getIfUnique());
@@ -271,11 +271,12 @@ public class BindingServiceConfiguration {
@Bean
@ConditionalOnMissingBean
public BinderAwareRouter binderAwareRouterBeanPostProcessor(
@Autowired(required = false) AbstractMappingMessageRouter[] routers,
@Autowired(required = false) List<AbstractMappingMessageRouter> routers,
@Autowired(required = false) @Qualifier("binderAwareChannelResolver")
DestinationResolver<MessageChannel> channelResolver) {
return new BinderAwareRouter(routers, channelResolver);
final AbstractMappingMessageRouter[] routersArray = CollectionUtils.isEmpty(routers) ?
new AbstractMappingMessageRouter[]{} : routers.toArray(new AbstractMappingMessageRouter[]{});
return new BinderAwareRouter(routersArray, channelResolver);
}
@Bean

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2019-2019 the original author or authors.
* Copyright 2019-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -39,6 +39,7 @@ import org.springframework.util.CollectionUtils;
* function with the name `myFunction`.
*
* @author Oleg Zhurakousky
* @author Soby Chacko
*
* @since 3.0
*/
@@ -74,6 +75,7 @@ class BindableFunctionProxyFactory extends BindableProxyFactory {
@Override
public void afterPropertiesSet() {
populateBindingTargetFactories(context.getBeanFactory());
Assert.notEmpty(BindableFunctionProxyFactory.this.bindingTargetFactories,
"'bindingTargetFactories' cannot be empty");

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2018-2020 the original author or authors.
* Copyright 2018-2021 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -116,6 +116,7 @@ import org.springframework.util.StringUtils;
* @author Oleg Zhurakousky
* @author David Turanski
* @author Ilayaperumal Gopinathan
* @author Soby Chacko
* @since 2.1
*/
@Configuration
@@ -147,10 +148,10 @@ public class FunctionConfiguration {
}
@Bean
public InitializingBean functionInitializer(FunctionCatalog functionCatalog, FunctionInspector functionInspector,
StreamFunctionProperties functionProperties, @Nullable BindableProxyFactory[] bindableProxyFactories,
BindingServiceProperties serviceProperties, ConfigurableApplicationContext applicationContext,
FunctionBindingRegistrar bindingHolder, StreamBridge streamBridge) {
public InitializingBean functionInitializer(FunctionCatalog functionCatalog,
StreamFunctionProperties functionProperties,
BindingServiceProperties serviceProperties, ConfigurableApplicationContext applicationContext,
StreamBridge streamBridge) {
boolean shouldCreateInitializer = applicationContext.containsBean("output")
|| ObjectUtils.isEmpty(applicationContext.getBeanNamesForAnnotation(EnableBinding.class));
@@ -167,10 +168,10 @@ public class FunctionConfiguration {
@Bean
InitializingBean supplierInitializer(FunctionCatalog functionCatalog, StreamFunctionProperties functionProperties,
GenericApplicationContext context, BindingServiceProperties serviceProperties,
@Nullable BindableFunctionProxyFactory[] proxyFactories, StreamBridge streamBridge,
@Nullable List<BindableFunctionProxyFactory> proxyFactories, StreamBridge streamBridge,
TaskScheduler taskScheduler) {
if (!ObjectUtils.isEmpty(context.getBeanNamesForAnnotation(EnableBinding.class)) || proxyFactories == null) {
if (!ObjectUtils.isEmpty(context.getBeanNamesForAnnotation(EnableBinding.class)) || CollectionUtils.isEmpty(proxyFactories)) {
return null;
}