What is the best place in SpringBoot application to initialize business logic? - spring

I want to initialize some business logic (e.g. send some messages to a message broker) in a Spring Boot application after context is created and beans (singletons) are initialized - what is the "most correct" place for it?
From my perspective the candidates are:
Implement ApplicationListener + listen for ContextStartedEvent
ApplicationRunner's OR CommandLineRunner's run() method
#PostConstruct of a particular bean (I don't this method, but have seen sometimes in colleagues' code - because I need to be sure all beans are created, initialized, customized, set up, etc. and I don't wanna play with beans load order)
I understand that in general, in MVC web application the place for business logic is #Service, but I need to call it immediately after the start of my application, so what's the best way to do that?

I would go with #EventListener. Like you said there are different ways to achieve this. I will give my opinion on your numbers
ApplicationListener called 3 times. No need to listen this one. This maybe usefull if you are doing something close to tomcat.
ApplicationRunner,CommandLineRunner is called after all bean initialization. This can be useful.
#PostConstruct you can get null beans if you are working with other components.
I prepared a small example to use all these in one application and print some logs but I could not put them here. spring log looks ugly here. anyway my suggestion is here if you dont have any dependency to other beans this looks nicest. if there are dependencies then you can use ApplicationListener which was the last logged in my example.

Related

why #RestController by default use singleton scope?

I am actually a EJB developer and very new in spring framework.
i find a couples of conflict conceptually. Like ..
#RestController use by default scope which is singleton. By single object per loc have to manage heavy trafic.
is it a good design?
Of course, it is a good design because the same instance of the object will be reused instead of keep creating it each time you need it. That is the whole point of that design pattern.
Here is a great example where singleton comes to the rescue.
https://rules.sonarsource.com/java/RSPEC-2119
By default, spring will take care of the creation and destruction of all singleton beans, while the prototype has to be manually handled. Therefore in a lot of cases prototype scope is for custom beans made by developers.
In SpringMVC Controller layer, #Scope("prototype") vs #Scope("singleton")
is it a good design?
Yes, all beans in Spring are singletons (by default).
We have 100+ controllers in several applications and it works perfectly.
If you really need to instantiate controllers more than once, you can, of course, consider other bean scopes (see brief explanation of scopes here https://www.baeldung.com/spring-bean-scopes)

When and where must I initialize the spring context?

I'm a noob when using Spring and I have a doubt.
When and where must I initialize the spring context?
Right now I am initializing the context when I'm going to use something like a properties file:
ClassPathXmlApplicationContext cxt = new ClassPathXmlApplicationContext("myContext.xml");
But I have read that the Spring context must be initialized in the entry point of my program (Main.java) and pass it as argument in the necessary methods.
Is this true?
As #MarounMaroun said, it really depends on what are you trying to do.
When people use Spring they usually build the entire application to take advantage of what Spring has to offer. That is to say, they put everything in the Spring context, configure it, and let it wire all the things together when starting. So in order to be useful, the application needs to load the Spring context before doing anything else.
For a standalone application you do the initialization in the main method.
When main is called, you first initialize the Spring context, and once the context is fully loaded you retain a reference to it and make it available where needed.
If it makes sense to initialize the Spring context at a later time or in another class you can do that too, but as I said, most applications need the context initialized to be able to function so that's why they initialize it as early as possible, in the main method, and that's probably the recommendation you have read.
If you are talking about a web application, you should do it web.xml
Loading context in Spring using web.xml
If it's a test, things are different:
spring junit load application context for tests
In both cases, you don't need an explicit main.java

Scenario when we may be needing #Configurable in spring?

I have question about the need of using #configurable. I have gone through the blog that explains how to use #configurable. But the question that comes to my mind is, what can be the scenario when we need to use #configurable. I can think of two scenarios where it can be useful
In a legacy project, when we are already making any bean with new operator and we want to make it spring managed.
In a new project, we want to enforce that even if developer makes the bean with new operator, still it is spring managed.
Otherwise for new beans we can always declare them in applicationContext.xml and I do not see any need to declare them #configurable.
Please let me know if above understanding is correct or if I am missing something.
UPDATE:- Basically as per my understanding configurable is generally used to inject dependency when creating the object with new operator. But why would i be creating the object with new operator when i am using spring
#Configurable annotation is meant for injecting dependencies in domain-driven applications. That means, in such applications, the domain objects interact with each other to perform a certain operation.
Take the following example:
In an invoicing application, the Invoice class provides a constructor to create it, then it has methods to validate, and finally persist it. Now, to persist the invoice, you need a DAO implementation available within the invoice. This is a dependency you would like to be injected or located. With Spring's #Configurable, whenever an invoice is created using the new operator, the appropriate DAO implementation will get injected and can be used for all persist operations.
I had a more realtime scenario where I used #Configurable annotation as described here.

Can a Spring Bean programmatically replaced in an loaded SpringContext

I want write an integration test but with one minor restriction. I got a TimeSourceBean that I want to mock out. This TimeSourceBean is used several times deep in the application. (no way to do this with reflection)
Everything is done by autowire.
I think I could load in my test an additional XML with an implementation I like to have.
see: here!
But really nice would be when I can create my mock TimeSourceBean in the test itself and register it (replace the original bean) to the context
=> so before I start the test, I create the mock and register my bean like this:
context.registerBean(timeSourceBeanMockVersion);
Any ideas if this is possible?
You can add an other bean/class that implement the same interface (hopefully you use them), and mark this other bean class as #Primary.
But then you need to make sure that this primary bean is only loaded in the test cases you need them.

Access application context from BundleContextAware class

I have created an osgi bundle from an existing legacy war. The app has a class that implements the spring interface ApplicationContextAware, it then uses the context to programmatically get beans (not sure why but this needs refactoring eventually). The app now uses OsgiBundleXmlApplicationContext, but I believe that there is an issue with using this whereby the setApplicationContext method does not get called in any classes implementing ApplicationContextAware, so now the context in this class is always null.
So as a workaround I have implemented BundleContextAware so that I can get a reference to the published context and get access to the beans that way. This works ok however the only bean on the context is warDeployer (should mention that I am using the spring dm bundle spring-extender to deploy the war). The bundle present on the context is my bundle so I cannot see why the context that I am getting has none of my beans on it. The code I have to get the application context is:
ServiceReference ref = bundleContext.getServiceReference(ApplicationContext.class.getName());
applicationContext = (OsgiBundleXmlApplicationContext) bundleContext.getService(ref);
I can see in the logs that much of my context is getting created so I can't see why they are not on the context I am getting.
Can anyone advise as to what is wrong? I understand that this approach is a bit hacky, but it's temporary until the existing code is refactored.
Thanks in advance.
Barry
I believe that the ApplicationContext service is registered asynchronously by the Spring-DM extender. So you probably have a race condition, i.e. asking for the service just before it is actually registered.
You could introduce a delay but then you're very deep into nasty hack territory. It would be better to work out why the setApplicationContext method on the ApplicationContextAware beans is not being set. You should try raising this is a bug against Spring-DM or asking in the Spring-DM Google Group.

Resources