I started to use Spring Integration in a project at work. Everything was looking fine and running smoothly on my local dev environment (when executed from Eclipse).
However, when I tried to deploy to our dev/staging environment I got some issues related with the definition of the Spring Integration channels.
After a couple of hours completely clueless (blaming external dependencies, our development/staging environment setup etc etc), I came to realize that I would get exactly the same issue whenever I tried to execute my application as a packaged jar (on my local machine)
I did a small "sample" application without any other dependencies in order to reproduce this issue. Once again everything works fine from eclipse but whenever executed as a packaged jar the following exception was thrown:
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'gatewayChannel' available
at org.springframework.beans.factory.support.DefaultListableBeanFactory.getBeanDefinition(DefaultListableBeanFactory.java:687)
at org.springframework.beans.factory.support.AbstractBeanFactory.getMergedLocalBeanDefinition(AbstractBeanFactory.java:1207)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:284)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:202)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:89)
at org.springframework.integration.support.channel.BeanFactoryChannelResolver.resolveDestination(BeanFactoryChannelResolver.java:46)
at org.springframework.integration.gateway.MessagingGatewaySupport.getRequestChannel(MessagingGatewaySupport.java:344)
at org.springframework.integration.gateway.MessagingGatewaySupport.send(MessagingGatewaySupport.java:385)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invokeGatewayMethod(GatewayProxyFactoryBean.java:481)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.doInvoke(GatewayProxyFactoryBean.java:433)
at org.springframework.integration.gateway.GatewayProxyFactoryBean.invoke(GatewayProxyFactoryBean.java:424)
at org.springframework.integration.gateway.GatewayCompletableFutureProxyFactoryBean.invoke(GatewayCompletableFutureProxyFactoryBean.java:65)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy24.send(Unknown Source)
at com.test.App$RealApp.doThings(App.java:52)
at com.test.App.main(App.java:62)
Bellow you can find the code of my sample application and the pom that I used to build my packaged jar.
@ComponentScan
@EnableIntegration
@IntegrationComponentScan
@Configuration
public class App {
@MessagingGateway
public interface GatewayApp {
@Gateway(requestChannel = "gatewayChannel")
void send(String string);
}
@Bean
public IntegrationFlow inboud() {
return IntegrationFlows.from("gatewayChannel")
.handle(System.out::println)
.get();
}
@Component
public class RealApp {
@Autowired
private GatewayApp gateway;
public void doThings() {
gateway.send("yeee");
}
}
@SuppressWarnings("resource")
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(App.class);
context.refresh();
context.getBean(RealApp.class).doThings();
}
}
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>sprint-integration</groupId>
<artifactId>integration</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>integration</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<spring.version>4.3.14.RELEASE</spring.version>
</properties>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.20.1</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>true</createDependencyReducedPom>
<createSourcesJar>false</createSourcesJar>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>yo-service</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<dependencies>
<!-- Spring Integration -->
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-amqp</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-java-dsl</artifactId>
<version>1.2.3.RELEASE</version>
</dependency>
</dependencies>
</project>
Note: I think this issue might have exaclty the same cause as the one reported in Spring integration bootstrap - intellij in debug works, packaged jar does not
My best guess is the shade plugin is having some effect on the order in which BeanPostProcessors are run.
Does the app work if you explicitly define the channel...
@Bean
public MessageChannel gatewayChannel() {
return new DirectChannel();
}
...?
If so, that would be a smoking gun. In that case, the next step would be to get a DEBUG log for org.springframework in both environments and compare the bean definition/creation/post processing logs.
If you can post a complete (simple) example that exhibits the problem, we can take a look.
EDIT
The problem is the shade plugin does not merge the META-INF/spring.factories files, so we lose the entry from the JAVA DSL and hence don't process any IntegrationFlows...
From the Uber jar we just have the core file...
org.springframework.integration.config.IntegrationConfigurationInitializer=\
org.springframework.integration.config.GlobalChannelInterceptorInitializer,\
org.springframework.integration.config.IntegrationConverterInitializer,\
org.springframework.integration.config.IdempotentReceiverAutoProxyCreatorInitializer
and so are missing the additional initializer from the DSL jar...
org.springframework.integration.config.IntegrationConfigurationInitializer=\
org.springframework.integration.dsl.config.DslIntegrationConfigurationInitializer
Hence it works with 5.0.1 because the DSL is now part of core.
Spring Boot solves this problem by nesting the jars instead of extracting all the classes.
EDIT2
Here's another work-around, if you can't move to Spring Integration 5. Add this bean to your application...
@Bean
public static BeanFactoryPostProcessor dslInitializer() {
return new BeanFactoryPostProcessor() {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory bf) throws BeansException {
new DslIntegrationConfigurationInitializer().initialize(bf);
}
};
}
(Notice static).
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With