I have an application which is built on Spring 3.0.5 and uses JMS for exchanging messages. The beans which receive the messages are configured by using the jms namespace. The class looks like this
class MyService {
public void receive(String msg) {
...
}
}
The Spring configuration looks like this
<jms:listener-container destination-type="queue">
<jms:listener destination="queue.test" ref="myService" method="receive"/>
</jms:listener-container>
However, when I change the receive method to get a Message object the method is no longer called.
class MyService {
public void receive(TextMessage msg) {
...
}
}
I realize that I could just use the MessageListenerAdapter but it is more configuration overhead and I am just wondering why this doesn't work.
Any insight is greatly appreciated.
Frank
The <jms:listener> config automatically creates a MessageListenerAdapter for you, so it's not necesarry for you to configure that explicitly.
Your problem is that MessageListenerAdapter is designed to decouple your code from the JMS API altogether. The target method in <jms:listener> must declare one of the parameter types permitted by MessageListenerAdapter (see docs), which represent the possible payload types of a message, i.e. one of String, Serializable, byte[] or Map.
If you want to receive the raw JMS TextMessage object, then your listener class has to implement MessageListener or SessionAwareMessageListener. That makes it a "proper" JMS listener. In that case, the method config becomes redundant, and you can just use :
<jms:listener destination="queue.test" ref="myService"/>
I'm actually rather surprised that Spring didn't throw an exception when it found that your receive method had an invalid parameter type.
What I've figured out is that in order for the MessageListenerAdapter not to convert the message the messageConverter attribute must be set to null. However, when using the namespace configuration it is not possible to disable the default message converter that is automatically created.
The code in the AbstractListenerContainerParser checks if the message-converter attribute of the <jms:listener-container> is either not set or points to a valid bean. Otherwise a SimpleMessageAdapter is instantiated.
To work around this problem I've created a NoopMessageConverter which solves the problem
public class NoopMessageConverter implements MessageConverter {
#Override
public Message toMessage(Object object, Session session)
throws JMSException, MessageConversionException {
return (Message) object;
}
#Override
public Object fromMessage(Message message)
throws JMSException, MessageConversionException {
return message;
}
}
Then configure the <jms:listener-container> like this
<bean id="noopMessageConverter" class="NoopMessageConverter"/>
<jms:listener-container message-converter="noopMessageConverter">
<jms:listener destination="queue.test" ref="myService" method="receive"/>
</jms:listener-container>
Then you can create your bean as follows and the receive method is called
class MyService {
public void receive(TextMessage msg) {
...
}
}
Related
Every request that my Java application receives, passes through 4 layers:
Handler --> Validator --> Processor --> DAO
Handler is the API Resource. (Handler.java)
Validator validates the input. (Validator.java)
Processor performs some business logic. (Processor.java)
DAO is the DB communication layer. (DAO.java)
The input request has a field called the request_type. Based on this request_type, I want to create different objects for all the layer classes, i.e:
request_type_A should pass through Handler1, Validator1, Processor1, DAO1 (instances)
request_type_B should pass through Handler2, Validator2, Processor2, DAO2 (instances)
request_type_C should pass through Handler3, Validator3, Processor3, DAO3 (instances).. and so on
To clarify, the requirement is to create different chain of objects for a given request type, so that two request having different request_type have entirely different object chain instances. Basically i want to shard my application's object based on a given request_type.
I am using Spring Boot. Is there a way that spring's ApplicationContext can provide different object chains for different object types. Or should I manage these instances by my own?
Is there a way I can create a library which would give me a new object instance for every layer, based on the request_type using Spring's ApplicationContext?
Or should i create multiple ApplicationContext?
Based on comments & question, I understand that you would be receiving 2 or 3 request_type.
So main idea which I have used here is to use constructor injection of chained objects with different configuration beans which will be used based on your request type.
Feel free to check-out this simple demonstration based code from github where I have proposed my idea : https://github.com/patilashish312/SpringObjectChaining
So based on this code, I can confirm that
This application is not creating chain of object per request but will re-use if same type of requests received by application
Objects assigned to one request type is not being used by other request type.
Below console output is proof :
displaying request MyRequest(id=1, name=Ashish, requestType=requestTypeA)
Printing handler bean com.spr.boot3.ConditionalVerification.Handler.MyHandler#31182e0a
Printing validator bean com.spr.boot3.ConditionalVerification.Validator.MyValidator#484e3fe7
Printing processor bean com.spr.boot3.ConditionalVerification.Processor.MyProcessor#70f9b9c7
Printing dao bean com.spr.boot3.ConditionalVerification.Dao.MyDao#2a8175d9
inside dao, doing DAO processing
displaying request MyRequest(id=1, name=Ashish, requestType=requestTypeA)
Printing handler bean com.spr.boot3.ConditionalVerification.Handler.MyHandler#31182e0a
Printing validator bean com.spr.boot3.ConditionalVerification.Validator.MyValidator#484e3fe7
Printing processor bean com.spr.boot3.ConditionalVerification.Processor.MyProcessor#70f9b9c7
Printing dao bean com.spr.boot3.ConditionalVerification.Dao.MyDao#2a8175d9
inside dao, doing DAO processing
displaying request MyRequest(id=1, name=Ashish, requestType=requestTypeB)
Printing handler bean com.spr.boot3.ConditionalVerification.Handler.MyHandler#55ea9008
Printing validator bean com.spr.boot3.ConditionalVerification.Validator.MyValidator#5b2d74c5
Printing processor bean com.spr.boot3.ConditionalVerification.Processor.MyProcessor#5f12fb78
Printing dao bean com.spr.boot3.ConditionalVerification.Dao.MyDao#1a107efe
inside dao, doing DAO processing
displaying request MyRequest(id=1, name=Ashish, requestType=requestTypeB)
Printing handler bean com.spr.boot3.ConditionalVerification.Handler.MyHandler#55ea9008
Printing validator bean com.spr.boot3.ConditionalVerification.Validator.MyValidator#5b2d74c5
Printing processor bean com.spr.boot3.ConditionalVerification.Processor.MyProcessor#5f12fb78
Printing dao bean com.spr.boot3.ConditionalVerification.Dao.MyDao#1a107efe
inside dao, doing DAO processing
I had a similar requirement in my solution. What I built was a general-purpose command handler, and used a decorator pattern of annotations on each command to provide the specification for which handlers, validators, processors, and dao.
In my implementation, I have API handlers which convert requests to specific commands. Command class was an subclass of an abstract command class with a generic type param.
API -> all API variables are copied into a wrapper data model. (This could encapsulate the entrypoint of your handler concept or request_type concept)
Command extends AbstractCommand where T is the wrapper data model.
Then I would have an annotation for each of your concepts: Handler, Validator, Processor, Dao.
The general purpose command handler would have a method that "process"es commands by reading their annotations and then lining up the annotation helper that corresponds to that annotation. This could use the application context to load the bean of the class referenced in the annotation value. By providing a sequencing property for each of the annotation helpers you could loop over the sorted helpers to perform actions in the right order.
In my implementation this was further augmented by whether or not the command included asynchronous behavior, so that all the synchronous behavior would occur first, and the asychronous behavior would be wrapped in a background thread.
The beans that are injected in the rest controller don't vary with the http request content. What you can do is factor your request_type as a path variable and create the desired chains in separate http mappings like so:
#PostMapping(value = "/request_type_A")
public Object handle1(args...){
// Validator1 --> Processor1 --> DAO1
}
#PostMapping(value = "/request_type_B")
public Object handle2(args...){
// Validator2 --> Processor2 --> DAO2
}
If this is not practical for whatever reason and you must specify the type dynamically in the #RequestBody, #PathVariable or #RequestParam, then I would suggest implementing a resolver bean similar to this:
#Component
public class Resolver {
private final RequestTypeAValidator requestTypeAValidator;
private final RequestTypeBValidator requestTypeBValidator;
...
public IValidator getValidator(String requestType) {
switch (requestType) {
case "request_type_A":
return requestTypeAValidator;
case "request_type_B":
return requestTypeBValidator;
default:
throw new IllegalArgumentException("cannot find validator");
}
}
}
The drawback of this approach is that it does not comply with the "Open-Closed" principle in the sense that for any new request type, you will need to edit the resolvers. That can be fixed by using a HashMap in the resolver and letting the beans register themselves to that map on #PostConstruct:
#Component
public class Resolver {
private final Map<String, IValidator> validators = new HashMap<>();
public IValidator getValidator(String requestType) {
IValidator result = validators.get(requestType);
if (Objects.isNull(result)) {
throw new IllegalArgumentException("cannot find validator");
}
return result;
}
public void register(String type, IValidator validator) {
validators.put(type, validator)
}
}
#Component
public class ValidatorA implements IValidator {
private final Resolver resolver;
#PostConstruct
private void register() {
resolver.register("request_type_A", this);
}
...
}
However, in this approach there is a direct dependency from all implementations back to the Resolver.
Lastly, you could inject dynamically like so:
#Component
public class Resolver {
private final ApplicationContext applicationContext;
...
public IValidator getValidator(String requestType) {
switch (requestType) {
case "request_type_A":
try {
return applicationContext.getBean(ValidatorA.class);
} catch (NoSuchBeanDefinitionException e) {
// handle exception
}
case "request_type_B":
try {
return applicationContext.getBean(ValidatorB.class);
} catch (NoSuchBeanDefinitionException e) {
// handle exception
}
default:
throw new IllegalArgumentException("cannot find validator");
}
}
}
Note: Avoid taking the client specified string as the class name or type directly in the applicationContext.getBean() call. That is not safe and may present a great security vulnerability, use a switch or dictionary to resolve the correct bean name or bean type.
If you want to inject multiple instances of the same classes, create a configuration class and declare the beans like this:
#Configuration
public class BeanConfiguration {
#Bean
public IValidator aValidator(){
return new ValidatorImpl(...);
}
#Bean
public IValidator bValidator(){
return new ValidatorImpl(...);
}
}
And then to inject it, you can either use the dynamic resolution by name as above, or use the #Qualifier annotation:
#Service
public class MyService {
private final ApplicationContext applicationContext;
private final IValidator bValidator;
public MyService(ApplicationContext applicationContext, #Qualifier("bValidator") IValidator bValidator) {
this.applicationContext = applicationContext;
this.bValidator = bValidator;
}
public void getDynamically(){
IValidator aValidator = (IValidator)applicationContext.getBean("aValidator");
}
}
I have created a custom channel in Spring cloud stream with custom inputs and outputs. Let's suppose this is the created channel:
public interface Channel {
String FOO = "foo-request";
String BAR = "bar-response";
#Input(FOO)
SubscribableChannel fooRequest();
#Output(BAR)
MessageChannel barResponse();
}
Something.java:
public class Something{
#Autowired
private Channel channel;
public void doSomething(..){
// Do some steps
channel.barRequest().send(MessageBuilder.withPayload(outputMessage).build())
}
}
As it can be seen I am injecting the custom channel in the Something class to send the message at the end of a method.
When I would like to test this method, I am having some issues with the injection done in the Something class. I cannot inject the Something class because it's not a component. But this class injects a Channel object as it can be seen. So here is what I have done to pass the limitation of injecting an internal property for this class:
#RunWith(SpringRunner.class)
#SpringBootTest(classes = {MyChannel.class})
public class SomethingTest{
#Autowired
private Channel myChannel;
#Test
public void TestDoSomething(){
// cannot inject it as it does not have any qualified bean
Something something = new Something();
ReflectionTestUtils.setField(something, "channel", channel);
}
#EnableBinding(Channel.class)
public static class MyChannel {
}
}
Without the ReflectionTestUtls line, I am getting a NullPointerException on channel.barRequest().send() in the doSomething method. With having this line to pass the injected object, I am getting the following error:
org.springframework.messaging.MessageDeliveryException: Dispatcher has no subscribers for channel 'application.bar-response'.; nested exception is org.springframework.integration.MessageDispatchingException: Dispatcher has no subscribers
First of all, I am not sure if what I am doing is the best way of dealing with my custom channel and testing the corresponding method, so please let me know if there is a better way. Second, why am I getting this exception and how I can address it?
P.S: I have already set the required configurations in my application.yml file for the test related to the binders and channels in a similar way that I have been doing with running the application in a normal way. This approach has been working so far with other properties.
the first thing noticing is you try to send to your Input Channel which typically recevies the messages.
Try changing it to channel.barResponse().send(...)
Other then that i am facing the same issue, but with a more complicated use-case. We have already definied our rabbit queues.
When you add a #ServiceActivator annotation on a method, that method can have different return types which seem to have different implications for the service:
#ServiceActivator(inputChannel = "..", outputChannel = "..")
public T messageReceiver() {...}
Where T could be
void
Object
MessageHandler
How does the ServiceActivator differ based on the return type? I am specifically wondering about the line in the docs that says:
Return values from the annotated method may be of any type. If the return value is not a Message, a reply Message will be created with that object as its payload.
But I'm not following this because I've seen people return MessageHandlers from their ServiceActivator-annotated methods, and they don't want their MessageHandlers to be wrapped as a payload right?
Like this:
#Bean
#ServiceActivator(inputChannel = "sendAsyncChannel", autoStartup="false")
public MessageHandler sendAsyncHandler() {
return // some MessageHandler
}
What you are pointing is a Messaging Annotations on #Bean. This is a bit different story and it implies not related to POJO method invocation aspect.
We use that #ServiceActivator on the MessageHandler #Bean to register an EventDrivenConsumer endpoint for the provided MessageHandler, when the POJO method style, creates a MethodInvokingMessageHandler for the marked with this #ServiceActivator method.
Please, see more info in the Reference Manual:
https://docs.spring.io/spring-integration/docs/5.0.9.RELEASE/reference/html/overview.html#programming-tips
and:
https://docs.spring.io/spring-integration/docs/5.0.9.RELEASE/reference/html/configuration.html#annotations_on_beans
I have read through the dependency capabilities through Java CDI but could not figure out so far how to inject a class by runtime. Let me explain the scenario first.
Lets assume I have a JSF web app with a central Email service.
I am defining an interface
public interface EmailService {
public String sendEmail(Email email);
}
Then next I have a concrete implementation of the EmailService using Smtp:
public class SmtpEmailServiceImpl implements EmailService {
#Override
public String sendEmail(Email email) {
// concrete implementation using Smtp
}
}
Now in my web app I am having a JSF backing bean that should get the EmailService injected in order to sende the e-mail
public class JSFBackingBean {
// This is the EmailService to be injected
private EmailService emailService;
public String sendEmail(){
emailService.sendEmail(new Email());
}
}
Now lets assume the Smtp-Server is down for maintenance. In this scenario I would like to spool all the Emails in a Database and process them later when the Smtp server is up and running. In this case I would like to have a second implementation of the EmailService:
public class DatabaseEmailService implements EmailService {
#Override
public String sendEmail(Email email) {
// concrete implementation writing the email to a database
}
}
Now I understand from CDI that I can use Annotations to inject the proper service implementation but that would mean that I would have to re-build and deploy my classes in case I would like to change the appropriate service. Is there a better solution where I can use e.g. a configuration file in order to change the injection at runtime of the application?
Thanks for your answers in advance
Pred
In cases like this, you could write a custom Producer and Qualifier. Instead of injecting the EmailService, inject for example a "#Failsafe EmailService".
Then write a producer
#Produces
#Failsafe
private EmailService failsafeEmailService() {
// here you can check if the Mail Server is available and then decide
// to return the "real" Service or the DB-Queue.
}
Instead of creating/looking up the Services inside the method body, you could also let CDI inject both alternatives (directly or via Instance<>) and then decide which one to propagate.
#Produces
#Failsafe
private EmailService failsafeEmailService(MailServiceBean bean, DBQueue queue) {
return (check_if_mail_server_is_running) ? bean : queue
}
(of course both DBQueue and Bean have to implement EmailService).
Well, I doubt you want to make it so that every client to this email service is aware that the mail service needs to be switched out, even if you used annotations and instance selectors, e.g.:
#Inject
private Instance<EmailService> emailServiceInstance;
// few lines down
emailServiceInstance.select(new SmtpLiteral()).get();
Which is how you would do it in a CDI fashion. What I would recommend is that this logic belongs in your EmailService and itself injects a reference to some DB class that persist the message to the database until the SMTP server is back online.
Ok. We have the need to #Autowire a different webservice on-the-fly (preferably by toggling a JNDI setting on the webserver) and I'm at a loss on how to do this. This is the way I was approaching the problems..
Two packages:
com.mycomp.service.stub
com.mycomp.service.impl
One package contains MyServiceStub.java while implement MyService
The other package contains MyServiceImpl.java, which implements same
My controller, which requires MyService, has the bean defined as such
#Autowire
private MyService communicator;
My spring-context.xml has the following:
<context:component-scan base-package="com.mycomp" />
At this point I get a DuplicateBean exception during autowiring. Now, I can statically define which bean to autowire in spring-context.xml:
<bean id="communicator" class="com.mycomp.service.impl.MyServiceImpl" />
and everything works fine... But then, how to 'flip' the switch and change over to the Stub method on our QA server? It has no connection to that service, so we need to run with stubs enabled. A JNDI property would be best for this.. but I just can't get my head around how to toggle what bean spring autowires at runtime.
Any help??
Cheers,
Chris
#Profile solution
You definitely have to try Spring 3.1 #Profile:
#Autowire
private MyService communicator;
//...
#Service
#Profile("prd")
class MyServiceImpl //...
#Service
#Profile("qa")
class MyServiceStub //...
Now depending on which profile is enabled, either DefaultMyService will be initialized or MyServiceStub.
You can choose between profile in various ways:
How to set active spring 3.1 environment profile via a properites file and not via an env variable or system property
using system property
programmatically
...
Spring AOP (explicit around every method)
In this example the aspect wraps around every single MyService method separately and returns stubbed value:
#Aspect
#Service
public class StubAspect {
#Around("execution(public * com.blogspot.nurkiewicz.MyService.foo(..))")
public Object aroundFoo(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
return //stub foo() result
}
return pjp.proceed();
}
#Around("execution(public * com.blogspot.nurkiewicz.MyService.bar(..))")
public Object aroundBar(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
return //stub bar() result
}
return pjp.proceed();
}
private boolean stubMode() {
//whatever condition you want here
return true;
}
}
The code is pretty straightforward, unfortunately the return values are buried inside the aspect and you need a separate #Around for every target method. Finally, there is no place for MyServiceStub.
Spring AOP (automatically around all methods)
#Aspect
#Service
public class StubAspect {
private MyServiceStub stub = //obtain stub somehow
#Around("execution(public * com.blogspot.nurkiewicz.MyService.*(..))")
public Object aroundFoo(ProceedingJoinPoint pjp) throws Throwable {
if (stubMode()) {
MethodSignature signature = (MethodSignature)pjp.getSignature();
Method method = signature.getMethod();
return method.invoke(stub, pjp.getArgs());
}
return pjp.proceed();
}
private boolean stubMode() {
//whatever condition you want here
return true;
}
}
This approach is more implicit as it automatically wraps every target method, including new methods added in the future. The idea is simple: if stubMode() is off, run the standard method (pjp.proceed()). If it is on - run the exact same method with exact same parameters - but on a different object (stub in this case).
This solution is much better as it involves less manual work (at the price of using raw reflection).
Note that if both MyService implementations are Spring beans (even when one is annotated with #Primary), you might run into weird troubles. But it should be a good start.
See also:
Spring 3.1 M1: Introducing #Profile
Maybe you can replace the class with a property and deploy your application with different property files. The production version would contain the name of the real class while the QA version would contain the name of a stub.
Maybe this http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/beans.html#beans-factory-extension-factory-postprocessors can help you.