Spring core. Default #Bean destroy method - java

I have my own bean:
#Bean
public MyBean myBean(){...
following spring documentation to release its own resources I should specify destroyMethod. I've not found any default destroy methods called by spring in case if destroyMethod is not specified directly.
I used
#Bean(destroyMethod = "close")
public MyBean myBean(){...
but think about possibility to do not specify destroy method directly if it has value by default.
Does spring try something by default like destroy, close, release?
If spring tries some methods by default to release resources - which ones?

As documented in Bean.destroyMethod:
As a convenience to the user, the container will attempt to infer a
destroy method against an object returned from the #Bean method. For
example, given an #Bean method returning an Apache Commons DBCP
BasicDataSource, the container will notice the close() method
available on that object and automatically register it as the
destroyMethod. This 'destroy method inference' is currently limited
to detecting only public, no-arg methods named 'close' or 'shutdown'.
In other words, if you don't specify destroyMethod, but the bean has a public close() or shutdown() method, it will be automatically used as the destroy-method.
To disable this inference, use #Bean(destroyMethod = "").

You can implement a method which will be executed before destroying and annotate it with #PreDestroy
#PreDestroy
public void methodName() {
//Your code..
}

The org.springframework.beans.factory.DisposableBean interface specifies a single method −
void destroy() throws Exception;
Simply implement it −
public class ExampleBean implements DisposableBean {
public void destroy() {
// do some destruction work
}
}
for XML-based configuration
<bean id = "exampleBean" class = "examples.ExampleBean" destroy-method = "destroy"/>
and in the bean
public class ExampleBean {
public void destroy() {
// do some destruction work
}
}
or annotate with #PreDestroy

You can extend DisposableBeanAdapter class. One of the methods it provides is the destroy method being called by Spring. This way you don't have to provide any implementation while it is required when you're using DisposableBean interface.

Related

Can we use spring prototype bean together with try-with-resources?

Want to know if we can use spring prototype bean with try-with-resources mechanism:
MyResource implements AutoCloseable
Suppose I have a bean defined as:
#Configuration
public class ResourceCreation {
#Bean()
#Scope("prototype")
public MyResource createResource() {
return new MyResource("Test");
}
}
I have a factory class to generate the prototype beans:
public class ResourceFactory() {
#Autowired
ApplicationContext m_applicationContext;
public static generateResource() {
return m_applicationContext.getBean(MyResource.Class);
}
}
Then to use try-with-resources:
try (MyResource = ResourceFactory.generateResource()) {
...
}
So in this way, is there any problem? Because spring container should manage the lifecycle of the prototype bean.
Will the close() method in the MyResource gets called after the try block ends?
Short answer: Yes thanks to try-with-resources.
Long answer:
These two are completely unrelated concepts. You are mixing try-with-resources(1) which is a java concept and the destroyMethod(2), a callback method of a spring managed bean.
Explaining per point:
try-with-resources: it's a syntactic sugar (Java 1.7 or later) for:
MyResource myResource = ResourceFactory.generateResource();
try {
...
} finally {
myResource.close();
}
and it will be called for any class that implements java.lang.AutoCloseable or java.io.Closeable interface.
Reference: https://docs.oracle.com/javase/7/docs/technotes/guides/language/try-with-resources.html
destroyMethod it's a callback method, that spring lets you implement, called before the instance is destroyed by the container as per: https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-nature
But,
In case of a prototype bean, Spring does not manage his complete lifecycle; initialization lifecycle callback methods are called on all objects regardless of scope, in the case of prototypes, configured destruction lifecycle callbacks are not called.
Reference:
https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#beans-factory-scopes-prototype

Does calling #Bean methods create a new instance of the object or the bean instance?

In the code below, is calling bar() inside foo.setBar(bar()) and blah.setBar(bar()) using two difference instances of Bar? Or is it using a bean instance of Bar instead? If it's a bean instance, how does Spring do it automagically? Is it achieved by proxy?
#Configuration
public class AppConfig {
#Bean
public Foo foo() {
Foo foo = new Foo();
foo.setBar(bar());
return foo;
}
#Bean
public Bar bar() {
return new Bar();
}
#Bean
public Blah blah() {
Blah blah = new Blah();
blah.setBar(bar());
return blah;
}
}
Spring creates a proxy of your #Configuration annotated classes. This proxy intercepts #Bean method calls and caches the bean instances so that further calls to the same #Bean method refers to the same bean instance.
Hence in your case both calls to bar() method refers to the same Bar instance.The Bar instance is actually a singleton per application context.This is why the #Bean methods visibility is restricted to either protected , package or public because Spring needs to override your #Bean methods in the proxy.
Single bean instance will be used and it is achieved using proxies. Spring uses the concept of Inheritance based proxies to achieve this. Please take a look at - How to exactly work the Spring Inheritance-based Proxies configuration?
the same bean instance will be used in your case because a singleton scope is used by default for '#Bean' annotation.
yes, it's achived by spring proxying internals.

How do you refactor a #Transactional method to split out non-transactional parts

I have a data access class which runs as part of a stand-alone java application. It is currently working which means that a transaction manager is defined but I want to refactor the class to reduce the scope of the transaction but if I do I get org.hibernate.HibernateException: No Hibernate Session bound to thread, and configuration does not allow creation of non-transactional one here which implies that moving the #Transactional has somehow stopped it from being recognised.
My original version had the refactored methods being private but I found a recommendation to change that to public as in some cases the annotation would not be picked up.
public class DoStuff {
#Transactional
public void originalMethod() {
// do database stuff
...
// do non-database stuff that is time consuming
...
}
}
What I want to do is refactor to the following
public class DoStuff {
public void originalMethod() {
doDatabaseStuff()
doNonDatabaseStuff()
}
#Transactional
public void doDatabaseStuff() {
...
}
public void doNonDatabaseStuff() {
...
}
}
Edit:
You need to understand how Spring proxying works to understand why your refactoring does not work.
Method calls on the object reference will be calls on the proxy, and as such the proxy will be able to delegate to all of the interceptors (advice) that are relevant to that particular method call. However, once the call has finally reached the target object, any method calls that it may make on itself, are going to be invoked against the this reference, and not the proxy. This has important implications. It means that self-invocation is not going to result in the advice associated with a method invocation getting a chance to execute.
#Transactional uses Spring AOP, Spring uses proxies. This means that when you call an #Transactional method from another class, Spring will use a proxy, so the transactional advice will be applied. However, if you call the method from the same class, spring will use the "this" reference instead of the proxy, so that transactional advice will not be applied.
Original Answer:
Here is what worked for me in similar scenario.
public class DoStuff implement ApplicationContextAware {
private ApplicationContext CONTEXT;
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
public void originalMethod() {
getSpringProxy().doDatabaseStuff()
doNonDatabaseStuff()
}
private DoStuff getSpringProxy() {
return context.getBean(this.getClass());
}
#Transactional
public void doDatabaseStuff() {
...
}
public void doNonDatabaseStuff() {
...
}
}
Explanation:
Make the class ApplicationContextAware, so it has a reference to the context
When you need to call a transactional method, fetch the actual spring proxy from the context
Use this proxy to call your method, so that #Transactional is actually applied.
Your approach looks like it should work just fine, I expect the issue is related to Spring proxies.
The reason that I asked about interfaces is related to the default method by which Spring applies transactional behaviour - JDK dynamic proxies.
If the actual definition of your class is:
public class DoStuff implements Doable {
public void originalMethod() {
}
}
public interface Doable {
public void originalMethod();
}
If this is indeed the structure, when you moved to the new structure Spring is not able to proxy the new doDatabaseStuff method.
Your options to fix this:
Add the new methods to your interface to ensure that Spring can proxy them
Move to using CGLIB based proxies (these do not rely on interfaces)

Spring ApplicationListener is not receiving events

I have the following ApplicationListener:
package org.mycompany.listeners;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextStartedEvent;
public class MyApplicationListener implements ApplicationListener<ContextStartedEvent> {
public MyApplicationListener() {
super();
System.out.println("Application context listener is created!");
}
/**
* {#inheritDoc}
*/
public void onApplicationEvent(final ContextStartedEvent event) {
System.out.println("Context '" + event.getApplicationContext().getDisplayName() + "' is started!");
}
}
And the following bean definition:
<bean name="myApplicationListener" class="org.mycompany.listeners.MyApplicationListener" />
I can see that bean is created as message from the constructor is printed, but context start event is never recieved. What am I missing?
ContextStartedEvent is published when you explicitly invoke ConfigurableApplicationContext.start() on the context. If you need an event that is published when context is initialized, use ContextRefreshedEvent.
See also:
3.13.2 Standard and Custom Events
Since you have no lazy loaded beans (according to you) then you are most likely using events for the wrong reason and probably should use something like InitializingBean interface instead:
public class MyBean implements InitializingBean {
#Override
public void afterPropertiesSet() throws Exception {
// ...
}
}
From Spring manual:
To interact with the container's management of the bean lifecycle, you
can implement the Spring InitializingBean and DisposableBean
interfaces. The container calls afterPropertiesSet() for the former
and destroy() for the latter to allow the bean to perform certain
actions upon initialization and destruction of your beans. You can
also achieve the same integration with the container without coupling
your classes to Spring interfaces through the use of init-method and
destroy method object definition metadata.
Source: Spring Framework - Lifecycle callbacks
Not sure if this helps, but I vaguely remember having a similar problem, which was solved by preloading and not lazy loading. Here's a quick overview of both

Spring IoC - Ensuring all beans are created before #PostConstruct/afterProperiesSet

I've got a project using Spring IoC for dependency injection, and I'm trying to slightly simplify my model by having one central location for accessing most of my beans.
I'm running into a problem using the #PostConstruct mechanism, or alternatively when implementing the InitializingBean interface. While all the dependencies in that particular bean may have been resolved, the dependencies in injected beans may not have been. For example I have:
public class A {
public void doSomething() {};
}
public class B {
private A objectA;
#Required
public void setObjectA(A objectA) {
this.objectA = objectA;
}
public A getObjectA() {
return objectA;
}
}
public class C implements InitializingBean {
private B objectB;
#Required
public void setObjectB(B objectB) {
this.objectB = objectB;
}
public void afterPropertiesSet() throws Exception {
objectB.getObjectA().doSomething();
}
}
My context.xml file defines these three beans and injects the appropriate properties, but I get a NullPointerException when the object of class C gets instantiated and the afterPropertiesSet method is called, debugging shows me that the call to getObjectA() returns null. If I inject object A directly into class C I get no errors.
Is there a mechanism I can use to ensure that all beans have been completely instantiated before my afterPropertiesSet method / any method annotated with #PostConstruct is called?
Thanks,
Joseph.
The afterPropertiesSet() is little too early to call methods on injected dependencies. Indeed, the init-method (if you have that in XML) is called after afterPropertiesSet() and then postProcessAfterInitialization() of BeanPostProcessors are called. You have #Required annotation and so, ofcourse, RequiredAnnotationBeanPostProcessor is executed.
Lifecycle callback methods are what they are: they inform you about lifecycle events and their purpose is not to enable you to hijack the task that Spring is performing. (Though you can do it as you did when directly injecting object A in C- but it is not recommended).
If you want to use object A (or any other spring bean for that matter) in class C, then I would recommend to use ApplicationContextAware (or BeanFactoryAware as the case may be) and use getBean() method to get fully baked and ready to serve bean!
Implement ApplicationListener[ContextRefreshedEvent] and do your work in onApplicationEvent(). Word of caution - ContextRefreshedEvent is sometimes published multiple times, so you may want to set a flag after the first time you get it to ignore the additional events.
Use #DependsOn to ensure that A is instantiated before C.

Categories