Why Spring Boot Application logs that it started twice after adding spring-cloud-bus dependency - spring-boot

This is simple code in my Spring boot application:
package com.maxxton.SpringBootHelloWorld;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class SpringBootHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloWorldApplication.class, args);
}
}
And a ApplicationListener class to listen to ApplicationEvent:
package com.maxxton.SpringBootHelloWorld;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
#Component
public class Test implements ApplicationListener {
#Override
public void onApplicationEvent(ApplicationEvent event) {
if (event.getClass().getSimpleName().equals("ApplicationReadyEvent")) {
System.out.println("-------------------------------------");
System.out.println(event.getClass().getSimpleName());
System.out.println("-------------------------------------");
}
}
}
build.gradle contains these dependencies:
dependencies {
compile("org.springframework.boot:spring-boot-starter-amqp")
compile("org.springframework.cloud:spring-cloud-starter-bus-amqp")
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter')
compile("org.springframework.cloud:spring-cloud-starter")
compile("org.springframework.cloud:spring-cloud-starter-security")
compile("org.springframework.cloud:spring-cloud-starter-eureka")
testCompile('org.springframework.boot:spring-boot-starter-test')
}
Now, when I run this spring boot application, I see this log printed twice:
[main] c.m.S.SpringBootHelloWorldApplication : Started SpringBootHelloWorldApplication in ... seconds (JVM running for ...)
Usually, this log get printed only once, but it get printed twice if I add these dependencies:
compile("org.springframework.boot:spring-boot-starter-amqp")
compile("org.springframework.cloud:spring-cloud-starter-bus-amqp")
This is complete log:
2017-11-17 15:44:07.372 INFO 5976 --- [ main] o.s.c.support.GenericApplicationContext : Refreshing org.springframework.context.support.GenericApplicationContext#31c7c281: startup date [Fri Nov 17 15:44:07 IST 2017]; root of context hierarchy
-------------------------------------
ApplicationReadyEvent
-------------------------------------
2017-11-17 15:44:07.403 INFO 5976 --- [ main] c.m.S.SpringBootHelloWorldApplication : Started SpringBootHelloWorldApplication in 1.19 seconds (JVM running for 10.231)
2017-11-17 15:44:09.483 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare exchange: Exchange [name=springCloudBus, type=topic, durable=true, autoDelete=false, internal=false, arguments={}], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:09.492 INFO 5976 --- [ main] o.s.integration.channel.DirectChannel : Channel 'a-bootiful-client.springCloudBusOutput' has 1 subscriber(s).
2017-11-17 15:44:09.493 INFO 5976 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'a-bootiful-client.errorChannel' has 1 subscriber(s).
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started _org.springframework.integration.errorLogger
2017-11-17 15:44:09.530 INFO 5976 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147482647
2017-11-17 15:44:09.539 INFO 5976 --- [ main] c.s.b.r.p.RabbitExchangeQueueProvisioner : declaring queue for inbound: springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ, bound to: springCloudBus
2017-11-17 15:44:11.562 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare exchange: Exchange [name=springCloudBus, type=topic, durable=true, autoDelete=false, internal=false, arguments={}], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:13.587 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare queue: Queue [name=springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ, durable=false, autoDelete=true, exclusive=true, arguments={}], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:15.611 WARN 5976 --- [ main] o.s.amqp.rabbit.core.RabbitAdmin : Failed to declare binding: Binding [destination=springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ, exchange=springCloudBus, routingKey=#], continuing... org.springframework.amqp.AmqpConnectException: java.net.ConnectException: Connection refused: connect
2017-11-17 15:44:17.662 INFO 5976 --- [ main] o.s.i.a.i.AmqpInboundChannelAdapter : started inbound.springCloudBus.anonymous.kZ1vvxHaRfChKe1TncH-MQ
2017-11-17 15:44:17.662 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {message-handler:inbound.springCloudBus.default} as a subscriber to the 'bridge.springCloudBus' channel
2017-11-17 15:44:17.662 INFO 5976 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started inbound.springCloudBus.default
2017-11-17 15:44:17.663 INFO 5976 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 2147483647
2017-11-17 15:44:17.714 INFO 5976 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 8080 (http)
-------------------------------------
ApplicationReadyEvent
-------------------------------------
2017-11-17 15:44:17.717 INFO 5976 --- [ main] c.m.S.SpringBootHelloWorldApplication : Started SpringBootHelloWorldApplication in 20.131 seconds (JVM running for 20.545)
As you can see, ApplicationReadyEvent is happening twice.
Why is this happening?
Is there any way to avoid this?

spring-cloud-bus uses spring-cloud-stream which puts the binder in a separate boot child application context.
You should make your event listener aware of the application context it is running in. You can also use generics to select the event type you are interested in...
#Component
public class Test implements ApplicationListener<ApplicationReadyEvent>,
ApplicationContextAware {
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
#Override
public void onApplicationEvent(ApplicationReadyEvent event) {
if (event.getApplicationContext().equals(this.applicationContext)) {
System.out.println("-------------------------------------");
System.out.println(event.getClass().getSimpleName());
System.out.println("-------------------------------------");
}
}
}

Are u using multiple binders rabbitmq configuration in your application.yml/.xml ?
If it's a yes, then u can try to exclude RabbitAutoConfiguration.
#EnableDiscoveryClient
#EnableAutoConfiguration(exclude = {RabbitAutoConfiguration.class})
#SpringBootApplication
public class SpringBootHelloWorldApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootHelloWorldApplication.class, args);
}
}

Related

I'm still getting a Whitelabel error even though there is no error in my IDE

I'm still getting an error even though there is no error in my IDE
package com.example.demo;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
#SpringBootApplication
#RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
#GetMapping
public List<String> hello(){
return List.of("hello", "world");
}
}
:: Spring Boot :: (v3.0.0-SNAPSHOT)
2022-08-26T08:32:07.263+08:00 INFO 10580 --- [ main] com.example.demo.DemoApplication : Starting DemoApplication using Java 17.0.4.1 on DESKTOP-53LAED9 with PID 10580 (C:\Users\Larty\Desktop\Programming Softwares\Springsss\demo\demo\target\classes started by Larty in C:\Users\Larty\Desktop\Programming Softwares\Springsss\demo\demo)
2022-08-26T08:32:07.276+08:00 INFO 10580 --- [ main] com.example.demo.DemoApplication : No active profile set, falling back to 1 default profile: "default"
2022-08-26T08:32:10.093+08:00 INFO 10580 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8060 (http)
2022-08-26T08:32:10.120+08:00 INFO 10580 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2022-08-26T08:32:10.121+08:00 INFO 10580 --- [ main] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.0.22]
2022-08-26T08:32:10.428+08:00 INFO 10580 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2022-08-26T08:32:10.434+08:00 INFO 10580 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 3010 ms
2022-08-26T08:32:11.412+08:00 INFO 10580 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8060 (http) with context path ''
2022-08-26T08:32:11.435+08:00 INFO 10580 --- [ main] com.example.demo.DemoApplication : Started DemoApplication in 5.245 seconds (process running for 6.304)
More info that caused the error:
I change my port to 8060 cause I'm getting an error from 8080.
Try specify a path:
#GetMapping("/")
// or this syntax
#GetMapping(path = "/")
If you want to have more control over request mapping, you can take a look at #RequestMapping annotation.
BTW, the port is running at 8060, accessing http://localhost:8060 should return the list of Strings.

JobParametersValidator.validate() method parameters returns null in spring batch

I am writing simple helloworld application in spring batch, and I'm trying to validate the JobParameters with custom implementation of JobParametersValidator.
public class ParameterValidator implements JobParametersValidator{
#Override
public void validate(JobParameters parameters) throws JobParametersInvalidException {
//String parameter = parameters.getParameters().get("outputText");
System.out.println("jobparameters are ............ " + parameters);
//System.out.println("parameter is " + parameter);
//if(!StringUtils.hasText(parameter)) {
throw new JobParametersInvalidException("Parameter is missing.........");
//}
}
}
But when I tried to Sysout the JobParameters inside the validate method, parameters return null.
Here is my console out.
2021-11-26 10:06:32.457 INFO 11912 --- [ restartedMain] com.pack.SpringBatchDemo2Application : Starting SpringBatchDemo2Application using Java 16.0.2 on DESKTOP-T1L7IA7 with PID 11912 (D:\Workspace\EclipseWorkspaceSpringPractise\SpringBatchDemo2\target\classes started by arepa in D:\Workspace\EclipseWorkspaceSpringPractise\SpringBatchDemo2)
2021-11-26 10:06:32.458 INFO 11912 --- [ restartedMain] com.pack.SpringBatchDemo2Application : No active profile set, falling back to default profiles: default
2021-11-26 10:06:32.536 INFO 11912 --- [ restartedMain] .e.DevToolsPropertyDefaultsPostProcessor : Devtools property defaults active! Set 'spring.devtools.add-properties' to 'false' to disable
2021-11-26 10:06:33.575 INFO 11912 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Starting...
2021-11-26 10:06:33.784 INFO 11912 --- [ restartedMain] com.zaxxer.hikari.HikariDataSource : HikariPool-1 - Start completed.
2021-11-26 10:06:33.920 INFO 11912 --- [ restartedMain] o.s.b.c.r.s.JobRepositoryFactoryBean : No database type set, using meta data indicating: POSTGRES
2021-11-26 10:06:34.262 INFO 11912 --- [ restartedMain] o.s.b.c.l.support.SimpleJobLauncher : No TaskExecutor has been set, defaulting to synchronous executor.
2021-11-26 10:06:34.484 INFO 11912 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2021-11-26 10:06:34.539 INFO 11912 --- [ restartedMain] com.pack.SpringBatchDemo2Application : Started SpringBatchDemo2Application in 2.596 seconds (JVM running for 4.056)
2021-11-26 10:06:34.544 INFO 11912 --- [ restartedMain] o.s.b.a.b.JobLauncherApplicationRunner : Running default command line with: []
jobparameters are ............ {}
2021-11-26 10:06:34.713 INFO 11912 --- [ restartedMain] ConditionEvaluationReportLoggingListener :
Error starting ApplicationContext. To display the conditions report re-run your application with 'debug' enabled.
2021-11-26 10:06:34.756 ERROR 11912 --- [ restartedMain] o.s.boot.SpringApplication : Application run failed
Here is my Job creation code.
#Component
public class HelloWorldJob {
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
public Step step() {
Tasklet tasklet = (contribution, chunkContext) -> {
return RepeatStatus.FINISHED;
};
return this.stepBuilderFactory.get("step1")
.tasklet(tasklet).build();
}
#Bean
public Job job() {
return this.jobBuilderFactory.get("job1").start(step()).validator(new ParameterValidator()).build();
}
}
Here is my code for triggering jobs.
#Component
public class TriggerJobLauncher {
#Autowired
private JobLauncher launcher;
#Autowired
private Job job;
public void triggerJob() throws JobExecutionAlreadyRunningException,
JobRestartException,
JobInstanceAlreadyCompleteException,
JobParametersInvalidException {
JobParameters parameters = new JobParametersBuilder().addParameter("aa", new JobParameter("Hello World")).toJobParameters();
launcher.run(job, parameters);
}
}

Connect limits service to spring cloud config server failed

i would like ask your help regarding the above question.Now I am trying to connect application (SpringCloudConfigServer) with another application (Limits-service), Limits-service application have to pick the SpringCloudConfigServer properties file. when I hit http://localhost:8080/limits i need to get oupput like {"maximum":888,"minimum":8} but im getting {"maximum":999,"minimum":99}
this is my stack trace
2020-04-29 22:51:23.740 INFO 2016 --- [ restartedMain] c.c.c.ConfigServicePropertySourceLocator : Fetching config from server at :` http://localhost:8888
2020-04-29 22:51:25.063 INFO 2016 --- [ restartedMain] c.c.c.ConfigServicePropertySourceLocator : Connect Timeout Exception on Url - http://localhost:8888. Will be trying the next url if available
2020-04-29 22:51:25.074 WARN 2016 --- [ restartedMain] c.c.c.ConfigServicePropertySourceLocator : Could not locate PropertySource: I/O error on GET request for "http://localhost:8888/limits-service/dev": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
2020-04-29 22:51:25.074 INFO 2016 --- [ restartedMain] c.i.m.l.LimitsServiceApplication : The following profiles are active: dev
2020-04-29 22:51:27.792 INFO 2016 --- [ restartedMain] o.s.cloud.context.scope.GenericScope : BeanFactory id=fe72d2a0-4692-3641-b317-8a12c5b9eb59
2020-04-29 22:51:29.065 INFO 2016 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port(s): 8080 (http)
2020-04-29 22:51:29.099 INFO 2016 --- [ restartedMain] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2020-04-29 22:51:29.099 INFO 2016 --- [ restartedMain] org.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/9.0.33]
2020-04-29 22:51:29.349 INFO 2016 --- [ restartedMain] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring embedded WebApplicationContext
2020-04-29 22:51:29.349 INFO 2016 --- [ restartedMain] o.s.web.context.ContextLoader : Root WebApplicationContext: initialization completed in 4166 ms
2020-04-29 22:51:30.477 INFO 2016 --- [ restartedMain] o.s.s.concurrent.ThreadPoolTaskExecutor : Initializing ExecutorService 'applicationTaskExecutor'
2020-04-29 22:51:31.571 INFO 2016 --- [ restartedMain] o.s.b.d.a.OptionalLiveReloadServer : LiveReload server is running on port 35729
2020-04-29 22:51:31.941 INFO 2016 --- [ restartedMain] o.s.b.a.e.web.EndpointLinksResolver : Exposing 2 endpoint(s) beneath base path '/actuator'
2020-04-29 22:51:32.269 INFO 2016 --- [ restartedMain] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port(s): 8080 (http) with context path ''
2020-04-29 22:51:32.627 INFO 2016 --- [ restartedMain] c.i.m.l.LimitsServiceApplication : Started LimitsServiceApplication in 12.155 seconds (JVM running for 14.055)
2020-04-29 22:51:39.114 INFO 2016 --- [nio-8080-exec-1] o.a.c.c.C.[Tomcat].[localhost].[/] : Initializing Spring DispatcherServlet 'dispatcherServlet'
2020-04-29 22:51:39.115 INFO 2016 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Initializing Servlet 'dispatcherServlet'
2020-04-29 22:51:39.151 INFO 2016 --- [nio-8080-exec-1] o.s.web.servlet.DispatcherServlet : Completed initialization in 35 ms
here is my limits service code
package com.in28minutes.microservices.limitsservice;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class LimitsServiceApplication {
public static void main(String[] args) {
SpringApplication.run(LimitsServiceApplication.class, args);
}
}
`controller
package com.in28minutes.microservices.limitsservice;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.in28minutes.microservices.limitsservice.bean.LimitConfiguration;
#RestController
public class LimitsConfigurationController {
#Autowired
private Configuration configuration;
#GetMapping("/limits")
public LimitConfiguration retrieveLimitsFromConfigurations() {
return new LimitConfiguration(configuration.getMaximum(),
configuration.getMinimum());
}
}
component class
package com.in28minutes.microservices.limitsservice;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
#Component
#ConfigurationProperties("limits-service")
public class Configuration {
private int minimum;
private int maximum;
public int getMinimum() {
return minimum;
}
public int getMaximum() {
return maximum;
}
public void setMinimum(int minimum) {
this.minimum = minimum;
}
public void setMaximum(int maximum) {
this.maximum = maximum;
}
}
Bean class
package com.in28minutes.microservices.limitsservice.bean;
public class LimitConfiguration {
private int maximum;
private int minimum;
protected LimitConfiguration() {
}
public LimitConfiguration(int maximum, int minimum) {
super();
this.maximum = maximum;
this.minimum = minimum;
}
public int getMaximum() {
return maximum;
}
public int getMinimum() {
return minimum;
}
}
bootstrap.properties
spring.application.name=limits-service
spring.cloud.config.server.uri=http://localhost:8888
/git-localconfig-repo/limits-service.properties
limits-service.minimum=8
limits-service.maximum=888
please help me how to fix this
It looks like your config server call fails. That is why you are not able to load properties from config server but from your service local config file
Could not locate PropertySource: I/O error on GET request for "http://localhost:8888/limits-service/dev": Connection refused: connect; nested exception is java.net.ConnectException: Connection refused: connect
2020-04-29 22:51:25.074 INFO 2016 --- [ restartedMain] c.i.m.l.LimitsServiceApplication : The following profiles are active: dev
In your /git-localconfig-repo/limits-service.properties
add spring.cloud.config.server.git.uri=file:/git-localconfig-repo/limits-service

TCP Client Spring Integration with Java Config

I am attempting to create a TCP client to connect to a remote tcp server and wait to receive messages. So far I have the following code:
#EnableIntegration
#IntegrationComponentScan
#Configuration
public class TcpClientConfig {
#Bean
public TcpInboundGateway tcpInbound(AbstractClientConnectionFactory connectionFactory) {
TcpInboundGateway gate = new TcpInboundGateway();
gate.setConnectionFactory(connectionFactory);
gate.setClientMode(false);
gate.setRequestChannel(fromTcp());
return gate;
}
#Bean
public MessageChannel fromTcp() {
return new DirectChannel();
}
#MessageEndpoint
public static class Echo {
#Transformer(inputChannel = "fromTcp", outputChannel = "serviceChannel")
public String convert(byte[] bytes) {
return new String(bytes);
}
}
#ServiceActivator(inputChannel = "serviceChannel")
public void messageToService(String in) {
System.out.println(in);
}
#Bean
public EndOfLineSerializer endOfLineSerializer() {
return new EndOfLineSerializer();
}
#Bean
public AbstractClientConnectionFactory clientConnectionFactory() {
TcpNetClientConnectionFactory tcpNetServerConnectionFactory = new TcpNetClientConnectionFactory("192.XXX.XXX.XX", 4321);
tcpNetServerConnectionFactory.setSingleUse(false);
tcpNetServerConnectionFactory.setSoTimeout(300000);
tcpNetServerConnectionFactory.setDeserializer(endOfLineSerializer());
tcpNetServerConnectionFactory.setSerializer(endOfLineSerializer());
tcpNetServerConnectionFactory.setMapper(new TimeoutMapper());
return tcpNetServerConnectionFactory;
}
}
It starts up and connects to the remote server. However, I am not receiving any data in my serviceActivator method messageToService. To assure that data exists, I can successfully connect to my remote tcp server using telnet
telnet 192.XXX.XXX.XX 4321
Trying 192.XXX.XXX.XX...
Connected to 192.XXX.XXX.XX.
Escape character is '^]'.
Hello World
I have confirmed nothing is hitting my EndOfLineSerializer. What is wrong with my TCP client?
Bonus: Let's assume the hostname and port are determined by querying an API. How would I tell the TcpNetClientConnectionFactory to wait to try to connect until I have the correct data for the port?
Debug output:
main] o.s.j.e.a.AnnotationMBeanExporter : Registering beans for JMX exposure on startup
2018-11-22 23:00:46.182 DEBUG 35953 --- [ main] o.s.j.e.a.AnnotationMBeanExporter : Autodetecting user-defined JMX MBeans
2018-11-22 23:00:46.194 DEBUG 35953 --- [ main] .s.i.c.GlobalChannelInterceptorProcessor : No global channel interceptors.
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase -2147483648
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.channel.PublishSubscribeChannel : Channel 'application.errorChannel' has 1 subscriber(s).
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started _org.springframework.integration.errorLogger
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean '_org.springframework.integration.errorLogger'
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {service-activator:tcpClientConfig.messageToService.serviceActivator} as a subscriber to the 'serviceChannel' channel
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.serviceChannel' has 1 subscriber(s).
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started tcpClientConfig.messageToService.serviceActivator
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'tcpClientConfig.messageToService.serviceActivator'
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : Adding {transformer:tcpClientConfig.Echo.convert.transformer} as a subscriber to the 'toTcp' channel
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.integration.channel.DirectChannel : Channel 'application.toTcp' has 1 subscriber(s).
2018-11-22 23:00:46.198 INFO 35953 --- [ main] o.s.i.endpoint.EventDrivenConsumer : started tcpClientConfig.Echo.convert.transformer
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'tcpClientConfig.Echo.convert.transformer'
2018-11-22 23:00:46.198 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Starting beans in phase 0
2018-11-22 23:00:46.199 INFO 35953 --- [ main] .s.i.i.t.c.TcpNetClientConnectionFactory : started clientConnectionFactory, host=192.XXX.XXX.90, port=4321
2018-11-22 23:00:46.199 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'clientConnectionFactory'
2018-11-22 23:00:46.199 INFO 35953 --- [ main] .s.i.i.t.c.TcpNetClientConnectionFactory : started clientConnectionFactory, host=192.XXX.XXX.90, port=4321
2018-11-22 23:00:46.199 INFO 35953 --- [ main] o.s.i.ip.tcp.TcpInboundGateway : started tcpInbound
2018-11-22 23:00:46.199 DEBUG 35953 --- [ main] o.s.c.support.DefaultLifecycleProcessor : Successfully started bean 'tcpInbound'
When using a client connection factory with an inbound endpoint there is no stimulus to open a connection (client factories are normally used for outbound operations and the connection is established when the first message is sent).
When used in this mode, you need setClientMode(true). This starts a task that opens (and monitors) an outbound connection.
See the documentation
Normally, inbound adapters use a type="server" connection factory, which listens for incoming connection requests. In some cases, you may want to establish the connection in reverse, such that the inbound adapter connects to an external server and then waits for inbound messages on that connection.
This topology is supported by setting client-mode="true" on the inbound adapter. In this case, the connection factory must be of type client and must have single-use set to false.
Two additional attributes support this mechanism. retry-interval specifies (in milliseconds) how often the framework attempts to reconnect after a connection failure. scheduler supplies a TaskScheduler to schedule the connection attempts and to test that the connection is still active.
(The framework provides a default scheduler).
For your Bonus question, you would need to find the host/port before creating the application context; or create the connection factory and gateway dynamically after you have the information.

CamelContextStartedEvent called twice

The CamelContextStartedEvent is called twice for the same camel context (camel-1). The issue might be the way I register the EventNotifier. You can reproduce the issue with Spring Initializr with Spring Boot 1.5.14, Spring Boot Camel Starter 2.21.1 and Spring Boot Web Starter.
See the logs:
2018-07-06 11:04:41.104 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) is starting
2018-07-06 11:04:41.106 INFO 19092 --- [ main] o.a.c.m.ManagedManagementStrategy : JMX is enabled
2018-07-06 11:04:41.191 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : StreamCaching is not in use. If using streams then its recommended to enable stream caching. See more details at http://camel.apache.org/stream-caching.html
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.boot.RoutesCollector : Starting CamelMainRunController to ensure the main thread keeps running
2018-07-06 11:04:41.193 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Total 0 routes, of which 0 are started
2018-07-06 11:04:41.194 INFO 19092 --- [ main] o.a.camel.spring.SpringCamelContext : Apache Camel 2.21.1 (CamelContext: camel-1) started in 0.090 seconds
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.195 INFO 19092 --- [ main] c.e.bug.service.StartupEventNotifier : CamelContextStartedEvent for SpringCamelContext(camel-1) with spring id application:11223
2018-07-06 11:04:41.216 INFO 19092 --- [ main] s.b.c.e.t.TomcatEmbeddedServletContainer : Tomcat started on port(s): 11223 (http)
2018-07-06 11:04:41.221 INFO 19092 --- [ main] com.example.bug.BugApplication : Started BugApplication in 4.684 seconds (JVM running for 6.773)
The service that initializes the EventNotifier:
#Service
public class SchedulerService {
private final CamelContext camelContext;
private final StartupEventNotifier startupEventNotifier;
public SchedulerService(CamelContext camelContext, StartupEventNotifier startupEventNotifier) {
this.camelContext = camelContext;
this.startupEventNotifier = startupEventNotifier;
}
#PostConstruct
public void init() {
camelContext.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
}
The EventNotifier:
#Component
public class StartupEventNotifier extends EventNotifierSupport {
private static final Logger logger = LoggerFactory.getLogger(StartupEventNotifier.class);
#Override
public void notify(EventObject event) throws Exception {
if (event instanceof CamelContextStartedEvent) {
logger.info("CamelContextStartedEvent for {}", event.getSource());
}
}
#Override
public boolean isEnabled(EventObject event) {
if (event instanceof CamelContextStartedEvent) {
return true;
}
return false;
}
}
application.yml:
camel:
springboot:
main-run-controller: true
server:
port: 11223
It is called twice, because it is registered twice. Once by you and once by Apache Camel. EventNotifier is registered automatically, if is found in Registry. Since your StartupEventNotifier is annotated as Component, it is part of Registry and Apache Camel registered it during CamelContext startup (You can see it in CamelAutoConfiguration line 424).
You have four options:
Remove your custom registration from SchedulerService.
Remove #Component annotation from StartupEventNotifier and register it with with camelContext.getManagementStrategy().addEventNotifier(new StartupEventNotifier())
Add duplicity check to your SchedulerService. Something like:
if (!context.getManagementStrategy().getEventNotifiers().contains(startupEventNotifier)){
context.getManagementStrategy().addEventNotifier(startupEventNotifier);
}
Register EventNotifier in #PostConstruct of RouteBuilder. It will be registered before automatic discovery is started and then it will be skipped in CamelAutoConfiguration (See line 422)

Resources