Create an account

Very important

  • To access the important data of the forums, you must be active in each forum and especially in the leaks and database leaks section, send data and after sending the data and activity, data and important content will be opened and visible for you.
  • You will only see chat messages from people who are at or below your level.
  • More than 500,000 database leaks and millions of account leaks are waiting for you, so access and view with more activity.
  • Many important data are inactive and inaccessible for you, so open them with activity. (This will be done automatically)


Thread Rating:
  • 1056 Vote(s) - 3.46 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Do Spring prototype beans need to be destroyed manually?

#1
I noticed that the `@PreDestroy` hooks of my prototype scoped Spring beans were not getting executed.

I have since read [here][1] that this is actually by design. The Spring container will destroy singleton beans but will not destroy prototype beans. It is unclear to me why. If the Spring container will create my prototype bean and execute its `@PostConstruct` hook, why will it not destroy my bean as well, when the container is closed? Once my Spring container has been closed, does it even make sense to continue using any of its beans? I cannot see a scenario where you would want to close a container before you have finished with its beans. Is it even possible to continue using a prototype Spring bean after its container has been closed?

The above describes the puzzling background to my primary question which is: If the Spring container is not destroying prototype beans, does that mean a memory leak could occur? Or will the prototype bean get garbage-collected at some point?

The Spring documentations states:

> 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.

What does that mean? The text suggests to me that I, as the programmer am responsible for explicitly (manually) destroying my prototype beans. Is this correct? If so, how do I do that?


[1]:

[To see links please register here]

Reply

#2
For the benefit of others, I will present below what I have gathered from my investigations:

As long as the prototype bean does not itself hold a reference to another resource such as a database connection or a session object, it will get garbage collected as soon as all references to the object have been removed or the object goes out of scope. It is therefore usually not necessary to explicitly destroy a prototype bean.

However, in the case where a memory leak may occur as described above, prototype beans can be destroyed by creating a singleton bean post-processor whose destruction method explicitly calls the destruction hooks of your prototype beans. Because the post-processor is itself of singleton scope, its destruction hook *will* get invoked by Spring:

1. Create a bean post processor to handle the destruction of all your prototype beans. This is necessary because Spring does not destroy prototype beans and so any @PreDestroy hooks in your code will never get called by the container.

2. Implement the following interfaces:

1.**BeanFactoryAware**<br>
This interface provides a callback method which receives a Beanfactory object. This BeanFactory object is used in the post-processor class to identify all prototype beans via its BeanFactory.isPrototype(String beanName) method.
<br>
<br>2. **DisposableBean**<br>
This interface provides a Destroy() callback method invoked by the Spring container. We will call the Destroy() methods of all our prototype beans from within this method.
<br>
<br>3. **BeanPostProcessor**<br>
Implementing this interface provides access to post-process callbacks from within which, we prepare an internal List<> of all prototype objects instantiated by the Spring container. We will later loop through this List<> to destroy each of our prototype beans.

<br> 3. Finally implement the DisposableBean interface in each of your prototype beans, providing the Destroy() method required by this contract.

To illustrate this logic, I provide some code below taken from this [article][1]:

/**
* Bean PostProcessor that handles destruction of prototype beans
*/
@Component
public class DestroyPrototypeBeansPostProcessor implements BeanPostProcessor, BeanFactoryAware, DisposableBean {

private BeanFactory beanFactory;

private final List<Object> prototypeBeans = new LinkedList<>();

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (beanFactory.isPrototype(beanName)) {
synchronized (prototypeBeans) {
prototypeBeans.add(bean);
}
}
return bean;
}

@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}

@Override
public void destroy() throws Exception {
synchronized (prototypeBeans) {
for (Object bean : prototypeBeans) {
if (bean instanceof DisposableBean) {
DisposableBean disposable = (DisposableBean)bean;
try {
disposable.destroy();
} catch (Exception e) {
e.printStackTrace();
}
}
}
prototypeBeans.clear();
}
}
}


[1]:

[To see links please register here]

Reply

#3
Your answer is great. I'd also like to share some notes on an alternative solution that allows prototype members which are natively managed by the Spring IoC container lifecycle through the use of the inner beans.

I recently wrote an [answer][1] to a separate question on inner beans. Inner beans are created by assigning bean property values as `BeanDefinition` objects. Bean definition property values are automatically resolved to `(inner)` instances (as managed singleton beans) of the bean that they define.

The following XML context configuration element can be used to create distinct autowireable `ForkJoinPool` beans for each reference which will be managed (`@PreDestroy` will be called on context shutdown):

<!-- Prototype-scoped bean for creating distinct FJPs within the application -->
<bean id="forkJoinPool" class="org.springframework.beans.factory.support.GenericBeanDefinition" scope="prototype">
<property name="beanClass" value="org.springframework.scheduling.concurrent.ForkJoinPoolFactoryBean" />
</bean>

This behavior is contingent upon the reference being assigned as a _property value_ of a bean definition, though. This means that `@Autowired`- and constructor-injection do not work with this by default, since these autowiring methods resolve the value immediately rather than using the property value resolution in [`AbstractAutowireCapableBeanFactory#applyPropertyValues`][2]. Autowiring by type will also not work, as type-resolution will not propagate through beans that are `BeanDefinition`s to find the produced type.

**This method will only work if either of the two conditions are true:**

- The dependent beans are _also_ defined in XML
- _Or_ if the autowire mode is set to `AutowireCapableBeanFactory#AUTOWIRE_BY_NAME`

</

<!-- Setting bean references through XML -->
<beans ...>
<bean id="myOtherBean" class="com.example.demo.ForkJoinPoolContainer">
<property name="forkJoinPool" ref="forkJoinPool" />
</bean>
</beans>

<!-- Or setting the default autowire mode -->
<beans default-autowire="byName" ...>
...
</beans>

Two additional changes could likely be made to enable constructor-injection and `@Autowired`-injection.

- **Constructor-injection:**

The bean factory assigns an `AutowireCandidateResolver` for constructor injection. The default value (`ContextAnnotationAutowireCandidateResolver`) could be overridden (`DefaultListableBeanFactory#setAutowireCandidateResolver`) to apply a candidate resolver which seeks eligible beans of type `BeanDefinition` for injection.

- **`@Autowired`-injection:**

The `AutowiredAnnotationBeanPostProcessor` bean post processor directly sets bean values without resolving `BeanDefinition` inner beans. This post processor could be overridden, or a separate bean post processor could be created to process a custom annotation for managed prototype beans (e.g., `@AutowiredManagedPrototype`).


[1]:

[To see links please register here]

[2]:

[To see links please register here]

Reply



Forum Jump:


Users browsing this thread:
1 Guest(s)

©0Day  2016 - 2023 | All Rights Reserved.  Made with    for the community. Connected through