How to call a method after bean initialization is complete? - spring

I have a use case where I need to call a (non-static) method in the bean only-once at the ApplicationContext load up. Is it ok, if I use MethodInvokingFactoryBean for this? Or we have a some better solution?
As a side note, I use ConfigContextLoaderListener to load the Application Context in web application. And want, that if bean 'A' is instantiated just call methodA() once.
How can this be done nicely?

To expand on the #PostConstruct suggestion in other answers, this really is the best solution, in my opinion.
It keeps your code decoupled from the Spring API (#PostConstruct is in javax.*)
It explicitly annotates your init method as something that needs to be called to initialize the bean
You don't need to remember to add the init-method attribute to your spring bean definition, spring will automatically call the method (assuming you register the annotation-config option somewhere else in the context, anyway).

You can use something like:
<beans>
<bean id="myBean" class="..." init-method="init"/>
</beans>
This will call the "init" method when the bean is instantiated.

There are three different approaches to consider, as described in the reference
Use init-method attribute
Pros:
Does not require bean to implement an interface.
Cons:
No immediate indication in source code that this method is required after construction to ensure the bean is correctly configured.
Implement InitializingBean
Pros:
No need to specify init-method, or turn on component scanning / annotation processing.
Appropriate for beans supplied with a library, where we don't want the application using this library to concern itself with bean lifecycle.
Cons:
More invasive than the init-method approach.
Use JSR-250 #PostConstruct lifecyle annotation
Pros:
Useful when using component scanning to autodetect beans.
Makes it clearer that a specific method is to be used for initialisation. Intent is closer to the code.
Cons:
Initialisation no longer centrally specified in configuration.
You must remember to turn on annotation processing (which can sometimes be forgotten)

Have you tried implementing InitializingBean? It sounds like exactly what you're after.
The downside is that your bean becomes Spring-aware, but in most applications that's not so bad.

You could deploy a custom BeanPostProcessor in your application context to do it. Or if you don't mind implementing a Spring interface in your bean, you could use the InitializingBean interface or the "init-method" directive (same link).

To further clear any confusion about the two approach i.e use of
#PostConstruct and
init-method="init"
From personal experience, I realized that using (1) only works in a servlet container, while (2) works in any environment, even in desktop applications. So, if you would be using Spring in a standalone application, you would have to use (2) to carry out that "call this method after initialization.

Related

How to provide custom logic to search for bean if it cannot be found in Spring Context

If the Spring context cannot find a bean referred to from my xml I want to be able to provide some custom logic (ie look in another Spring Context or create the bean programmatically) before a BeanNotFoundException (whatever the expection is) is thrown.
You can use the BeanFactoryPostProcessor to define your beans dynamically (click on the link for an explanation).
Alternatively if you want to act on your bean in a lazy manner (instead of at app startup), which I strongly recommend not to do since you will have bugs related to the state of you beans config that is not visible at compile time: Anyway, you can surely add to your ApplicationContext a custom singleton : instead of calling getBean() from spring, if nothing was found, your class will be called to respond which bean corresponds to a bean name, and you will indirectly have the opportunity to handle BeanNotFoundException
See a post about the second (not recommended) solution here : How to add Properties to an Application Context

How to instantiate Spring bean with custom scope and #Autowired dependencies?

In our project, we use Spring request scoped beans. Now we've a requirement to support async requests and request scoped beans don't work for child threads. I'm aware of RequestContextFilter and it's "support" for async but it appears that RequestContextFilter expects the main thread to wait for the child threads to finish, which isn't the case for us. Our main thread immediately returns after spawning new threads using #Async annotation and DispatcherServlet clears out the RequestContextHolder. Thus when the child threads get to the point where they need a request scoped bean, #Autowired fails.
I'm also aware of SimpleThreadScope but it doesn't clean up thread-local attributes and in a thread-pooling situation, is not only dangerous to use but downright useless.
What I need is a custom scope. So far, I've found 3 useful examples but all of them fall short in that the beans they instantiate as part of the custom scope are plain POJOs without any dependencies. Needless to say that's non-existent in a real life application. Can anyone suggest a way to instantiate custom scoped beans that have #Autowired dependencies on beans from other scopes?
What I found so far:
https://github.com/spring-by-example/spring-by-example/tree/master/modules/sbe-thread-scope/src/main/java/org/springbyexample/bean/scope/thread
https://github.com/billkoch/spring-async-mdc
Spring Bean Custom Scope JMS
Continuing the discussion from the other question's answer here...
See the Spring Documentation about scoped beans as dependencies.
.
I'm referring to the <aop:scoped-proxy/> which is what the link points to. Each time the autowired field is referenced, your custom scope's get() method is called to lookup the instance based on some criteria.
.
I understand I can look up the dependencies (though unsure how, a scope isn't a bean, perhaps I need to pass application context during instantiation?). What I don't understand is how to inject those dependencies into my bean if those're marked #Autowired? Or are you saying the custom scoped bean shouldn't have #Autowired dependencies?
It works automatically; Spring injects a proxy for the bean and the scope.get() is invoked on every method call on that bean, returning the specific instance you want in the context of the current invocation.
Take a look at the AbstractRequestAttributesScope to see how it works (in that case, gets the instance from the HTTP Request and, if it doesn't exist, creates it).
So, your code calls foo() on the proxy; the framework calls the scope to get the desired instance and then calls foo() on that instance.
The exposed methods you wish to call must either be on an interface or not declared final.

Should a bean be initialized even if it does not have auto-wiring annotations?

If I have a bean defined in an xml file like so :
<bean id="myBean" class="com.myClass">
</bean>
Should "myBean" be autowired, ie should the class "com.myClass" be initialized by Spring ?
I have no Spring annotations in "com.myClass" but the class still seems to be initialized because it is declared in an xml file.
Yes, it is normal that your class to be initialised even though auto-wiring is not stated. The reason for this is:
Declared Spring beans have a life-cycle and the first step in this life-cycle is for Spring to initialise the bean.
The basic life-cycle is as follows:
Initialise Bean
Insert values
Calling certain methods depending on which interfaces you implement. This is useful for further custom initialisation and configuration.
Now your bean is ready for use by your application and will stay in the application context until your application context is destroyed.
Finally, if you implement the DisposableBean interface, the destroy method is called for any de-initialisation process that you may require.
This depends on whether you have any other beans that want Spring to inject myBean into them. If no one uses your bean, you can omit it.

Load Spring bean at the end

I have 20 beans in my application-context,I want to load a particular bean after all the beans are loaded. Is there a way for this?
You can use depends-on to force bean initialization order.
For example if bean1 depends on bean2 and bean3, you can put:
<bean id="bean1" class="YourBean" depends-on="bean2,bean3">
in your spring context.
As #skaffman said, this is a very strange requirement. Depending on your needs there are better solutions:
If you just need to start a process when Spring context is initialized, don't use a #PostConstruct annotated method (or an InitializingBean). ApplicationListener is probably what you need.
If you are worried because you need some beans injected in a #PostConstruct annotated method don't bother: Spring is usually smart enough for resolving such dependencies. If it isn't in your case, maybe you have an overcomplicated bean design.
If this isn't enough, you can follow #soulcheck instructions. This answer can probably help you in order to get cleaner configuration files.
If this don't help you, please give us some more information on what are you trying to achieve.

Spring calling 'destroy' method on session/request scoped beans

How does Spring know when to call 'destory' method on a session/request scoped bean (in other words, how does it detect that the concerned bean is going out of scope)?
I read somewhere that it uses request/session listeners to be notified of these events. But these listners need to be defined in web.xml, and there's no mention of defining such listeners in Spring literature. So how does this work?
The org.springframework.web.servlet.DispatcherServlet does it. It uses own code, e.g. the org.springframework.web.context.request.RequestAttributes#registerDestructionCallback callback list functionality to register all these scoped beans.
and there's no mention of defining such listeners in Spring literature
Oh, there is:
To support the scoping of beans at the request, session, and global session levels (web-scoped beans), some minor initial configuration is required before you define your beans.[...]
If you use a Servlet 2.4+ web container, [...] you need to add the following javax.servlet.ServletRequestListener to the declarations in your web applications web.xml file[...]
From: 4.5.4.1 Initial web configuration.
Also note that Spring does not call destroy on prototype-scoped beans.
You can implement the interface DisposableBean and InitializingBean for session scoped bean.
The org.springframework.beans.factory.InitializingBean interface allows a bean to perform initialization work after all necessary properties on the bean have been set by the container. The InitializingBean interface specifies a single method afterPropertiesSet().
Implementing the org.springframework.beans.factory.DisposableBean interface allows a bean to get a callback when the container containing it is destroyed. The DisposableBean interface specifies a single method destroy().
Read more about it here: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/beans.html#beans-factory-nature

Resources