Spring AMQP ListenerContainer lifecycle management - spring

We are using Spring AMQP to connect to RabbitMQ in our Spring based web application.
When we declare our listener-containers as beans (using rabbit:listener-container) in application context, their lifecycle is managed by Spring.
If we declare a listener-container in a component inside a #PostConstruct method, or we create a bean with class org.springframework.amqp.rabbit.listener.SimpleMessageListenerContainer as a prototype scoped bean, we then have to manage the lifecycle i.e. start and stop the listener-container ourselves.
My question is, if we declare new queues, bindings and listener-containers inside a #PostConstruct method, just calling listener.stop/shutdown/destroy method inside the corresponding #PreDestroy method would be enough for a graceful shutdown? Or else what do I need to do?
Note: I am guessing I don't have to do anything for the new queues and bindings created in the #PostContruct, but I would be very glad if you also confirm this for me.

I would not recommend starting a listener container or declaring queues/bindings in an #PostConstruct method; the context is only half-baked at that time. It might work but it's not recommended to do stuff like that while the context is being initialized.
It's better to implement SmartLifecycle and start/stop them in the start()/stop() methods.
Then, the container lifecycles would be indirectly managed by the spring context.
You can also control exactly when your bean is started/stopped by putting it in a phase.

Related

Spring - how to debug to find specific use of spring's auto-wiring or a request parameter?

Spring is auto-wiring in a request parameter - let's call it "bob".
I don't know where nor how it is doing this, so I cannot debug it. What spring specific code (using intellij, so I can at lest set a conditional) would be appropriate to find where the auto-wiring of the request parameter is happening, so I can work out what the system is doing?
I think I understood the question, so I will try to answer it as best as I can.
You are facing a dilemma of choosing between managing your instances, or letting Spring manage them. If you let Spring manage dependency injection, you will often face situations where you wish you had more fine control over the beans lifecycle.
By default, Spring beans are "singletons", which means that only one
instance of that object will be created, and every class that demands
a dependency injection of that object will receive the same instance.
The first step on beans lifecycle is its construction. You can setup a breakpoint to catch that moment on any method annotated with #PostConstruct. This article describes the need of running some code on bean initialization, and how it is solved by this annotation. For example:
public class AnyBean {
#PostConstruct
public void init(){
// any code or breakpoints inserted here will
// be run whenever an instance of this bean is created.
// if a singleton bean, only one instance is created and,
// only one #PostConstruct will be called.
// If a bean is a prototype bean, a new instance will be created
// for every dependency injection, and hence one #PostConstruct
// will be called for each.
}
}

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.

Getting Spring object instantiation right

I'm new to Spring and a little confused about how it works. I get that I can use the application context to instantiate beans and have them populated. However, is the idea that I should be able to just write Bean b = new Bean() and then have Spring to somehow automagically populate that Bean?
I'm experimenting with Spring in a web application, and as far as I can see I need to inject the ApplicationContext into, say, the servlets to be able to instantiate other beans (services, daos etc.) from there. It's a bit cumbersome, but probably works.
However, is Spring meant to be able to hook into any object instantiation which happens on classes defined as beans in applicationContext.xml?
Spring is an Inversion of Control container. A bean is an object whose life cycle is managed by Spring. If you want Spring to populate an object, it needs to go through Spring, ie. it needs to be bean.
is Spring meant to be able to hook into any object instantiation
which happens on classes defined as beans in applicationContext.xml?
Spring doesn't hook into anything. You configure your beans and the relationships between them with Spring and Spring handles creating the instances and linking them up.
For domain objects, Spring provides a solution via the #Configurable annotation: http://docs.spring.io/spring/docs/4.0.0.RELEASE/spring-framework-reference/htmlsingle/#aop-atconfigurable
It requires compile- or load-time-weaving and, thus, introduces some additional complexity but having the convenience of using the standard new Bean() syntax plus Spring's autowiring is worth it in my opinion.
Alternatively, you could define your domain objects as beans with prototype scope and use some factory to create them using the Spring ApplicationContext.getBean() method. With a scope of prototype a new instance will be returned every time and since you go through the ApplicationContext, Spring will do all the dependency injection magic as usual.
As for services and other beans with singleton scope, you would typically NOT retrieve them by first injecting the ApplicationContext and using it but instead you would inject them via either a constructor, setter or annotation-based strategy. The documentation covers that in detail: http://docs.spring.io/spring/docs/4.0.0.RELEASE/spring-framework-reference/htmlsingle/#beans-factory-collaborators

Spring #PreDestroy method

I found out that #PreDestroy only work with singleton scoped bean. I was thinking what could go wrong if we use it with prototype scoped bean. Anything at all??? I dont think so. I think this is just not implemented in spring as they would have to keep the references to all the beans created. Tell me if i am wrong
Spring can only initialize/destroy beans it also controllers and basically prototype scoped beans aren't under the control of spring (after construction). It doesn't know when it is cleaned up, destroyed or what so ever. As such the #PreDestroy method isn't callable for prototype beans (as they do not have a clearly defined lifecycle like singletons or request scoped beans).
For "prototype" scoped beans, Spring does not call the #PreDestroy method.
Here is the answer from the Spring reference manual. Section 7.5.2
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-scopes-prototype
In contrast to the other scopes, Spring does not manage the complete lifecycle of a
prototype bean: the container instantiates, configures, and otherwise assembles a
prototype object, and hands it to the client, with no further record of that prototype
instance.
Thus, although initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called. The client code must clean up prototype-scoped objects and release expensive resources that the prototype bean(s) are holding.
To get the Spring container to release resources held by prototype-scoped beans, try using a custom bean post-processor, which holds a reference to beans that need to be cleaned up.
The #PreDestroy annotation does not belong to Spring, it’s located in the jsr250-api library jar under javax.annotation package.
By default, Spring will not aware of the #PreDestroy annotation. To enable it, you have to either register CommonAnnotationBeanPostProcessor or specify the <context:annotation-config /> in bean XML configuration file.

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