why can't spring find the #Source bean channel created by spring cloud stream? - spring-boot

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()))

Related

Wiring multiple beans with the same dependency via Spring Boot #Configuration

In older Spring MVC apps, where you'd specify application.xml and declare your app's beans so that Spring DI could instantiate them and wire them together, you might have something like this:
<bean id="chargeFactory" class="com.example.myapp.ChargeFactory" />
<bean id="paymentService" class="com.example.myapp.DefaultPaymentService">
<ref id="chargeFactory"/>
</bean>
<bean id="chargeAuditor" class="com.example.myapp.ChargeAuditor">
<ref id="chargeFactory"/>
</bean>
Which might help wire up the following code:
public interface PaymentService {
public void makePayment(Payment payment);
}
public class DefaultPaymentService implements PaymentService {
#Autowired
private ChargeFactory chargeFactory;
#Override
public void makePayment(Payment payment, String key) {
Charge charge = chargeFactory.createCharge(key);
charge.doCharge(payment);
}
}
public class ChargeAuditor {
#Autowired
private ChargeFactory chargeFactory;
public void auditAllCharges(String key) {
List<Charge> charges = chargeFactory.getAllCharges(key);
// blah whatever
}
}
How do you accomplish the same bean wiring in Spring Boot with the #Configuration class? For example:
#Configuration
public class MyAppInjector {
#Bean
public ChargeFactory chargeFactory() {
return new ChargeFactory();
}
#Bean
public PaymentService paymentService() {
return new DefaultPaymentService(chargeFactory());
}
#Bean
public ChargeAuditor chargeAuditor() {
return new ChargeAuditor(chargeFactory());
}
}
This might work but introduces some issues:
It would force me to have to write value constructors for all my classes, which goes against everything I see in literally every tutorial/article I've come across. Plus, if I had to do that, then there's no real value to #Autowired anyways...
At this point I'm essentially doing "DIY DI", which is OK, except I'm trying to deliberately use Spring DI :-)
Every time I call chargeFactory() I'm getting a new (prototype-style) ChargeFactory instance. Maybe I want a singleton. Using this approach I have to hand-roll my own singleton implementation.
Sure, I can do all of this, but I feel like I'm flagrantly misusing/misunderstanding how #Configuration is supposed to be used, because it seems like I'm introducing a whole lot of DIY/homegrown code to solve something Spring DI should be able to do for me.
How would I reference the chargeFactory bean and wire it into both the "provider methods" for the paymentService and chargeAuditor beans? Again, looking for the Java-based #Configuration solution instead of writing an XML document to define the wirings.
I found this article which seems to be the only tutorial/documentation (surprisingly) on wiring Spring Boot apps via #Configuration (which leads me to believe there might be other/better methods...), but it does not address:
How to specify singleton vs prototype bean instantiation patterns
If multiple instances of a bean-class exist, how do I specify which instance gets wired into which dependency?
How do I get around not defining value constructors for all my classes, and just let Spring/#Autowired inject fields automagically?
When you call chargeFactory() , spring won't create new instance everytime. Give it a try and see. Same object will be returned. Anyways
You can do something like this.
#Bean
public PaymentService paymentService(ChargeFactory chargeFactory) { return new DefaultPaymentService(chargeFactory); }

How to dynamically inject a service using a runtime "qualifier" variable?

I can't find a simple way to inject a component/service given a runtime value.
I started reading # Spring's doc: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-autowired-annotation-qualifiers
but I can't find there how to variabilize the values passed to the #Qualifier annotation.
Let's say I've got a model entity with such interface:
public interface Case {
String getCountryCode();
void setCountryCode(String countryCode);
}
In my client code, I would do something like:
#Inject
DoService does;
(...)
Case myCase = new CaseImpl(); // ...or whatever
myCase.setCountryCode("uk");
does.whateverWith(myCase);
... with my service being:
#Service
public class DoService {
#Inject
// FIXME what kind of #$#& symbol can I use here?
// Seems like SpEL is sadly invalid here :(
#Qualifier("${caze.countryCode}")
private CaseService caseService;
public void whateverWith(Case caze) {
caseService.modify(caze);
}
}
I expect the caseService to be the UKCaseService (see related code below).
public interface CaseService {
void modify(Case caze);
}
#Service
#Qualifier("uk")
public class UKCaseService implements CaseService {
}
#Service
#Qualifier("us")
public class USCaseService implements CaseService {
}
So how do I "fix" all of this in the most simple / elegant / efficient way by using either/all Spring feature(s), so essentially NO .properties, NO XML, only annotations.
However I already suspect something is wrong in my DoService because Spring would need to know the "case" before injecting the caseService... but how to achieve this without the client code knowing about the caseService?!
I can't figure this out...
I already read several issues here on SO, but most of the times either they don't really have the same needs and/or config as I have, or the posted answers aren't enough satisfying to me (look like they're essentially workarounds or (old) usage of (old) Spring features).
How does Spring autowire by name when more than one matching bean is found?
=> only refers to component-like classes
Dynamically defining which bean to autowire in Spring (using qualifiers)
=> really interesting but the most elaborated answer (4 votes) is... almost 3 1/2 years-old?! (July 2013)
Spring 3 - Dynamic Autowiring at runtime based on another object attribute
=> quite similar problem here, but the answer really look like a workaround rather a real design pattern (like factory)? and I don't like implementing all the code into the ServiceImpl as it's done...
Spring #Autowiring, how to use an object factory to choose implementation?
=> 2nd answer seems interestingly but its author does not expand, so altough I know (a bit) about Java Config & stuff, I'm not really sure what he's talking about...
How to inject different services at runtime based on a property with Spring without XML
=> interesting discussion, esp. the answer, but the user has properties set, which I don't have.
Also read this:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/expressions.html#expressions-bean-references
=> I can't find expanded examples about the use of "#" in expressions. Does someone know about this?
Edit:
Found other related-to-similar issues, no one got a proper answer:
How to use #Autowired to dynamically inject implementation like a factory pattern
Spring Qualifier and property placeholder
Spring: Using #Qualifier with Property Placeholder
How to do conditional auto-wiring in Spring?
Dynamic injection in Spring
SpEL in #Qualifier refer to same bean
How to use SpEL to inject result of method call in Spring?
Factory Pattern might be a solution?
How to use #Autowired to dynamically inject implementation like a factory pattern
You can obtain your bean from the context by name dynamically using a BeanFactory:
#Service
public class Doer {
#Autowired BeanFactory beans;
public void doSomething(Case case){
CaseService service = beans.getBean(case.getCountryCode(), CaseService.class)
service.doSomething(case);
}
}
A side note. Using something like country code as bean name looks a bit odd. Add at least some prefix or better consider some other design pattern.
If you still like to have bean per country, I would suggest another approach. Introduce a registry service to get a required service by country code:
#Service
public class CaseServices {
private final Map<String, CaseService> servicesByCountryCode = new HashMap<>();
#Autowired
public CaseServices(List<CaseService> services){
for (CaseService service: services){
register(service.getCountryCode(), service);
}
}
public void register(String countryCode, CaseService service) {
this.servicesByCountryCode.put(countryCode, service);
}
public CaseService getCaseService(String countryCode){
return this.servicesByCountryCode.get(countryCode);
}
}
Example usage:
#Service
public class DoService {
#Autowired CaseServices caseServices;
public void doSomethingWith(Case case){
CaseService service = caseServices.getCaseService(case.getCountryCode());
service.modify(case);
}
}
In this case you have to add String getCountryCode() method to your CaseService interface.
public interface CaseService {
void modify(Case case);
String getCountryCode();
}
Alternatively, you can add method CaseService.supports(Case case) to select the service. Or, if you cannot extend the interface, you can call CaseServices.register(String, CaseService) method from some initialiser or a #Configuration class.
UPDATE: Forgot to mention, that Spring already provides a nice Plugin abstraction to reuse boilerplate code for creating PluginRegistry like this.
Example:
public interface CaseService extends Plugin<String>{
void doSomething(Case case);
}
#Service
#Priority(0)
public class SwissCaseService implements CaseService {
void doSomething(Case case){
// Do something with the Swiss case
}
boolean supports(String countryCode){
return countryCode.equals("CH");
}
}
#Service
#Priority(Ordered.LOWEST_PRECEDENCE)
public class DefaultCaseService implements CaseService {
void doSomething(Case case){
// Do something with the case by-default
}
boolean supports(String countryCode){
return true;
}
}
#Service
public class CaseServices {
private final PluginRegistry<CaseService<?>, String> registry;
#Autowired
public Cases(List<CaseService> services){
this.registry = OrderAwarePluginRegistry.create(services);
}
public CaseService getCaseService(String countryCode){
return registry.getPluginFor(countryCode);
}
}
According to this SO answer, using #Qualifier isn't going to help you much: Get bean from ApplicationContext by qualifier
As for an alternative strategy:
if you are spring boot, you could use #ConditonalOnProperty or another Conditional.
a lookup service, as #aux suggests
just name your beans consistently and look them up by name at runtime.
Note that your use case also appears to revolve around the scenario where beans are created on application startup, but the bean chosen needs to be resolved after the applicationContext has finished injecting the beans.

Load service for interface only where there is no other service

In my application I have interface with default implementation that is service:
public interface MessageGenerator {
Message getMessage();
}
#Service
public class PropertiesMessageGenerator implements MessageGenerator {
#Override
public Message getMessage() {
return doSmth();
}
}
This service is loaded by spring boots #ComponentScan and everything works fine until I've added new implementation with #Profile
#Service
#Profile("p1")
public class ProfileMessageGenerator implements MessageGenerator {
#Override
public Message getMessage() {
return doSmthWithProfile();
}
}
How can I stop loading into DI service PropertiesMessageGenerator when ProfileMessageGenerator is in context?
PS
I cannot use #Profile("default") on MultipleMessages, because I've got more profiles that I load at one time.
A bit late to the party, but might help future visitors:
I've got it working in Spring Boot 2.5.1 by configuring my service like this:
#Service
#ConditionalOnMissingBean(value = BaseService.class, ignored = DefaultService.class)
public class DefaultService implements BaseService {
...
}
Without the ignored field in the annotation, the condition will match DefaultService and thus not instantiate it. That behavior is a bit strange, but excluding itself from the condition makes it work. With this, I can create an additional implementation of BaseService that is just annotated with #Service and instead it will not instantiate DefaultService but the other implementation.
If you don't use component scanning you could define and pick the bean using #Qualifier
If you want to maintain using component scanning use the #Conditional annotation.
Create your own implementation of 'org.springframework.context.annotation.Condition.class' and pass this to the annotation.
This could read a property to define when it returns true which could be set when what you want is in the context.
#ConditionalOnMissingBean(MessageGenerator.class) can be used if you do not want to implement your own Condition.
Or just annotate ProfileMessageGenerator with #Primary.

Injecting a service in the RabbitMQ - ConfirmCallback class is not working

I have created a separate callback class implementing ConfirmCallback interface and overridden the confirm(). Corrlation data and ack is working fine. But I have injected using #Autowired a service to do some other activities after successful ack from the rabbitMQ. But that service reference is not injected at all. I have injected the same service in other classes it works fine. My code
public MyConfirmCallback implements ConfirmCallback {
#Autowired
private PostAckService postAckService;
public void confirm(CorrelationData correlationData, Boolean ack){
//check the ack and verify the correlationdata.
postAckService.clearData(....);
}
}
postAckService is throwing nullpointer exception. Any idea ?
MyConfirmCallback has to be a bean in the application context for auto wiring to work. You can't simply use new MyConfirmCallback() in your application.
If you believe it's a bean, turn on DEBUG logging for org.springframework; it emits lots of information about bean creation.

Event Listeners in spring is called twice

I am an issue with Spring Event Listeners In my Web app, Any immediate help will be appreciated.
Event Listeners is registered and called twice, If I have cyclic dependency.
I have service class, this has #transaction annotation on another methods
#Service(PBSTaskService.BEAN_NAME)
public class PBSTaskServiceImpl extends StandardServiceImpl<ITask> implements PBSTaskService,ApplicationListener<SurveyDefinitionPublishedEvent>
{
#Autowired
private AutoSelectTaskSliceRouteSyncService autoSelectTaskSliceRouteSyncService; // CYCLIC Dependency
#Override
public void onApplicationEvent(SurveyDefinitionPublishedEvent event)
{
System.out.println("PBSTSImpl"); // THIS IS CALLED TWICE
}
... Other method with #Transaction Annotation
}
#Service(AutoSelectTaskSliceRouteSyncService.BEAN_NAME)
public class AutoSelectTaskSliceRouteSyncServiceImpl implements AutoSelectTaskSliceRouteSyncService
{
#Autowired private PBSTaskService pbsTaskService; // CYCLIC dependency
}
Now If I remove AutoSelectTaskSliceRouteSyncService dependency from First Class, OnApplicationEvent is called once, else twice.
I debugged and found out that
SimpleApplicationEventMulticaster.getApplicationListeners(myEvent) : Has two proxy object, one wrapped with Cglib and another default one. But it has two only in case if it has cyclic dependency. If I remove Cyclic dependency, it has only one proxy object and that one is enahnces by CGLIB.
my Tx annotation :
I had tried it with proxy-target-class="true or false" but no luck.
You may want to have a look on
https://jira.springsource.org/browse/SPR-7940?focusedCommentId=98988&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-98988
Since Spring 4.2 you can do away with implementing ApplicationListener and use the new #EventListener annotation on methods in any managed bean. This should help you avoid any conflicts.
Below is an example from https://spring.io/blog/2015/02/11/better-application-events-in-spring-framework-4-2
#Component
public class MyListener {
#EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
...
}
}
ApplicationEvent Listeners are called twice at many more places in our web app. This is one of scenarios that we caught up.
Reason :
Listeners are registered twice. Two proxy are returned wrapped over one instance of listeners. Proxy returned are 1. Dynamic Jdk Interface proxy 2. Cglib Proxy, when we have #transactions annotations.
To recreate these three point are must:
Your listeners must implements ApplicationListener 2. Your listeners must have cyclic dependency with another class 3.Your listeners must have one method annotated with #Transaction.
I have created a separate project where I am able to reproduce it with spring and hibernate. If 2 and 3 are not present together, then we are safe.
Solution
I tried many tweaks with spring and transaction configuration but no luck. Then finally with my demo project when I moved the transaction code to another class, so that the listeners do not have any #transaction annotations then it worked for me.
In Spring classes anotated with #Service or #Component which implement the ApplicationListener interface are going to receive duplicate events. To resolve the issue, to only receive single events, just remove the #Service or #Compontent annotation.
In a case of circular dependency between Spring beans, Spring Beans machinery might (under certain circumstances) place two versions of a same bean, the bean itself and its Advised wrapper into the list of ApplicationListeners handled by an ApplicationEventMulticaster.
You could, however, implement your custom ApplicationEventMulticaster and fix this bug (it looks like a bug to me).
In a snippet below a custom implementation subclasses Spring's SimpleApplicationEventMulticaster, ignores non-Advised duplicate of a bean, and leaves Advised version of it in the list of ApplicationListeners (most likely you would want an Advised version of your onApplicationEvent method to be called - in a case it is annotated with #Transactional or AOP-advised, but if you need otherwise, the change of algorithm is trivial)
#Component
public class AdviceAwareApplicationEventMulticaster extends SimpleApplicationEventMulticaster {
#Override
protected Collection<ApplicationListener<?>> getApplicationListeners(ApplicationEvent event, ResolvableType eventType) {
Map<ApplicationListener<?>, ApplicationListener<?>> listenersByNakedInstances = new LinkedHashMap<>();// because superclass returns sorted listeners
Collection<ApplicationListener<?>> applicationListeners = super.getApplicationListeners(event, eventType);
for (ApplicationListener<?> listener : applicationListeners) {
boolean advised = false;
ApplicationListener<?> nakedListener = null;
if (listener instanceof Advised) {
try {
nakedListener = (ApplicationListener<?>) ((Advised)listener).getTargetSource().getTarget();
} catch (Exception e) {
// TODO
}
advised = true;
} else
nakedListener = listener;
if (advised || !listenersByNakedInstances.containsKey(nakedListener))
listenersByNakedInstances.put(nakedListener, listener);
}
return listenersByNakedInstances.values();
}
}
You don't need to anyhow make your custom implementation known to Spring, it's enough to have it as a Spring bean and Spring Application Context will pick it up.
Also, don't forget that if there are more one Spring Application Contexts in the application, your Listener might be called for each of those, but it's altogether different story.
I was running into the same issue with one of my services, created another listner with the same event that was only called once.
So what #SimonH wrote is not always the case, only in some circumstances I could not reproduce:
In Spring classes anotated with #Service or #Component which implement the ApplicationListener interface are going to receive duplicate events.
In my case this lead to a double call of the onApplicationEvent method.
#Service
public class TestClass implements ApplicationListener<MyEvent>{
#Override
public void onApplicationEvent(MyEvent event){
// called twice
}
}
Instead of the code above, I could solve it by creating the Event Listener as an inner class and then call the event method of the parent.
#Service
public class TestClass {
#Component
private class MyListener implements ApplicationListener<MyEvent> {
#Override
public void onApplicationEvent(MyEvent event) {
TestClass.this.onApplicationEvent(event);
}
}
public void onApplicationEvent(MyEvent event){
//Have fun with a single event here
}
}

Resources