當Bean在所有的屬性被BeanFactory
設置後需要進行一些客制化的調整,則Bean可實作InitializingBean
介面來客制Bean的初始化。
InitializingBean
介面需要實作方法為afterPropertiesSet()
。此方法在BeanFactory
把Bean所有的屬性值設置好後會被呼叫。
Spring的Bean實例是透過BeanFactory
的實作類AbstractBeanFactory
產生,
經由AbstractBeanFactory.getBean()
,
AbstractBeanFactory.doGetBean()
,
AbstractAutowireCapableBeanFactory.createBean()
,
AbstractAutowireCapableBeanFactory.doCreateBean()
,
AbstractAutowireCapableBeanFactory.initializeBean()
,
AbstractAutowireCapableBeanFactory.invokeInitMethods()
等方法。
而InitializingBean.afterPropertiesSet()
是在AbstractAutowireCapableBeanFactory.invokeInitMethods()
中被調用的。
以下節錄自AbstractAutowireCapableBeanFactory.invokeInitMethods()
原始碼。
AbstractAutowireCapableBeanFactory
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
...
/**
* Give a bean a chance to react now all its properties are set,
* and a chance to know about its owning bean factory (this object).
* This means checking whether the bean implements InitializingBean or defines
* a custom init method, and invoking the necessary callback(s) if it does.
* @param beanName the bean name in the factory (for debugging purposes)
* @param bean the new bean instance we may need to initialize
* @param mbd the merged bean definition that the bean was created with
* (can also be {@code null}, if given an existing bean instance)
* @throws Throwable if thrown by init methods or by the invocation process
* @see #invokeCustomInitMethod
*/
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
throws Throwable {
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isTraceEnabled()) {
logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged((PrivilegedExceptionAction>Object<) () -> {
((InitializingBean) bean).afterPropertiesSet();
return null;
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet(); // <--
}
}
if (mbd != null && bean.getClass() != NullBean.class) {
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
...
}
InitializingBean
用法如下,只要把該Bean類實作InitializingBean
並覆寫afterPropertiesSet()
方法即可。
DemoBean
@Component
public class DemoBean implements InitializingBean {
@Override
public void afterPropertiesSet() {
// 寫一些自訂的Bean屬性設置後的初始邏輯
}
}
應用場景包括Spring Bean初始化後一些額外設定值的載入,屬性值的驗證及調整修改等。
不過Spring官方不推薦實作InitializingBean
來自訂Bean初始化的邏輯,因為那會與Spring耦合,建議改用JavaEE的@PostConstruct
annotation來自訂Bean初始化的邏輯。
DemoBean
@Component
public class DemoBean {
@PostConstruct
public void init() {
// 寫一些自訂的Bean屬性設置後的初始邏輯
}
}
參考:
沒有留言:
張貼留言