I have configured a spring boot application which when run reads messages from the queue and processes them accordingly.
I also have configured the concurrency flag to run multiple such readers.
However in an ideal world i would like the receiver to keep running like a thread and keep checking for any messages.
My question is that whether there is any way i can configure this in spring boot or i have to fallback to using threading mechanism using executor or anything else.
Thanks,
- Vaibhav
I found a nice way from Spring Boot, the concurrency was of course taken case by concurrent attribute e.g.
#JmsListener(destination = "myqueue", concurrency="2-10")
However for the Thread part below was something which is a neat way:
#SpringBootApplication
#EnableAutoConfiguration(exclude={MongoAutoConfiguration.class, MongoDataAutoConfiguration.class})
#EnableJms
public class MyApplication implements CommandLineRunner{
public static void main(String[] args) {
SpringApplication.run(MyApplication.class, args);
}
#Override
public void run(String... arg0) throws Exception {
// TODO Auto-generated method stub
System.out.println("Joining Thread ctrl+c to bring down application");
Thread.currentThread().join();
}
}
Related
I'm successfully using Spring Cloud Sleuth in a Spring Boot microservice and am having fields logged and sent over http headers appropriately.
I now need to integrate this same process for logging and header propagation in a Spring Boot command line runner application but it looks like no trace and span are automatically setup since it isn't in the middle of an Http request (as it is a command line app). I cannot see these fields in my logs (with the same %X format in log configuration).
I've looked at the docs and can't find any examples for this specific use case. Is this possible in a command line runner app?
In order to add baggage you need to have a span. Spring Cloud Sleuth and Spring Boot create a span for you when the controller is invoked. If you want to do the same using CLI application, you need to create span yourself.
You have two options.
Using API calls:
Span span = this.tracer.nextSpan().name("mySpan");
// do some work
span.end(); // best to put it in finally to make sure span is always ended
Or you can use annotations:
#NewSpan
public void doWork() {
}
If you use the annotation, please keep in mind the AOP proxies limitations. In particular self invocations (calls using this) would not work.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Override
public void run(String... args) {
doWork(); //this is the same as this.doWork();
}
#NewSpan
public void doWork() {
}
}
This is not going to work as doWork is not invoked through the AOP proxy. Make sure that you annotate a component managed by Spring and then use an injected instance.
#SpringBootApplication
public class ConsoleApplication
implements CommandLineRunner {
#Autowired
private MyService myService;
#Override
public void run(String... args) {
myService.doWork();
}
}
#Component
class MyService {
#NewSpan
public void doWork() {
}
}
In this case myService is not instance of MyService, but rather an instrumented proxy.
I have Spring boot application AspectJ is configured to work async after one service returned data but this fails to triggers sometime only there is no error logs no warning, can this happen any time, please let me know if I have missed any conf?
Application code
#SpringBootApplication
#EnableAspectJAutoProxy
#EnableAsync
public class TitlesCompareUtilityApplication {
public static void main(String[] args) {
SpringApplication.run(TitlesCompareUtilityApplication.class, args);
}
}
Aspect code
#Aspect
#Component
public class DistributedLoggingAspect {
private static Logger log = LoggerFactory.getLogger(DistributedLoggingAspect.class);
#Async
#AfterReturning("execution(* com.mycomp.repo.TyRepository.findById(..))")
public void logAfterReturn(JoinPoint joinPoint) {
int id = (int) joinPoint.getArgs()[0];
log.info("logAfterReturn() is running! id:{}", id);
}
}
For technical reasons I find it highly unlikely, even next to impossible, that advice execution would sometimes be missed because when a public Spring bean/component method is called and an AOP proxy exists, this proxy will intercept the method call, unless you perform self-invocation (class-internal method call). Whether the advice is executed in the same or an asynchronous thread (if that is even possible), should not matter.
Instead, it is much more likely that due to the asynchronous nature of your application the log entries do not appear in the order you expect or that in a high-load scenario your logger buffer overruns (depending on your configuration) and log messages get lost before they can be written.
I would like to read data to List or Map from database on startup.
Which is the best way to do it? The Spring Boot version is 5.
Is the below solution is good?
#Component
public class ApplicationStartup
implements ApplicationListener<ApplicationReadyEvent> {
/**
* This event is executed as late as conceivably possible to indicate that
* the application is ready to service requests.
*/
#Override
public void onApplicationEvent(final ApplicationReadyEvent event) {
// here your code ...
return;
}
}
I'd like to storage data on static class, but I have doubt that is the best solution.
I don't quite understand what is your motive for doing so but for doing so you can create a bean using #Component and in that bean create a method with annotation #PostConstruct. you can do whatever you want in this method.
Using the ApplicationRunner interface is the best way to run code once the Spring boot context has loaded.
#Component
public class ApplicationStartup implements ApplicationRunner {
#Override
public void run(ApplicationArguments args) throws Exception {
}
}
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-spring-application.html#boot-features-command-line-runner
Spring Cloud Stream Dispatcher has no subscribers Error.
After a successful spring boot container start up we need to put few notification messages on a Kafka topic and several of our microservices does same function and for this reason we wrote a common jar that contains out put channel definitions and dispatch utils. And the functionality works as expected as long as we invoke the util right after the SpringApplication.run call.
Following is one of our microservices Application class sample.
#SpringBootApplication
public class Application {
public static void main(String[] args) {
ConfigurableApplicationContext context =SpringApplication.run(Application.class, args);
context.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
The above set up works as expected, however this puts unnecessary burden the developer to write the boiler template code on every microservice. So to avoid this, we wrote an Aspect implementation to do the same function, however with our aspect approach we are running into the following error.
org.springframework.context.ApplicationContextException: Failed to start bean 'outputBindingLifecycle'; nested exception is org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'schedulertestsvcs:dev:1180.scheduledJobExecutionResponseOutput'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
We tried several approaches like Spring SmartLifeCycle to get a handle on all Kafka Output/Input channel startup completion but all of them are running into the same error.
Following is our Aspect implementation on org.springframework.boot.SpringApplication.run(..)
#Aspect
#Component
public class SchedulerConsumerAspect {
#Autowired
protected ApplicationContext applicationContext;
#AfterReturning(value = "execution(* org.springframework.boot.SpringApplication.run(..))",returning = "result")
public void afterConsumerApplicationStartup(JoinPoint pjp, Object result) throws Throwable {
if(result!=null){
ConfigurableApplicationContext context=(ConfigurableApplicationContext) result;
if(context.containsBean("schedulerConsumerUtils")){
//For what ever reason the following call resulting in Dispatcher has no subscribers for channel error.
//TODO fix the above issue and enable the following call.
context.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
}
}
During our debug sessions, we found out org.springframework.boot.SpringApplication.run(..) Aspect was called several times during the bootstrap process. First when the aspect was called we got result value as null, after some time spring boot calls the same aspect this time result is not null. Even after getting result not null there is no grantee the component is completely initialized that's why you see a check for context.containsBean("schedulerConsumerUtils"). However after the bean initialization we are seeing output channels are not completely bound.
What is the best way to get handle on Spring Cloud Stream Kafka output/input channel binding completion ?
Why the component invocation works fine in SpringBoot Application but not through Aspect? I struggled on this few days couldn't find the right solution. Any help greatly appreciated.
I followed the suggestion from this post Spring cloud stream - send message after application initalization and used the 3rd option ApplicationRunner. The first two options didn't work for me.
#Component
public class AppStartup implements ApplicationRunner {
#Autowired
protected ApplicationContext applicationContext;
#Override
public void run(ApplicationArguments args) throws Exception {
if(applicationContext!=null){
applicationContext.getBean(SchedulerConsumerUtils.class).registerOrRestartConsumerJobs();
}
}
}
Is there a clean way to detect when a spring-boot application is stopped and perform some action before? Kind of CommandLineRunner for stopping a service
Thanks in advance
Similar to ApplicationReadyEvent you can use ContextClosedEvent:
#Component
public class ContextClosedEventListener {
#EventListener(ContextClosedEvent.class)
public void onContextClosedEvent(ContextClosedEvent contextClosedEvent) {
System.out.println("ContextClosedEvent occurred at millis: " + contextClosedEvent.getTimestamp());
}
}
I've come up with this solution. If you have better one, feel free to share
#Component
public class PortalServiceLifeCycle implements CommandLineRunner {
static final Logger LOGGER = LoggerFactory.getLogger(PortalServiceLifeCycle.class);
#Override
public void run(String... arg0) throws Exception {
LOGGER.info("###START FROM THE LIFECYCLE###");
}
#PreDestroy
public void onExit() {
LOGGER.info("###STOP FROM THE LIFECYCLE###");
}
}
Don't know if you have resolve this problem perfectly. I meet this issue recently, and have got a solution that a little different.
Firstly, my Spring boot Application is a Tomcat embedded one. (The second method of this issue doesn't depends on the web structure. don't mad, my friend.) In this case, it's naturally to get the idea of catch the stop event by register a listener. I do it like this,
#WebListener
public class HelloListener implements ServletContextListener {
#Override
public void contextInitialized(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextInitialized");
}
#Override
public void contextDestroyed(ServletContextEvent servletContextEvent) {
System.out.println("HelloListener contextDestroyed");
}
}
and, at the same time, add the annotation #ServletComponentScan on your Application class.
Surely, there are some other ways to register a ServletContextListener, and once you registered it, you can get the stop event in the contextDestroyed function.
BUT, that don't match my issue very much. I must catch the stop event BEFORE the Spring Beans being destroyed. And here comes the second solution.
modify your application main method like the follow:
SpringApplication application = new SpringApplication(DemoApplication.class);
application.addListeners(new MyListener());
application.run(args);
and provide the defination of class MyListener:
class MyListener implements ApplicationListener<ContextClosedEvent>{
#Override
public void onApplicationEvent(ContextClosedEvent contextClosedEvent) {
// your code here
}
}
NOTE: the second solution has nothing to do with Tomcat or other web container. The ContextClosedEvent isn't introduced in the Spring document, but I found it in the source, it's very useful i think.
I will be very glad if this can help some one.
It depends what you want to do but one thing you could do is have a bean that implements SmartLifecycle and implement the stop method. Whenever the context is being stopped, you'd get a callback. Note that it does not necessarily means that the process is shutting down. If you want to invoke some code when that happens, I'd register a shutdown hook as Sven wrote in a comment.