Spring的方法注入
阿新 • • 發佈:2019-02-14
當一個Bean依賴的Bean和自己生命週期不同的時候:如Bean A依賴Bean B,Bean A 是singleton,如果需要在Bean A每次用到Bean B的時候都用一個Bean B的新的例項,通過在配置檔案中通過 property或者 contructor-arg是不能實現的.這時候只能在Bean A中用Bean B的時候動態得到.通常的做法有兩種:
1,Bean A實現 ApplicationContextAware, Spring初始化的時候會將 ApplicationContext 傳給Bean A,Bean A通過getBean("BeanB")方法每次得到Bean B.("BeanB"最好不要hardcode,通過property傳入)例:
2,方法注入:在Bean A中定義一個方法,返回型別是Bean B,在配置檔案中通過"lookup-method"告訴Spring動態覆蓋該方法,並返回Bean B的一個例項:public class ContextAwareBean implements ApplicationContextAware { protected static final Log log = LogFactory.getLog(AnotherBean.class); private String anotherBeanName; private ApplicationContext applicationContext; public String getAnotherBeanName() { return anotherBeanName; } public void setAnotherBeanName(String anotherBeanName) { this.anotherBeanName = anotherBeanName; } public void process() { log.info("process applicationContext " + applicationContext); AnotherBean anotherBean = createAnotheBean(); anotherBean.doSth(); } protected AnotherBean createAnotheBean() { return this.applicationContext.getBean(anotherBeanName, AnotherBean.class); } public void setApplicationContext(ApplicationContext applicationContext){ log.info("setApplicationContext " + applicationContext); this.applicationContext = applicationContext; } } public class AnotherBean { protected static final Log log = LogFactory.getLog(AnotherBean.class); public String doSth(){ log.info("AnotherBean.doSth"); return "do something"; } } <bean id="AnotherBean" class="com.test.spring.di.mtddi.AnotherBean" scope="prototype"/> <bean id="ContextAwareBean" class="com.test.spring.di.mtddi.ContextAwareBean" > <property name="anotherBeanName" value="AnotherBean"/> </bean>
客戶端程式碼:public abstract class ReplacedBean { protected static final Log log = LogFactory.getLog(ReplacedBean.class); public void process() { AnotherBean anotherBean = createAnotheBean(); anotherBean.doSth(); } protected abstract AnotherBean createAnotheBean(); } <bean id="AnotherBean" class="com.test.spring.di.mtddi.AnotherBean" scope="prototype"/> <bean id="ReplacedBean" class="com.test.spring.di.mtddi.ReplacedBean" > <lookup-method name="createAnotheBean" bean="AnotherBean"/> </bean>
public class MtddiClient {
private static BeanFactory factory;
private static ApplicationContext ctx;
static {
Resource resource = new ClassPathResource("conf/mtddiAppcontext.xml");
factory = new XmlBeanFactory(resource);
ctx = new ClassPathXmlApplicationContext("conf/mtddiAppcontext.xml");
}
/**
* @param args
*/
public static void main(String[] args) {
/*不能通過bean factory的方式得到bean
ContextAwareBean bean = (ContextAwareBean) factory.getBean("ContextAwareBean");
bean.process();
*/
//ContextAwareBean 只能從ApplicationContext獲得bean
//ContextAwareBean bean = (ContextAwareBean) ctx.getBean("ContextAwareBean");
//bean.process();
ReplacedBean bean1 = (ReplacedBean) factory.getBean("ReplacedBean");
bean1.process();
}
}
*對於實現ApplicationContextAware的Bean,必須用 ApplicationContext的getBean方法.對於方法注入(lookup-method方式):用BeanFactory和ApplicationContext的getBean都可以.如果要用BeanFactory,應該實現BeanFactoryAware:public class BeanFactoryAwareBean implements BeanFactoryAware {
protected static final Log log = LogFactory.getLog(BeanFactoryAwareBean.class);
private String anotherBeanName;
private BeanFactory beanFactory;
public String getAnotherBeanName() {
return anotherBeanName;
}
public void setAnotherBeanName(String anotherBeanName) {
this.anotherBeanName = anotherBeanName;
}
public void process() {
log.info("process beanFactory " + beanFactory);
AnotherBean anotherBean = createAnotheBean();
anotherBean.doSth();
}
protected AnotherBean createAnotheBean() {
return this.beanFactory.getBean(anotherBeanName, AnotherBean.class);
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
this.beanFactory = beanFactory;
}
}
兩種方法的比較:理論上來講,第二種方法更體現了IoC的思想,而且在bean類裡面沒有依賴到Spring,只是一個POJO.客戶端在使用它的時候可以是依靠Spring配置(lookup-method)來使用,也可以通過提供實現類來完成呼叫.