Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring context dynamic change

Tags:

java

spring

I've read that dynamic bean definition change. I try it in a simple code example (see code below), and I find it very attractive in situations where I don't want to stop server but add/change bean definition.

Questions:

  1. Is it safe do to so (see code below)?
  2. I've read that it is possible to achieve bean definition change in runtime with help of StaticApplicationContex or BeanPostProcessor or BeanFactoryPostProcessor? So what is the difference?

    public class Main {
    final static String header = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
            "<beans xmlns=\"http://www.springframework.org/schema/beans\"\n" +
            "       xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\"\n" +
            "       xmlns:context=\"http://www.springframework.org/schema/context\"\n" +
            "       xsi:schemaLocation=\"http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\">\n" +
            "    <context:annotation-config />\n" +
            "    <context:component-scan base-package=\"vbah\"/>";
    
    final static String contextA =
            "<bean id=\"test\" class=\"java.lang.String\">\n" +
                    "\t\t<constructor-arg value=\"fromContextA\"/>\n" +
                    "</bean></beans>";
    
    final static String contextB =
            "<bean id=\"test\" class=\"java.lang.String\">\n" +
                    "\t\t<constructor-arg value=\"fromContextB\"/>\n" +
                    "</bean></beans>";
    
    public static void main(String[] args) throws IOException {
        //create a single context file
        final File contextFile = new File("src/resources/spring-config.xml");
    
        //write the first context into it
        FileUtils.writeStringToFile(contextFile, header + contextA);
    
        //create a spring context
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext(
                new String[]{contextFile.getPath()}
        );
    
        //echo "fromContextA"
        System.out.println(context.getBean("test"));
    
        //write the second context into it
        FileUtils.writeStringToFile(contextFile, header + contextB);
    
        //refresh the context
        context.refresh();
    
        //echo "fromContextB"
        System.out.println(context.getBean("test"));
    }
    }
    

EDIT:

Can you answer the questions below:

  1. As I understand BeanPostProcess allow you to modify already existed bean instances at runtime by wrapping the object with proxy. Am I right?
  2. AbstractApplicationContext#refresh() drop all singleton beans and recreate them.

    • But If I want to change the definition of prototype/custom scoped bean?
    • If I've got two beans: A and B. A has reference to B. If I change the bean definition in such way that it doesn't contain definition of B. Than B instances will be destroyed, but new instances won't be created. Than A will get a null dependency. Am I right?
  3. StaticApplicationContext and BeanFactoryPostProcessor both allow me to change a bean definition in runtime. But what are the difference, pros/cons?

  4. [Main question] Why Spring has 3 mechanism to achieve the same goal. Can you make a brief compoarison (or usecases examples) between AbstractApplicationContext#refresh(), StaticApplicationContext and BeanFactoryPostProcessor please.
like image 209
VB_ Avatar asked Jan 19 '14 18:01

VB_


People also ask

How to change properties in a file during runtime in spring?

To change properties in a file during runtime, we should place that file somewhere outside the jar. Then, we'll tell Spring where it is with the command-line parameter –spring.config.location=file:// {path to file}. Or, we can put it in application.properties. In file-based properties, we'll have to choose a way to reload the file.

What is applicationcontext in Spring Boot?

Furthermore, it provides more enterprise-specific functionalities. The important features of ApplicationContext are resolving messages, supporting internationalization, publishing events, and application-layer specific contexts. This is why we use it as the default Spring container.

Is there an out-of-box configuration for dynamic context paths?

For dynamic context paths there really is no out-of-box configuration since the context path is static. Now, why would you want multiple or dynamic context paths?

How do I load properties from an external file in spring?

Reloading Properties from External File To change properties in a file during runtime, we should place that file somewhere outside the jar. Then, we'll tell Spring where it is with the command-line parameter –spring.config.location=file:// {path to file}.


1 Answers

Is it safe do to so (see code below)?

You'll have to define safe.

The AbstractApplicationContext#refresh() method javadoc states

As this is a startup method, it should destroy already created singletons if it fails, to avoid dangling resources. In other words, after invocation of that method, either all or no singletons at all should be instantiated.

Basically every bean in your context will be destroyed and all references to them will be dropped, making them candidates for garbage collection. You need to make sure that those beans have appropriate ways to release any resources they might have. There are different ways to do that

  • Make your class implement the DisposableBean interface.
  • Add a destroy-method attribute to your <bean> or @Bean definition.
  • Annotate a method with @PreDestroy.

Note that refresh() will typically eagerly refresh your ApplicationContext, ie. re-instantiate all the beans immediately. You may notice some slow down in your application while that happens.

I've read that it is possible to achieve bean definition change in runtime with help of StaticApplicationContext or BeanPostProcessor or BeanFactoryPostProcessor? So what is the difference?

StaticApplicationContext is one of the ApplicationContext classes where you register the bean definitions yourself. In your example, the bean definitions are parsed from your XML file and registered behind the scenes. With StaticApplicationContext, you use registerBeanDefinition(..) or the other registerXxx() methods to explicitly register a bean definition.

A BeanFactoryPostProcessor has access to the BeanFactory being used and therefore all the bean definitions that have been registered. As such, you can retrieve any BeanDefinition you want and modify it. As the javadoc for BeanFactoryPostProcess#postProcessBeanFactory(..) states

All bean definitions will have been loaded, but no beans will have been instantiated yet. This allows for overriding or adding properties even to eager-initializing beans.

You can change the bean definition before the ApplicationContext actually uses it.

Finally, a BeanPostProcessor doesn't change the bean definition. You can use a BeanPostProcessor to change how a bean is created but the underlying BeanDefinition will stay the same.


For your edit (which is bigger than the actual answer :) )

As I understand BeanPostProcess allow you to modify already existed bean instances at runtime by wrapping the object with proxy. Am I right?

It's not just for proxying, you can do anything you want with the object: modify its properties, register it in some other context, make it null, etc. This goes around the bean definition.

AbstractApplicationContext#refresh() drop all singleton beans and recreate them.

But If I want to change the definition of prototype/custom scoped bean? If I've got two beans: A and B. A has reference to B. If I change the bean definition in such way that it doesn't contain definition of B. Than B instances will be destroyed, but new instances won't be created. Than A will get a null dependency. Am I right?

In an ApplicationContext, you declare your bean definitions. If you're going to change a bean definition, change it in a BeanFactoryPostProcessor or declare it differently in the context configuration.

For dependencies, if you destroy the B bean definition, there won't be a bean to inject into A and Spring will complain, throwing NoSuchBeanDefinitionException. Bean injection never injects null unless you explicitly tell it to.

StaticApplicationContext and BeanFactoryPostProcessor both allow me to change a bean definition in runtime. But what are the difference, pros/cons?

The two serve completely different purposes. StaticApplicationContext is an ApplicationContext implementation. Here, you declare bean definitions. A BeanFactoryPostProcessor serves to modify those bean definitions in any way, based on whatever condition you care to implement.

Why Spring has 3 mechanism to achieve the same goal. Can you make a brief comparison (or usecases examples) between AbstractApplicationContext#refresh(), StaticApplicationContext and BeanFactoryPostProcessor please.

The goal is not the same. An ApplicationContext is different than a BeanFactoryPostProcessor and comes into play at a different time in the context life cycle (see that nice graph you had in a previous question).

I don't have use cases for you. Learn what each of the above can do and you'll know when to apply them when you get specific requirements.

like image 106
Sotirios Delimanolis Avatar answered Nov 15 '22 17:11

Sotirios Delimanolis