Spring mvc on application load event to load collection - java

I have to load something from the database to initialize a hashMap object that I want to add to a application wide variable that all my mvc controllers can access.
I won't be modifying this object, and I don't care if it can only be updated when the application reloads.
Does spring MVC have a place where I can do this and have spring manage the lifecycle also?
I know servlets has the WebListener annotation:
#WebListener
But not sure if spring has this also (wrapped in their iOc container).

I think the best place is to declare a bean like the following:
public class MyInitializingBean {
#PostConstruct
private void init() {
//do initialization here
}
}
Then you declare that bean in your xml file, if you don't like the annotation, there are non-annotation approaches for initializing a bean, but that gets executed when the spring context starts.

Related

get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method

I know I can not use #Autowired annotation in a non managed spring class. But I notice I do able to get a bean instance inside a non managed spring class if I am retrieving it through ApplicationContext getBean method.
can someone explain me why is that ? what is the different between the options ? in both spring doesn't know the non managed class
1) You can use #Autowired in a non-managed spring class if you use #Configurable -with the usage of internal aspect weaving spring will manage to autowired the referenced beans into your "Configurable" class when it is constructed with the "new" operator. Here is an article how this works: http://www.javacodegeeks.com/2013/09/spring-configurable-magic.html
If a class is not configurable spring cannot notice when a new instance is created to autowire its references.
2) The ApplicationContext is "Central interface to provide configuration for an application." Here you have access to the whole spring managed beans etc. That's why you can get everything due to accessing it via ApplicationContext. http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/ApplicationContext.html
ok, so here's the major points:
the "bean declaration" (either in xml or java) is just a recipe of how to instantiate the object (not a object itself).
when spring application boots, the beanFactory receives this recipes from beanDefinitionReader, instantiates objects according to them (recipes) and then pass them (objects) to a list of beanPostProcessors (several times) that are "injecting" dependences to the instantiated objects and then puts the objects into hashMap.
roughly saying applicationContext is a class exposing access to this beans;
and that's how you can access this beans out of spring application using applicationContext.
another thing is that, actually you can inject beans into non managed beans through #Configurable. in this case the AspectJ would be used for making this work

Failing to #AutoWire a member in a #WebServlet

I can't seem to get my servlet's fields to #AutoWire; they end up null. I have a pure annotation-configured webapp (no XML files). My servlet looks like this:
#WebServlet("/service")
public
class
SatDBHessianServlet
extends HttpServlet
{
#Autowired protected NewsItemDAO mNewsItemDAO;
}
Other #AutoWired things seem to work fine, both #Service objects and #Repository objects. But not this one, and I can't figure out why. I even tried adding its package to the ComponentScan(basePackages) list for my other classes.
Additional Info:
I added the following to my servlet’s init() method, and everything seemed to wire up properly, but I'm confused as to why Spring can't wire it up without that.
SpringBeanAutowiringSupport.processInjectionBasedOnServletContext(this, inConfig.getServletContext());
Servlet are web components that are not being created by Spring container, based on that lifecycle is not managed by the container and a lot of stuff that spring provides such as autowired or aspect can not run from them.
You need to indicate to the spring container that a component was created outside of IoC container and need to be part of it.
And as the API said SpringBeanAutowiringSupport is for:
Convenient base class for self-autowiring classes that gets
constructed within a Spring-based web application
This generic servlet base class has no dependency on the Spring ApplicationContext concept.
There is another way to indicate servlets being created by spring container using an interface
Spring MVC uses the DispatcherServlet for handling all requests in a Servlet environment.
The DispatcherServlet accordingly forwards the requests to the appropriate #Controller class (if any) based on the #RequestMapping on that class and/or it's methods.
What is happening in your Servlet is that it is not managed by Spring (but by the Servlet container) and there for no injection of dependencies is occurring.

Set object in application context in spring mvc

I have a utility class which I want to initialize when the application starts in Spring MVC. So I am implementing InitializingBean. Now I have to create an object for the same and save it in Application scope so that I can access the same instance everywhere. But I am not able to get hold of this.
Here is my try:
public class DashboardInitializer implements InitializingBean, ApplicationContextAware {
private ApplicationContext mApplication;
#Override
public void afterPropertiesSet() throws Exception {
initializeConfigurationUtil();
ConfigurationUtil util = ConfigurationUtil.getInstance();
/* Save the util to application scope */
}
#Override
public void setApplicationContext(ApplicationContext pApplication) throws BeansException {
this.mApplication = pApplication;
}
}
Is this approach correct or there is a better way to do that?
I think you need to simplify this a little bit.
You want the utility class to be initialized after your application context is loaded, but you also want your util class to be in the application context?
Seems the util class has some dependency objects configured in the application context, and the util class is in turn a dependency of some classes in the application context.
If you can express these dependencies in the form of beans (util is a bean, which has its dependency beans injected into it, and beans that need util have util injected into them), Spring will ensure that all dependencies of util are initialized first, then util is initialized and then it is injected into classes that need util.
You should not try to add something to an initialized context.. Its not possible.
If you cannot express util and its dependencies as beans, you can also take this approach:
1. Configure util as a bean in the application context, add a default constructor that does nothing. So this object would be created, but not initialized when the spring context is loaded.
In the ApplicationContextAware implementation you have, modify the setApplicationContext method. Get the util bean you configured earlier from the context.
You can now initialize (execute some code that you want to execute) the util instance, just make sure you do not try to reassign the bean to some other instance of util.
Hope this helps.
You can use #postconstruct annotation on methods to perform business logic immediately after the application has been initilized. And properties can simply be injected using placeholder in config and #Value annotation on java fields.

Ordering Listeners in Spring's WebApplicationInitializer

I have a custom ServletContextListener that I am using to initialize and start up a Cron4J scheduler.
public class MainListener implements ServletContextListener {
#Value("${cron.pattern}")
private String dealHandlerPattern;
#Autowired
private DealMoqHandler dealMoqHandler;
}
I am autowiring some objects in the Listener as shown, and would like for Spring to manage the listener's instantiation. I am using programmatic web.xml configuration through WebApplicationInitializer, but so far the Listener isn't being autowired (NullPointerExceptions whenever I try to access the supposedly autowired objects).
I've already tried to add my customer listener after adding the ContextLoaderListener, shown below:
public class CouponsWebAppInitializer implements WebApplicationInitializer {
#Override
public void onStartup(ServletContext container) throws ServletException {
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(SpringAppConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
container.addListener(new MainListener()); //TODO Not working
}
I checked these past questions Spring - Injecting a dependency into a ServletContextListener and dependency inject servlet listener and tried to implement the following code inside the contextInitialized method of my listener:
WebApplicationContextUtils
.getRequiredWebApplicationContext(sce.getServletContext())
.getAutowireCapableBeanFactory()
.autowireBean(this);
However, I just get the following exception:
Exception sending context initialized event to listener instance of class com.enovax.coupons.spring.CouponsMainListener: java.lang.IllegalStateException: No WebApplicationContext found: no ContextLoaderListener registered?
at org.springframework.web.context.support.WebApplicationContextUtils.getRequiredWebApplicationContext(WebApplicationContextUtils.java:90) [spring-web-3.1.1.RELEASE.jar:3.1.1.RELEASE]
How can I make sure that Spring has already finished instantiation before adding my listener?
My mistake. It turns out the code in the original post is correct, and the listeners are being added in the correct order.
The issue was that I had annotated my custom listener with a #WebListener annotation (Servlet 3.0). This was causing the web app to disregard my addListener() code in WebApplicationInitializer, and instantiate the custom listener AHEAD of Spring's ContextLoaderListener.
The following code block illustrates the ERRONEOUS code:
#WebListener /* should not have been added */
public class CouponsMainListener implements ServletContextListener {
#Autowired
private Prop someProp;
}
You cannot use new with Spring beans - Java doesn't care about Spring and Spring has no way to modify the behavior of the new operator. If you create your objects yourself, you need to wire them yourself.
You also need to be careful what you do during initialization. When using Spring, use this (simplified) model: First, Spring creates all the beans (calls new for all of them). Then it starts to wire them.
So you must be extra careful when you start to use the autowired fields. You can't always use them right away, you need to make sure that Spring is finished initializing everything.
In some cases, you can't even use autowired fields in #PostProcess methods because Spring couldn't create the bean because of cyclic dependencies.
So my guess is that "whenever I try to access" is too early.
For the same reason, you can't use WebApplicationContextUtils in the WebApplicationInitializer: It hasn't finished setting up Spring, yet.

Executing a Java class at application startup using Spring MVC [duplicate]

This question already has answers here:
Execute method on startup in Spring
(13 answers)
Closed 6 years ago.
What is the best way to execute a Java class at application startup using Spring MVC ?
There's not necessarily a "best" way. As usual, there are many ways to do it, and the "best" is whichever fits into your project the best:
Use init-method="..." on a bean element in XML, as cjstehno mentioned
Implement Spring's InitializingBean interface. When deployed in an ApplicationContext, the afterPropertiesSet() method will be called when the bean is created.
Annotate a method on a bean with #PostConstruct. Again, if deployed to an ApplicationContext, the annotated method will be called when the bean is created.
If your bean is more of an infrastructure bean to be tied into the Spring lifecycle, implement ApplicationListener<ContextRefreshedEvent>. The onApplicationEvent(..) method will be called during Spring's startup, and you can do whatever work you need there.
Assuming your context is loaded on startup, create a bean in your spring application context with an init method explicitly called out in the XML config (or implement Springs InitializingBean). If you have lazy-loading enabled you will need to make sure this bean is not lazy.
<bean name="starter" init-method="start" class="com.my.StarterBean" lazy="false" />
(please double-check the params in the docs).
If your context is not loaded on startup you can register an server context listener (part of Servlet API, not Spring).
You can use either implementations:
1) Implement interface InitializingBean. This approach is granted load all your beans then call afterPropertiesSet method.
#Override
public void afterPropertiesSet() throws Exception {
init();
}
2) Using JSR-250's Annotation #PostConstruct. This approach will not wait for spring beans to load.
#PostConstruct
public void init() {
}

Categories