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();
}
}
}
Related
The applicationContext vs beanFactory seems to be very popular job interview question.
Is there any real use case to call applicationContext.getBean(foo.class) or beanFactory.getBean(foo.class) explicitly in Spring Boot?
I have read some tutorials explaining the difference between ApplicationContext and BeanFactory, but I still don't see the real use-case. Why would any developer call getBean() explicitly?
BeanFactory is the parent interface that exposes all the basic methods of the spring container, which are closely related with beans (getBean(), containsBean(), isPrototype()...)
Here a common scenario where it could be used, is for example in the main static method that spring boot starts, in case you want to do some action after the initialization of spring container has finished. Considering that you are inside a static method autowiring will not work. But with this BeanFactory you are able to manually do such action.
Example
#SpringBootApplication
public class ServiceLauncher {
public static void main(String[] args) {
BeanFactory beanFactory = SpringApplication.run(ServiceLauncher.class, args);
//At this point the Spring Beans Context has been loaded
Activity activity = beanFactory.getBean(Activity.class); //So we are able to retrieve from the context a bean to do in this static class some more actions.
activity.doSomething();
}
}
ApplicationContext is an interface extending the above BeanFactory interface. It could be used again in the above scenario, but the reason it exists is that it exposes some more useful methods which could provide some extra functionality when needed. More commonly used are some interfaces that extend the ApplicationContext. Example the ConfigurableApplicationContext.
Here common scenarios used are the refresh() of applicationContext,
close() which closes the application context and also the registering of a shutdown hook when terminating with registerShutdownHook().
Basically the registerShutdownHook() is commonly used because when the JVM is asked to terminate maybe you want to do a graceful shutdown, where the application context will not be closed immediately but will give you some control during shutdown.
#Component
public class Activity implements DisposableBean {
#Override
public void destroy() throws Exception {
System.out.println("Destroying Activity component shutting down!!!");
}
}
and you register the hook with
#SpringBootApplication
public class ServiceLauncher {
public static void main(String[] args) {
ConfigurableApplicationContext context = SpringApplication.run(ServiceLauncher.class, args);
context.registerShutdownHook();
}
}
Those are just some of the most common uses I have seen in several applications and projects. But each separate method exposed by some interface could have it's own use case and that's why it exists there. I am confident though that just for interview questions, the interviewer will have in his mind the above 2 scenarios.
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 have this
#Bean public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
// use a lambda expression to define a CommandLineRunner
return args -> {
... work ...
};
}
which is invoked like this
SpringApplication app = new SpringApplication(MyApp.class);
app.run(args); // perform configuration magic and invoke the above lambda function
This works great as long as the application was only used from the CLI. Now, the application is going through some refactoring to support a new run-time platform, and now I would like to do this:
app.run(complexOject); // pseudo-code, no such method in SpringApplication
i.e. I need to pass an ComplexObject to the application, while still preserving all the magic auto-configuration.
How can this be accomplished? Solutions with the least amount of code change are preferred.
The refactoring steps to enable a CommandLineRunner to receive arbitrary parameters is roughly as follows:
Move the guts (the ... work ... part) of the commandLineRunner method to a new method in a new bean class e.g. #Component public class GenericRunner { public void run(String ... args) ... }.
This is the most important step: Delete the original CommandLineRunner #Bean definition in its entirety. This will cause the application's run() method to exit after performing configuration.
Replace the app.run(args); invocation with the following
ConfigurableApplicationContext ctx = app.run(); // oh yeah
GenericRunner runner = ctx.getBean(GenericRunner.class);
runner.run(args);
Re-run all tests, commit the code changes.
The actual refactoring is now trivial: modify the runner.run(args) call at will. This is just a straight call into the GenericRunner POJO and is free of SpringBoot rules and limitations.
SpringApplication class obviously doesn't have a method that gets this output stream, its an entry point to the complicated by very powerful spring boot application loading process.
If the goal is to store the log of the application consider logging configuration rather than using output streams.
Otherwise please describe the requirement, what is the purpose of this output stream and I'll do my best to update this answer.
Update:
SpringApplication starts up an application context that is used as a registry for spring beans in the application.
So the most "spring friendly solution is to define a ComplexObject to be a spring bean, so that it will be injected into other beans that might need it.
This will work great if this bean can be created during the application startup.
Example:
class ComplexObject {...}
class ServiceThatMaintainsAReferenceOnObject {
private ComplexObject complexObject;
// all arg constructor
}
#Configuration
class SpringConfiguration {
#Bean
public ComplexObject complexObject() {
return new ComplexObject();
}
#Bean
public ServiceThatMaintainsAReferenceOnObject service(ComplexObject complexObject) {
return new ServiceThatMaintainsAReferenceOnObject(complexObject);
}
}
Now, if this complex object has to be created outside the spring application, maybe you need to pass it to some bean method as a parameter, after the application context is created. This can also be a case in the question, although it's definitely not a Spring way to do things.
Here is an example:
class ComplexObject {}
class Service {
void foo(ComplexObject complexObject);
}
#Configuration
class MyConfiguration {
#Bean
public Service service() {
return new Service();
}
}
// inside the main class of the application:
SpringApplication app = ...
ComplexObject complexObject = ... // get the object from somewhere
ApplicationContext ctx = app.run(args);
// by this time, the context is started and ready
Service service = ctx.getBean(Service.class);
service.foo(complexObject); // call the method on bean managed by spring
All in all, usually the second approach is not a regular use case of spring application, although its kind of feels like you're looking for something like this in the question.
All-in-all I think you should learn and understand how Spring works in a nutshell, and what exactly the ApplicationContext is to provide the best solution (I'm sorry for mentioning this, I said so because from the question it looks like you haven't really worked with Spring and don't really understand what does it do and how does it manage the application).
I'm trying to use Spring Cloud Stream to publish and consume Kafka messages. I've been working off of the documentation here on Accessing Bound Channels. I'm trying to use a custom name on the channel for my topic, so I have a #Qualifier when I'm trying to inject it, but spring can't find the relevant bean. It says "For each bound interface, Spring Cloud Stream will generate a bean that implements the interface", but the auto-wiring isn't working.
The error I'm getting is "Parameter 0 of constructor in com...MessagingManager required a bean of type 'org.springframework.messaging.MessageChannel' that could not be found."
I tried using #Autowired before the MessagingManager constructor like in the example, but then got a similar error in bean factory about there being 2 of them, so I took it out, and got the current error.
It's probably complicated by my trying to use a Processor.
Here are my components. I'm running it with spring boot and trying to test it with this :
#Component
public class StartupTester implements ApplicationListener<ContextRefreshedEvent> {
MessagingManager messagingManager;
#Override
public void onApplicationEvent(ContextRefreshedEvent event) {
messagingManager.sendThingCreatedMessage(new ThingCreated("12345", "667788"));
}
}
#Component
public class MessagingManager {
private MessageChannel thingCreatedChannel;
public MessagingManager(#Qualifier(ThingChannelProcessor.THING_CREATED) MessageChannel output) {
thingCreatedChannel = output;
}
public void sendThingCreatedMessage(ThingCreated thingCreated) {
thingCreatedChannel.send(MessageBuilder.withPayload(thingCreated).build());
}
}
#Component
public interface ThingsChannelProcessor extends Processor {
String THING_REQUEST = "thing-request";
String THING_CREATED = "thing-created";
#Input(THING_REQUEST )
SubscribableChannel thingsRequest();
#Output(THING_CREATED )
MessageChannel thingCreated();
}
And I also have #EnableBinding(ThingsMessagingManager.class) on my main class which is annotated with #SpringBootApplication.
I could not reproduce your error. But I have a few points you could follow:
You don't need to annotate the interface with #Component
It seems that you have a typo on your #EnableBinding you should have #EnableBinding(ThingsChannelProcessor.class) not ThingsMessagingManager
You don't need to extend Processor either, that may be the reason why you got 2 beans in the first time. If you are customizing your channels, you don't need to descend from Sink/Source/Processor, look at the Barista example in the docs
Listen for an contextRefresh won't work either, as we do the binding after the context was refreshed
Actually, let me a bit more clear on 4. We create a child context, so in order to make sure that your context has fully initialized, make sure you also implement ApplicationContextAware on your Starter, and before sending the message check if the contexts are the same otherwise you will get an error if(this.context.equals(event.getApplicationContext()))
So I've got a Runnable class that should invoke the method notifyUser(String username, String content) once a certain criteria is met. I've been trying to get this to work but it always fails with NullPointerExceptions. This has most likely to do with an Autowiring failure (since the Runnable class is not managed by Spring). Autowiring SimpMessagingTemplate in a Spring-managed context works just fine and the methods do what they're supposed to.
What I want to do is to invoke the method (or a similar method) convertAndSendToUser of the SimpMessagingTemplate, but I cannot autowire it in this context. Everything I've tried failed so far, which is why I assume I got some of the basic concepts wrong.
My Configuration looks like this:
#Configuration
#EnableScheduling
#EnableWebSocketMessageBroker
public class WebSocketConfig extends AbstractWebSocketMessageBrokerConfigurer {
#Override
public void configureMessageBroker(MessageBrokerRegistry config) {
config.enableSimpleBroker("/test");
config.setApplicationDestinationPrefixes("/app");
}
#Override
public void registerStompEndpoints(StompEndpointRegistry registry) {
registry.addEndpoint("/test").withSockJS();
}
}
Update: I've managed to get rid of the NullPointerException by using the following code .. but messages (convertAndSendToUser() as well as convertAndSend()) don't get picked up by the client. The developer console doesn't show any incoming messages.
AbstractApplicationContext ctx = new AnnotationConfigApplicationContext(Application.class);
ctx.getAutowireCapableBeanFactory().autowireBean(myService);
That's true because you do this:
new AnnotationConfigApplicationContext(Application.class);
in that your class, meaning starting a new full appicationContext. But your user is registered in the another context.
It isn't clear why you can't make your component managed by Spring, but there is no other way to use SimpMessagingTemplate, if you can't reach applicationContext.
It would be better to share that your code to investigate from our side and decide how can we help there.
Maybe you can use there WebApplicationContextUtils...