7

I've a little experience in Spring. And I wondering about the amount of callbacks in Spring Context/Bean Lifecycle. I've never used them, and can imaging situations in which the most of them are needed.

My question is: can you provide for each callback at least one example of usage? Means situations when you need that callback.

Conext callbacks: enter image description here

Bean callbacks: enter image description here

P.S.:

It is clear for me when majority of callbacks are calling, or what one or another implementation of ApplicationContext was written for. But I can't figure out why someone may want to profit from that callback\implementation. For example:

  • AbstractRefreshableApplicationContext is using to change bean configurations on fly. But Why? In which situation I may want to change bean's configuration on fly?
  • afterPropertiesSet callback, obviously is invoked after all bean's properties are setted :) But why I should know about that, and when I should (may want) use it?
VB_
  • 45,112
  • 42
  • 145
  • 293
  • 4
    Take each of those interfaces, google them with the term `javadoc` and look at the implementing classes. – Sotirios Delimanolis Jan 16 '14 at 13:39
  • But I asking about practical situations when people face the need to use these callbacks. Can I rely on that `javadoc` in such question? – VB_ Jan 16 '14 at 13:41
  • The javadoc explains what the interface is for. When you need that, that's when you use it. For the non-interface callbacks, again, they are pretty self-explanatory (or go to the documentation). `init-method` for setup, `destroy-method` for cleanup, etc. – Sotirios Delimanolis Jan 16 '14 at 13:42
  • Not all. For example, afterPropertySet(). But thanks, I'll through the docs. – VB_ Jan 16 '14 at 13:45
  • 1
    `InitializingBean` says `Interface to be implemented by beans that need to react once all their properties have been set by a BeanFactory`. If you look at a lot of the implementing classes, you will notice a lot of those also implement `FactoryBean`. Spring will first call `afterPropertiesSet` and then call `getObject()`. Source code is also a great place to look. – Sotirios Delimanolis Jan 16 '14 at 13:47
  • @Sotirios Delimanolis From `javadoc`: `AbstractRefreshableApplicationContext - implementation which are supposed to support multiple calls to refresh, creating a new internal bean factory instance every time.` So as I understand we can define new beans on the fly. But again, I haven't got enough experience to imagine why someone may want to change bean definition on the fly! I am not askin what does the implementation ro callback do, I just asking when\(in which situation) someone may want to get benefit of it. – VB_ Jan 16 '14 at 14:00
  • @Sotirios Delimanolis see P.S. section of the question, please. – VB_ Jan 16 '14 at 14:14

2 Answers2

6

can you provide for each callback at least one example of usage?

Look at the javadoc for each of the interfaces, check any of the implementing classes for their purpose and look up their source code for their implementation.

A typical bean definition would be

<bean id="someBean" class="com.example.beans.SomeBean">
    <property name="someProperty" value="42" />
    <property name="other" value="I will always love you." />
</bean>

with a class like

public class SomeBean {
    private String someProperty;
    private String other;
    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }
    public void setOther(String other) {
        this.other = other;
    }
}

But some times you have classes where you need to perform some logic based on the properties set

public class SomeBean {
    private String someProperty;
    private String other;
    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }
    public void setOther(String other) {
        this.other = other;
    }
    public void init() {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                // for example
                // send the two property values to some external service
            }
        });
        thread.start();
    }
}

This logic can only be performed after the properties have been set. In that case, you can have your class implement the InitializingBean interface (old school)

public class SomeBean implements InitializingBean {
    private String someProperty;
    private String other;
    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }
    public void setOther(String other) {
        this.other = other;
    }
    public void init() {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                // for example
                // send the two property values to some external service
            }
        });
        thread.start();
    }
    public void afterPropertiesSet() throws Exception {
        init();
    }
}

Or annotate it with @PostConstruct (new school)

public class SomeBean implements InitializingBean {
    private String someProperty;
    private String other;
    public void setSomeProperty(String someProperty) {
        this.someProperty = someProperty;
    }
    public void setOther(String other) {
        this.other = other;
    }
    @PostConstruct
    public void init() {
        Thread thread = new Thread(new Runnable() {
            public void run() {
                // for example
                // send the two property values to some external service
            }
        });
        thread.start();
    }
}

This is just an example. The InitializingBean interface is often used along with the FactoryBean interface. It helps to initialize the factory before it produces an object. For more example, see the javadoc of both of those interfaces and look up the source code of the various implementing classes. Do the same for the other *Aware interfaces.

As for AbstractRefreshableApplicationContext, some times you need to refresh() your ApplicationContext. This can happen because you want to reload an XML configuration or because your environment has changed, but you don't want to stop/re-start the application.

Sotirios Delimanolis
  • 274,122
  • 60
  • 696
  • 724
1

1. BeanFactoryPostProcessor:

I give this example as I see this answer: https://stackoverflow.com/a/2349891/4251461

He initially chose BeanFactory for use in integration/performance tests since He didn't want to load the entire application for testing isolated beans. However, He think BeanFactory doesn't support classpath XML configuration. So BeanFactory and ApplicationContext each provide a crucial feature I wanted, but neither did both.

He implements his own ApplicationContext which extends ClassPathXmlApplicationContext.

Here he could use BFPP instead of custom ApplicationContext.

public class LazyInitBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        String[] beanNames = beanFactory.getBeanDefinitionNames();
        for (String beanName : beanNames) {
            BeanDefinition bd = beanFactory.getBeanDefinition(beanName);
            bd.setLazyInit(true);
        }
    }

}

configure it in spring container like other regular beans:

<bean class="com.example.LazyInitBeanFactoryPostProcessor" />

You can also see the source of PropertyPlaceholderConfigurer and PropertyOverrideConfigurer in spring.

2. InitializingBean:

As Sotirios Delimanolis said: The InitializingBean interface is often used along with the FactoryBean interface. It helps to initialize the factory before it produces an object.

Here is an example.

import org.springframework.beans.factory.FactoryBean;
import org.springframework.beans.factory.InitializingBean;

import java.security.MessageDigest;

public class SampleDigesterFactory implements FactoryBean<MessageDigest>, InitializingBean {

    MessageDigest messageDigest;

    String algorithmName = "MD5";

    public MessageDigest getObject() throws Exception {
        return messageDigest;
    }

    public Class<?> getObjectType() {
        return MessageDigest.class;
    }

    public boolean isSingleton() {
        return true;
    }

    public void afterPropertiesSet() throws Exception {
        messageDigest = MessageDigest.getInstance(algorithmName);
    }

    public String getAlgorithmName() {
        return algorithmName;
    }

    public void setAlgorithmName(String algorithmName) {
        this.algorithmName = algorithmName;
    }
}


import java.security.MessageDigest;

public class SampleDigester {

    private MessageDigest messageDigest;

    public void digestMessage(String message) {
        System.out.println("digest message:" + message);
        System.out.println("result: " + messageDigest.digest(message.getBytes()));
    }

    public MessageDigest getMessageDigest() {
        return messageDigest;
    }

    public void setMessageDigest(MessageDigest messageDigest) {
        this.messageDigest = messageDigest;
    }
}

configure beans in spring container:

<bean id="messageDigesterFactoryMD5" class="com.example.SampleDigesterFactory" />
<bean id="messageDigesterFactorySHA1" class="com.example.SampleDigesterFactory" p:algorithmName="SHA1" />

<bean id="sampleDigesterMD5" class="com.example.SampleDigester" p:messageDigest-ref="messageDigesterFactoryMD5" />
<bean id="sampleDigesterSHA1" class="com.example.SampleDigester" p:messageDigest-ref="messageDigesterFactorySHA1" />

Test it:

SampleDigester sampleDigesterMD5 = context.getBean("sampleDigesterMD5", SampleDigester.class);
SampleDigester sampleDigesterSHA1 = context.getBean("sampleDigesterSHA1", SampleDigester.class);

sampleDigesterMD5.digestMessage("Hello World!");
sampleDigesterSHA1.digestMessage("Hello World!");

The output is:

digest message:Hello World!
result: [B@19d02cb
digest message:Hello World!
result: [B@1753b6d

The spring reference says:

The FactoryBeanconcept and interface is used in a number of places within the Spring Framework;more than 50 implementations of the FactoryBeaninterface ship with Spring itself.

3. BeanPostProcessor:

You can refer to source of RequiredAnnotationBeanPostProcessor in spring.

a BeanPostProcessorimplementation that ships with the Spring distribution which ensures that JavaBean properties on beans that are marked with an (arbitrary) annotation are actually (configured to be) dependency-injected with a value.

Community
  • 1
  • 1
Sealter
  • 301
  • 3
  • 7