作用
自定义一些 bean 的初始化时机,在自定义 bean 初始化初始化时做一些检查或者属性值获取
介绍
InitializingBean(关于这个接口的描述:Interface to be implemented by beans that need to react once all their properties have been set by a BeanFactory: for example, to perform custom initialization, or merely to check that all mandatory properties have been set。An alternative to implementing InitializingBean is specifying a custom init-method, for example in an XML bean definition.For a list of all bean lifecycle methods, see the BeanFactory javadocs/由Bean实现的接口,需要在BeanFactory设置完所有属性后作出反应。实现InitializingBean的替代方法是在XML bean定义中指定自定义的init-method)
InitializingBean 只有一个方法 afterPropertiesSet() (关于这个方法的描述:Invoked by a BeanFactory after it has set all bean properties supplied (and satisfied BeanFactoryAware and ApplicationContextAware). This method allows the bean instance to perform initialization only possible when all bean properties have been set and to throw an exception in the event of misconfiguration. @throws Exception in the event of misconfiguration (such as failure to set an essential property) or if initialization fails./此方法允许Bean实例仅在设置了所有Bean属性后才可能执行初始化)
通过以上介绍我们大致可以明白,实现的 InitializingBean 的方法是在 BeanFactory 设置完所有属性后执行初始化过程,并且在配置文件配置 init-method 和实现 InitializingBean 作用是一样的。两种方法是可以同时使用的,顺序是实现接口比配置文件 init-method 要先加载,两者执行的代码如下
public abstract class AbstractAutowireCapableBeanFactory extends AbstractBeanFactory
implements AutowireCapableBeanFactory {
@Override
public Object initializeBean(Object existingBean, String beanName) {
return initializeBean(beanName, existingBean, null);
}
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedAction<Object>() {
@Override
public Object run() {
invokeAwareMethods(beanName, bean);
return null;
}
}, getAccessControlContext());
}
else {
invokeAwareMethods(beanName, bean);
}
Object wrappedBean = bean;
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
}
try {
// 真正调用在这个方法里
invokeInitMethods(beanName, wrappedBean, mbd);
}
catch (Throwable ex) {
throw new BeanCreationException(
(mbd != null ? mbd.getResourceDescription() : null),
beanName, "Invocation of init method failed", ex);
}
if (mbd == null || !mbd.isSynthetic()) {
wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
}
return wrappedBean;
}
protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
// 判断是否是 InitializingBean 类型的bean
boolean isInitializingBean = (bean instanceof InitializingBean);
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if (logger.isDebugEnabled()) {
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
// 直接调用实现方法afterPropertiesSet()
((InitializingBean) bean).afterPropertiesSet();
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
throw pae.getException();
}
}
else {
((InitializingBean) bean).afterPropertiesSet();
}
}
if (mbd != null) {
// 判断是init-method方法,则执行init-method方法
String initMethodName = mbd.getInitMethodName();
if (initMethodName != null && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.isExternallyManagedInitMethod(initMethodName)) {
// init-method方法的原理,其实就是反射
invokeCustomInitMethod(beanName, bean, mbd);
}
}
}
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)
throws Throwable {
String initMethodName = mbd.getInitMethodName();
final Method initMethod = (mbd.isNonPublicAccessAllowed() ?
BeanUtils.findMethod(bean.getClass(), initMethodName) :
ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));
if (initMethod == null) {
if (mbd.isEnforceInitMethod()) {
throw new BeanDefinitionValidationException("Couldn't find an init method named '" +
initMethodName + "' on bean with name '" + beanName + "'");
}
else {
if (logger.isDebugEnabled()) {
logger.debug("No default init method named '" + initMethodName +
"' found on bean with name '" + beanName + "'");
}
// Ignore non-existent default lifecycle methods.
return;
}
}
if (logger.isDebugEnabled()) {
logger.debug("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");
}
if (System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
ReflectionUtils.makeAccessible(initMethod);
return null;
}
});
try {
AccessController.doPrivileged(new PrivilegedExceptionAction<Object>() {
@Override
public Object run() throws Exception {
initMethod.invoke(bean);
return null;
}
}, getAccessControlContext());
}
catch (PrivilegedActionException pae) {
InvocationTargetException ex = (InvocationTargetException) pae.getException();
throw ex.getTargetException();
}
}
else {
try {
// 真正反射的执行
ReflectionUtils.makeAccessible(initMethod);
initMethod.invoke(bean);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}
}
}
应用
@Component
public class TestInitlizingBean implements InitializingBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("InitializingBean 初始化了。。。。");
}
}
2020-05-27 20:12:03,328main o.h.e.t.j.p.i.JtaPlatformInitiator HHH000490: Using JtaPlatform implementation: [org.hibernate.engine.transaction.jta.platform.internal.NoJtaPlatform]
2020-05-27 20:12:03,920main o.s.o.j.LocalContainerEntityManagerFactoryBean Initialized JPA EntityManagerFactory for persistence unit 'default'
2020-05-27 20:12:03,932InitializingBean 初始化了。。。。
main org.neo4j.ogm.metadata.DomainInfo Starting Post-processing phase
2020-05-27 20:12:04,728main org.neo4j.ogm.metadata.DomainInfo Building byLabel lookup maps
2020-05-27 20:12:04,728main org.neo4j.ogm.metadata.DomainInfo Building interface class map for 19 classes
2020-05-27 20:12:04,729main org.neo4j.ogm.metadata.DomainInfo Post-processing complete
2020-05-27 20:12:04,902main o.s.s.concurrent.ThreadPoolTaskExecutor Initializing ExecutorService 'applicationTaskExecutor'
2020-05-27 20:12:05,092main o.s.b.w.embedded.tomcat.TomcatWebServer Tomcat started on port(s): 9317 (http) with context path ''
2020-05-27 20:12:05,325main com.just.JustApplication Started JustApplication in 5.812 seconds (JVM running for 7.342)