application.yaml spring.activemq.broker-url not set - spring-boot

I'm trying to set my spring app to listen to a JMS queue.
I try to set the broker-url in my application.yml but it always seems to default back to "localhost:61616".
The application.yml file is loaded from another application, but I don't think that matters since other properties in the file are read (the name of the queues for example)
Here is the message I get :
o.a.a.t.failover.FailoverTransport;Failed to connect to [tcp://localhost:61616] after: 40 attempt(s) continuing to retry.
What I tried
I've tried following the answer to this question : Camel ActiveMQ + Spring boot not reading spring activemq configurations
Which is my exact issue
But when I try adding the dependency and creating that class I get this error :
Parameter 0 of method createComponent in xxx.xxxxx.xxxx.configuration.ActiveMQComponentConfig required a bean of type 'javax.jms.ConnectionFactory' that could not be found.
I'm quite new to Spring boot / ActiveMQ and don't really know what to do about this.
Here's the relevant part of my pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.3.RELEASE</version>
<relativePath />
</parent>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
<version>${camel.version}</version>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-broker</artifactId>
</exclusion>
</exclusions>
</dependency>
And my application.yml :
spring:
aop:
proxy-target-class: true
cache:
ehcache:
config: classpath:ehcache.xml
activemq:
broker-url: tcp://foo:12345
pool:
enabled: true
max-connections: 5
Any help would be greatly appreciated, I already spent a fair amount of time on this and not making any progress

This is what I ended up doing to get it to work again. I still don't know why Spring's autoconfig stopped working but that solved it
#Configuration
public class JmsConfig {
#Value("${spring.activemq.broker-url}")
String BROKER_URL;
#Value("${spring.activemq.user}")
String BROKER_USERNAME;
#Value("${spring.activemq.password}")
String BROKER_PASSWORD;
#Bean
public ActiveMQConnectionFactory connectionFactory(){
ActiveMQConnectionFactory connectionFactory = new ActiveMQConnectionFactory();
connectionFactory.setBrokerURL(BROKER_URL);
connectionFactory.setUserName(BROKER_USERNAME);
connectionFactory.setPassword(BROKER_PASSWORD);
return connectionFactory;
}
#Bean
public JmsTemplate jmsTemplate(){
JmsTemplate template = new JmsTemplate();
template.setConnectionFactory(connectionFactory());
return template;
}
#Bean
public DefaultJmsListenerContainerFactory jmsListenerContainerFactory() {
DefaultJmsListenerContainerFactory factory = new DefaultJmsListenerContainerFactory();
factory.setConnectionFactory(connectionFactory());
factory.setConcurrency("1-1");
return factory;
}
}

Related

Spring Security OAuth2 client_credentials + Webclient without webserver

I have an application, that currently uses RestTemplate + OAuth2. The application itself is NOT a Spring MVC app, so for example no ports are open (no #GetMapping what so ever).
I am migrating from Spring Security OAuth 2.x to Spring Security 5.2.x. using this guide:
https://github.com/spring-projects/spring-security/wiki/OAuth-2.0-Migration-Guide
Config is:
#Configuration
public class WebClientConfig {
#Bean
public OAuth2AuthorizedClientManager authorizedClientManager(
ClientRegistrationRepository clientRegistrationRepository,
OAuth2AuthorizedClientRepository authorizedClientRepository) {
OAuth2AuthorizedClientProvider authorizedClientProvider =
OAuth2AuthorizedClientProviderBuilder.builder()
.clientCredentials()
.build();
DefaultOAuth2AuthorizedClientManager authorizedClientManager =
new DefaultOAuth2AuthorizedClientManager(
clientRegistrationRepository, authorizedClientRepository);
authorizedClientManager.setAuthorizedClientProvider(authorizedClientProvider);
return authorizedClientManager;
}
#Bean
public WebClient webClient(OAuth2AuthorizedClientManager authorizedClientManager) {
ServletOAuth2AuthorizedClientExchangeFilterFunction oauth2Client =
new ServletOAuth2AuthorizedClientExchangeFilterFunction(authorizedClientManager);
oauth2Client.setDefaultClientRegistrationId("regid");
return WebClient.builder()
.apply(oauth2Client.oauth2Configuration())
.build();
}
}
application.properties:
spring.security.oauth2.client.registration.regid.provider=regid
spring.security.oauth2.client.registration.regid.client-id=java-web
spring.security.oauth2.client.registration.regid.client-secret=secret
spring.security.oauth2.client.registration.regid.authorization-grant-type=client_credentials
spring.security.oauth2.client.provider.regid.token-uri=https://...token
spring.security.oauth2.client.provider.regid.jwk-set-uri=https://..certs
The problem is:
This app runs on a server that has port 8080 already allocated.
Previous version (Spring Oauth2 + RestTemplate) did NOT open any ports, especially 8080.
It seems that I can not use WebClient without making this app a webapp, listening on port 8080, which I cannot open, and I don't want to change to a random port to avoid collision. The app just simply does not need any ports to be opened.
I've tried several things, for example:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<artifactId>tomcat-embed-el</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
<exclusion>
<artifactId>tomcat-embed-core</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
<exclusion>
<artifactId>tomcat-embed-websocket</artifactId>
<groupId>org.apache.tomcat.embed</groupId>
</exclusion>
</exclusions>
</dependency>
And also:
spring.main.web-application-type=none
etc., but every single time I've encountered a "random" NoClassDefFound javax.servlet.*, or: "Could not autowire. No beans of 'x' type found."
How can I setup the app:
using newest Spring Security with OAuth2
using WebClient
not being a webapp itself
?
thank you

Spring Boot application is ignoring hikaricp config

I'm new to stackoverflow, but read tons of posts here and now stuck.my application.properties is read, but the portion for configuring hikaricp is ignored/has no effect.
I read https://www.javadevjournal.com/spring-boot/spring-boot-hikari/ and folowed those steps there, still any success.
pom.xml
<dependencies>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-ehcache</artifactId>
<version>5.4.10.Final</version>
<exclusions>
<exclusion>
<groupId>net.sf.ehcache</groupId>
<artifactId>ehcache</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-jcache</artifactId>
<version>5.4.10.Final</version>
</dependency>
<dependency>
<groupId>org.ehcache</groupId>
<artifactId>ehcache</artifactId>
<version>3.6.3</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
<version>2.2.2.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
</exclusion>
</exclusions>
<scope>test</scope>
<version>2.2.2.RELEASE</version>
</dependency>
application.properties
spring.cache.jcache.config=classpath:ehcache.xml
spring.datasource.jdbc-url=jdbc:postgresql://VOC-APP202-db:5432/voice-app
spring.datasource.username=vocapp202
spring.datasource.password=******
srping.datasource.driver-class-name=org.postgresql.Driver
spring.datasource.type=com.zaxxer.hikari.HikariDataSource
spring.datasource.hikari.connectionTimeout=1000
spring.datasource.hikari.idleTimeout=30000
spring.datasource.hikari.maxLifetime=60000
spring.datasource.hikari.connectionTestQuery=SELECT * FROM table where id=1
spring.datasource.hikari.minimumIdle=1
spring.datasource.hikari.maximumPoolSize=5
spring.datasource.hikari.poolName=voiceapp-db-pool
spring.datasource.hikari.autoCommit=false
BlacklistApplication.class:
package de.mycompany.voice.blacklist_ng;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
#SpringBootApplication
#EnableJpaAuditing
#EnableCaching
#Configuration
public class BlacklistngApplication {
public static void main(String[] args) {
SpringApplication.run(BlacklistngApplication.class, args);
}
}
Config class:
#Configuration
#ConfigurationProperties("spring.datasource")
#EnableTransactionManagement
#EnableJpaRepositories(
entityManagerFactoryRef = "entityManagerFactory",
basePackages = {"de.firsttelecom.voice.blacklist_ng.repository.vocapp202"}
)
public class VocApp202DbConfig extends HikariConfig {
#Primary
#Bean(name = "dataSource")
public DataSource dataSource() {
return new HikariDataSource(this);
}
What I'm missing?
spring.datasource.hikari.* (and also spring.datasource.url) properties will work only if you are using Spring Boot DataSource autoconfiguration. In order to achieve it, you need to remove this bean:
#Primary
#Bean(name = "dataSource")
public DataSource dataSource() {
return new HikariDataSource(this);
}
Spring Boot will create it for you automatically using all these properties. You can check DataSourceAutoConfiguration.class for more information.
If, for some reason, you cannot remove this bean (f.e., you have another bunch of datasources, and you need to create your manual datasource in order to mark it as #Primary), you can use "raw" properties to configure hikari. So, instead of removing dataSource() method, you should modify your properties by removing hikari. part:
...
spring.datasource.jdbc-url=jdbc:postgresql://VOC-APP202-db:5432/voice-app
...
spring.datasource.connectionTimeout=1000
spring.datasource.idleTimeout=30000
spring.datasource.maxLifetime=60000
spring.datasource.connectionTestQuery=SELECT * FROM table where id=1
spring.datasource.minimumIdle=1
spring.datasource.maximumPoolSize=5
spring.datasource.poolName=voiceapp-db-pool
spring.datasource.autoCommit=false
jdbc-url is also hikari-specific property, that's why it works now.
To summarize: properties without hikari. and with jdbc-url for manually created datasource beans, and properties with hikari. and url for Spring Boot DataSource autoconfiguration.
If you're already using application.properties file with hikari and datasource configuration, the moment you use new HikariDataSource(this) it will override your application.properties values.
You either create your HikariDataSource manually and remove from application.properties:
#Bean(name = "dataSource")
public DataSource dataSource() {
HikariDataSource hikariDataSource = new HikariDataSource();
hikariDataSource.setMaximumPoolSize(5);
hikariDataSource.setMaxLifetime(60000);
hikariDataSource.setMinimumIdle(1);
//.. some other configs
return hikariDataSource;
}
or use application.properties values only.
but something did not work with application.properties, so I now did:
DbConfig.class(es)
#Primary
#Bean(name = "dataSource")
public DataSource dataSource() {
HikariConfig config = new HikariConfig("/hikari_voiceapp.properties");
//HikariDataSource dataSource = new HikariDataSource(config);
return new HikariDataSource(config);
}
and specify all params to each database in separate hikari.properties file including the name of database:
hikari_asterisk.properties
hikari_billing.properties
hikari_voiceapp.properties
works for me.
To keep configuration in standard format, and still create DataSource explicitly, connection pool specific prefix can be used for configuration properties. This is the same what spring boot DataSourceConfiguration does when auto-configuration is used:
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource")
public DataSourceProperties dataSourceProperties() {
return new DataSourceProperties();
}
#Bean
#Primary
#ConfigurationProperties(prefix = "spring.datasource.hikari")
public HikariDataSource dataSource(DataSourceProperties properties) {
HikariDataSource dataSource = properties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
if (StringUtils.hasText(properties.getName())) {
dataSource.setPoolName(properties.getName());
}
return dataSource;
}
Sample application.yaml:
spring:
datasource:
url: jdbc:postgresql://localhost:5432/postgres?gssEncMode=disable
username: postgres
password: postgres
hikari:
minimumIdle: 0
maximumPoolSize: 50
idleTimeout: 90000
maxLifetime: 900000
connectionTimeout: 45000
leakDetectionThreshold: 45000
I used the following approach
second.datasource.jdbc-url=jdbc-url
second.datasource.username=username
second.datasource.password=password
.
.
.
.
=================== In Java Configuration File ==================
#Bean(name = "secondDataSource")
#ConfigurationProperties(prefix = "second.datasource")
public DataSource dataSource() {
return DataSourceBuilder.create().build();
}
#Bean(name = "secondEntityManagerFactory")
public LocalContainerEntityManagerFactoryBean barEntityManagerFactory(EntityManagerFactoryBuilder builder,
#Qualifier("secondDataSource") DataSource dataSource) {
Map<String, String> props = new HashMap<String, String>();
props.put("spring.jpa.database-platform", "org.hibernate.dialect.Oracle12cDialect");
.
.
.
return builder.dataSource(dataSource).packages("com.second.entity").persistenceUnit("secondDB")
.properties(props)
.build();
}
#Bean(name = "secondTransactionManager")
public PlatformTransactionManager secondTransactionManager(
#Qualifier("secondEntityManagerFactory") EntityManagerFactory secondEntityManagerFactory) {
return new JpaTransactionManager(secondEntityManagerFactory);
}

Why does Spring Boot app start when two #Bean methods are present for restTemplate

I have this dependency:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.2.0.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
</dependencies>
And I have this config:
#Configuration
public class AppConfig {
#Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
#Bean
public RestTemplate restTemplate(RestTemplateBuilder restTemplateBuilder) {
return restTemplateBuilder
.setConnectTimeout(ofMillis(3000))
.setReadTimeout(ofMillis(3000))
.build();
}
}
I wonder why Spring does not fail on start. It never inits first restTemplate but inits second one. I would expect Spring to fail.
This is a valid case, you are defining two bean definitions with same name of same bean, then the last bean defined will replace then first one bean defined.
If you want to an exception is thrown when two beans are defined by same name then you can configure by using setAllowBeanDefinitionOverriding(boolean allowBeanDefinitionOverriding) method from DefaultListableBeanFactory is who overrides whether it should be allowed to override bean definitions by registering a different definition with the same name.

Error creating bean with name 'gemfireCache': FactoryBean threw exception on object creation

I am trying to create an "employee" Region and put some data into it. But, I am getting Exception below:
[warn 2018/12/27 17:15:46.518 IST tid=0x1] Exception
encountered during context initialization - cancelling refresh
attempt: org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'gemfireConfiguration': Injection of
resource dependencies failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'gemfireCache': FactoryBean threw exception on
object creation; nested exception is java.lang.NoClassDefFoundError:
it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap
[warn 2018/12/27 17:15:46.519 IST tid=0x1] Invocation of
destroy method failed on bean with name 'gemfireCache':
org.apache.geode.cache.CacheClosedException: A cache has not yet been
created.
[error 2018/12/27 17:15:46.522 IST tid=0x1] Caught exception
while allowing TestExecutionListener
[org.springframework.test.context.web.ServletTestExecutionListener#c667f46]
to prepare test instance
[com.gemfire.demo.Gemfire1ApplicationTests#48bfb884]
Domain class
#Region("employee")
public class Employee {
#Id
public String name;
public double salary;
...
}
Repository class
#Repository
public interface EmployeeRepository extends CrudRepository<Employee, String> {
Employee findByName(String name);
}
Configuration class
#Configuration
#ComponentScan
#EnableGemfireRepositories(basePackages = "com.gemfire.demo")
public class GemfireConfiguration {
#Autowired
EmployeeRepository employeeRepository;
#Bean
Properties gemfireProperties() {
Properties gemfireProperties = new Properties();
gemfireProperties.setProperty("name", "SpringDataGemFireApplication");
gemfireProperties.setProperty("mcast-port", "0");
gemfireProperties.setProperty("log-level", "config");
return gemfireProperties;
}
#Bean
#Autowired
CacheFactoryBean gemfireCache() {
CacheFactoryBean gemfireCache = new CacheFactoryBean();
gemfireCache.setClose(true);
gemfireCache.setProperties(gemfireProperties());
return gemfireCache;
}
#Bean(name="employee")
#Autowired
LocalRegionFactoryBean<String, Employee> getEmployee(final GemFireCache cache) {
LocalRegionFactoryBean<String, Employee> employeeRegion = new LocalRegionFactoryBean<String, Employee>();
employeeRegion.setCache(cache);
employeeRegion.setClose(false);
employeeRegion.setName("employee");
employeeRegion.setPersistent(false);
employeeRegion.setDataPolicy(DataPolicy.PRELOADED);
return employeeRegion;
}
}
POM.XML
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.0.5.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
<exclusions>
<exclusion>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-to-slf4j</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.session</groupId>
<artifactId>spring-session-core</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-gemfire</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
<version>2.9.0</version>
</dependency>
Adding additional tips with your above GemFire/Spring JavaConfig configuration class above.
Given you are using Spring Data Kay (implied by your use of the Spring Boot 2.0.x parent POM, i.e. org.springframework.boot:spring-boot-dependencies; see here), then you could be using Spring Data GemFire's (relatively) new and convenient Annotation-based configuration model.
By doing so, your GemfireConfiguration class above would become...
#PeerCacheApplication
#EnableGemfireRepositories(basePackages = "com.gemfire.demo")
class GemfireConfiguration {
#Bean(name="employee")
LocalRegionFactoryBean<String, Employee> getEmployee(GemFireCache cache) {
LocalRegionFactoryBean<String, Employee> employeeRegion =
new LocalRegionFactoryBean<String, Employee>();
employeeRegion.setCache(cache);
employeeRegion.setClose(false);
employeeRegion.setDataPolicy(DataPolicy.PRELOADED);
return employeeRegion;
}
}
A few things to keep in mind:
#PeerCacheApplication is meta-annotated with #Configuration so you do not need the explicit Spring #Configuration annotation on the configuration class.
#PeerCacheApplication allows you to adjust the GemFire log-level (along with other logging configuration) using the logLevel annotation attribute. Similarly, you can set the log-level using the corresponding property, spring.data.gemfire.cache.log-level in a Spring Boot application.properties file (see here). There are many other attributes and corresponding properties (e.g. name) you can use to adjust and customize other configuration.
While String-based package names are supported on #EnableGemfireRepositories and similar annotations, we generally prefer and recommend users to use the type-safe variant basePacakgeClasses. You only need to refer to a single type from each top-level package where your application Repositories are kept.
The explicit #Autowired annotation is not needed on your bean definitions. You do not need to explicit inject the EmployeeRepository in the configuration class to have it initialized; just inject it into the #Service class where it will be used.
For convenience, the name ("employee") of the Region bean definition on your LOCAL "employee" Region, will also be used as the name of the Region, so employeeRegion.setName("employee") is unnecessary.
You should not combine LocalRegionFactoryBean.setPersistent(:boolean) with LocalRegionFactoryBean.setDataPolicy(:DataPolicy) since the DataPolicy is going to take precedence.
While #ComponentScan is perfectly acceptable and even convenient in development, I generally do not prefer nor recommend users to use component-scanning. It is usually always better to be explicit.
As stated in the comments, you chould remove <relativePath/> from your parent definition in your application Maven POM file.
Final note, as of this post, Spring Boot 2.0.8.RELEASE is the latest release.
As for your classpath issues, if you are using Maven correctly, then Maven should take care of pulling in the correct transitive dependencies.
You can refer to the many examples I have in this repo for further clarification.
Hope this helps!
As mentioned in comments, the error shows some dependencies (java.lang.NoClassDefFoundError: it/unimi/dsi/fastutil/ints/Int2ObjectOpenHashMap) are missing. Please add corresponding dependencies in your pom.xml

ConnectionFactory get destroyed before camel

I'm using spring-boot with camel and ActiveMQ.
I'm using activemq autoconfiguration via #EnableJms annotation.
But creating my own ActiveMQComponent to enable "transacted(true)" on all queues.
#Bean(name = "activemq")
#ConditionalOnClass(ActiveMQComponent.class)
public ActiveMQComponent activeMQComponent(ConnectionFactory connectionFactory) {
ActiveMQComponent activeMQComponent = new ActiveMQComponent();
activeMQComponent.setConnectionFactory(connectionFactory);
activeMQComponent.setTransacted(true);
activeMQComponent.setTransactionManager(jmsTransactionManager(connectionFactory));
return activeMQComponent;
}
It works well but when I try to gracefully shutdown the application.
The PooledConnectionFactory get destroyed before the camel graceful shutdown happens.
Leading to a tons of error and the route unable to correctly stops.
Like 20 times this error :
2017-05-04 18:21:59.748 WARN 12188 --- [er[test.queue]] o.a.activemq.jms.pool.PooledSession : Caught exception trying rollback() when putting session back into the pool, will invalidate. javax.jms.IllegalStateException: The Session is closed
Followed by:
2017-05-04 18:21:59.748 INFO 12188 --- [ Thread-18] o.a.camel.spring.SpringCamelContext : Apache Camel 2.18.3 (CamelContext: route) is shutting down
Then later :
2017-05-04 18:21:59.766 INFO 12188 --- [ - ShutdownTask] o.a.camel.impl.DefaultShutdownStrategy : Waiting as there are still 1 inflight and pending exchanges to complete, timeout in 300 seconds. Inflights per route: [test2 = 1]
Anyone can help me configuring spring-boot camel activemq all together with graceful shutdown ?
Thanks
Update :
Here is a sample of my pom.xml:
<properties>
<!-- Spring -->
<spring-boot.version>1.4.3.RELEASE</spring-boot.version>
<!-- Camel -->
<camel-spring-boot.version>2.18.3</camel-spring-boot.version>
</properties>
....
<!-- Camel BOM -->
<dependency>
<!-- Import dependency management from Spring Boot -->
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>${spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-dependencies</artifactId>
<version>${camel-spring-boot.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
...
<!-- Spring -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
<!-- ActiveMQ -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-activemq</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-camel</artifactId>
</dependency>
<dependency>
<groupId>org.apache.activemq</groupId>
<artifactId>activemq-pool</artifactId>
</dependency>
<!-- Camel -->
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot-starter</artifactId>
</dependency>
Update 2:
After further investigation and the creation of a new project adding every modification one by one I have isolated the problem.
The shutdown works correcly until I add a specific endpoint :
#EndpointInject(uri = "direct:aaa")
private Endpoint errorHandling;
Using :
private String errorHandling = "direct:aaa";
Doesn't produce the bug.
It seems like using #EndpointInject is making the activemq close first
Update 3 :
Found that SpringCamelContext is not implementing ApplicationListener and thus its method "onApplicationEvent" its not called handling the "shutdownEager" of camel.
Important thing is to use Camel Spring Boot Starter.
http://camel.apache.org/spring-boot.html
How to enable Camel auto-configuration in my Spring Boot application?
Just drop camel-spring-boot jar into your classpath:
<dependency>
<groupId>org.apache.camel</groupId>
<artifactId>camel-spring-boot</artifactId>
<version>${camel.version}</version> <!-- use the same version as your Camel core version -->
</dependency>
camel-spring-boot jar comes with the spring.factories file, so as soon as you add that dependency into your classpath, Spring Boot will automatically auto-configure the Camel for you. Yay! That was fast ;) .
Auto-configured Camel context
The most important piece of functionality provided by the Camel auto-configuration is the CamelContext instance.
Camel auto-configuration creates SpringCamelContext for your and take care of the proper initialization and shutdown of that context.
Created Camel context is also registered in the Spring application context (under camelContext bean name), so you can access it just as the any other Spring bean.
#Configuration
public class MyAppConfig {
#Autowired
CamelContext camelContext;
#Bean
MyService myService() {
return new DefaultMyService(camelContext);
}
}
Apparently since https://issues.apache.org/jira/browse/CAMEL-2607
the SpringCamelContext doesn't implement ApplicationListener interface anymore.
Since I'm using spring-boot autoconfiguration, I am not using CamelContextFactoryBean which is adding the listener.
Has a temporary fix, I created a component which listen to ApplicationEvent and dispatch them to the SpringCamelContext method :
public class SpringCamelContextFix implements ApplicationListener<ApplicationEvent> {
private SpringCamelContext camelContext;
public SpringCamelContextFix(SpringCamelContext camelContext) {
this.camelContext = camelContext;
}
#Override
public void onApplicationEvent(ApplicationEvent event) {
camelContext.onApplicationEvent(event);
}
}
I had this same problem running unit/integration tests with Spring Boot, ActiveMQ or A-MQ, and Camel (version 2.18.1.redhat-000012). Apparently, when Spring Boot shuts down, the JMS thread pool is closed before the Camel context is shutdown, which is the wrong order. #John D provided a code fix in a Camel users mailing list thread which is similar to what he provided in this thread. Here is the version of John D's code that worked for me:
#Component
public class SpringCamelContextFix implements
ApplicationListener<ApplicationEvent> {
#Inject
private SpringCamelContext camelContext;
public SpringCamelContextFix(SpringCamelContext camelContext) {
this.camelContext = camelContext;
}
#Override
public void onApplicationEvent(ApplicationEvent event) {
camelContext.onApplicationEvent(event);
}
}

Resources