Spring Context和Bean Lifecycle回调:实际的使用示例

时间:2014-01-16 13:38:13

标签: java spring

我在Spring有一点经验。我想知道Spring Context / Bean Lifecycle中的回调量。我从来没有使用它们,并且可以成像需要大部分的情况。

我的问题是 您是否可以为每个回调提供至少一个使用示例?表示您需要回调时的情况。< / p>

Conext回调: enter image description here

Bean回调: enter image description here

P.S:

当大多数回调调用时,或者为ApplicationContext编写了一个或另一个实现时,很明显。但我无法弄清楚为什么有人可能想要从回调\实施中获利。例如:

  • AbstractRefreshableApplicationContext用于在飞行中更改bean配置。但为什么?在哪种情况下,我可能想在飞行中更改bean的配置?
  • afterPropertiesSet回调,显然是在设置了所有bean的属性后调用的:)但为什么我应该知道这一点,何时应该(可能想要)使用它?

2 个答案:

答案 0 :(得分:4)

  

你能为每个回调提供至少一个使用示例吗?

查看每个接口的javadoc,检查任何实现类是否有用,并查找其源代码以实现它们。

典型的bean定义是

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

有一个类

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 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();
    }
}

此逻辑只能在设置属性后执行。在这种情况下,您可以让您的班级实现InitializingBean界面(旧学校)

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();
    }
}

或使用@PostConstruct(新学校)

对其进行注释
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();
    }
}

这只是一个例子。 InitializingBean接口通常与FactoryBean接口一起使用。它有助于在生成对象之前初始化工厂。有关更多示例,请参阅这两个接口的javadoc并查找各种实现类的源代码。对其他*Aware接口执行相同操作。

至于AbstractRefreshableApplicationContext,有时您需要refresh() ApplicationContext。这可能是因为您要重新加载XML配置,或者因为您的环境已更改,但您不想停止/重新启动应用程序。

答案 1 :(得分:0)

<强> 1。 BeanFactoryPostProcessor时:

我在看到这个答案时给出了这个例子:https://stackoverflow.com/a/2349891/4251461

他最初选择BeanFactory用于集成/性能测试,因为他不想加载整个应用程序来测试孤立的bean。但是,他认为BeanFactory不支持类路径XML配置。所以BeanFactory和ApplicationContext都提供了我想要的关键功能,但两者都没有。

他实现了自己的ApplicationContext,它扩展了ClassPathXmlApplicationContext。

在这里,他可以使用BFPP而不是自定义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);
        }
    }

}

像其他常规bean一样在spring容器中配置它:

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

您还可以在春季看到PropertyPlaceholderConfigurer和PropertyOverrideConfigurer的来源。

<强> 2。的InitializingBean:

正如Sotirios Delimanolis所说:InitializingBean接口通常与FactoryBean接口一起使用。它有助于在生成对象之前初始化工厂。

这是一个例子。

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;
    }
}

在spring容器中配置bean:

<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" />

测试它:

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

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

输出结果为:

摘要信息:Hello World!
结果:[B @ 19d02cb
消化信息:Hello World!
结果:[B @ 1753b6d

春季参考文献说:

  

FactoryBeanconcept和接口在Spring Framework中的许多地方使用; FactoryBeaninterface的50多个实现随Spring一起提供。

第3。的BeanPostProcessor:

您可以在spring中引用RequiredAnnotationBeanPostProcessor的源代码。

  

与Spring发行版一起提供的BeanPostProcessorimplementation,它确保使用(任意)注释标记的bean上的JavaBean属性实际上(配置为)依赖注入值。