我是靠谱客的博主 愉快茉莉,最近开发中收集的这篇文章主要介绍【spring源码分析】IOC容器初始化——查漏补缺(三),觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

前言:本文分析InitializingBean和init-method方法,其实该知识点在AbstractAutowireCapableBeanFactory#initializeBean方法中有所提及,这里对其进行详细分析。


InitializingBean

InitializingBean是一个接口,它只包含一个afterPropertiesSet方法:

 1 public interface InitializingBean {
 2
 3
/**
 4 
* 该方法在BeanFactory设置完了所有的属性之后被调用<br/>
 5 
* 该方法允许bean实例设置了所有bean属性时执行初始化工作,如果该过程出现了错误,则需要抛出异常<br/>
 6 
* Invoked by the containing {@code BeanFactory} after it has set all bean properties
 7 
* and satisfied {@link BeanFactoryAware}, {@code ApplicationContextAware} etc.
 8 
* <p>This method allows the bean instance to perform validation of its overall
 9 
* configuration and final initialization when all bean properties have been set.
10 
*
11 
* @throws Exception in the event of misconfiguration (such as failure to set an
12 
*
essential property) or if initialization fails for any other reason
13
*/
14
void afterPropertiesSet() throws Exception;
15
16 }

分析:

Spring在完成实例化后,设置完所有属性,进行"Aware"接口和"BeanPostProcessor"前置处理后,会接着检测当前bean对象是否实现了InitializingBean接口,如果是,则会调用其afterPropertiesSet方法进一步调整bean实例对象的状态。

InitializingBean示例

 1 public class UserDefinedInitializingBean implements InitializingBean {
 2
 3
private String msg;
 4
 5
public String getMsg() {
 6
return msg;
 7 
}
 8
 9
public void setMsg(String msg) {
10
this.msg = msg;
11 
}
12
13 
@Override
14
public void afterPropertiesSet() throws Exception {
15
System.out.println("InitializingBean afterPropertiesSet......");
16
this.msg = "修改了msg,msg=hello initializingBean!!!!!!";
17 
}
18 }

进行如下配置:

1 <bean id="userDefinedInitializingBean" class="com.dev.basebean.initializingbean.UserDefinedInitializingBean"
2 
p:msg="i am msg!!!"/>

测试:

1 @Test
2
public void initializingBeanTest() {
3
ApplicationContext context = new ClassPathXmlApplicationContext("classpath*:com/dev/config/initializingbean/initializingbean.xml");
4
UserDefinedInitializingBean initializingBean = context.getBean(UserDefinedInitializingBean.class);
5 
System.out.println(initializingBean.getMsg());
6
}

运行结果如下:

从运行结果来看,msg属性被我们修改了,在afterPropertiesSet方法中,这相当于Spring又提供给我们一种可以改变bean实例对象的方法。

invokeInitMethods

InitializingBean的afterPropertiesSet方法就是在invokeInitMethods方法中被执行的。

AbstractAutowireCapableBeanFactory#invokeInitMethods:

 1 protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)
 2
throws Throwable {
 3
 4
// 首先先检查是否是InitializingBean,如果是,则需要调用afterPropertiesSet()
 5
boolean isInitializingBean = (bean instanceof InitializingBean);
 6
if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
 7
if (logger.isDebugEnabled()) {
 8
logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
 9 
}
10
// 安全模式
11
if (System.getSecurityManager() != null) {
12
try {
13
AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
14 
((InitializingBean) bean).afterPropertiesSet();
15
return null;
16 
}, getAccessControlContext());
17
} catch (PrivilegedActionException pae) {
18
throw pae.getException();
19 
}
20
} else {
21
// 属性初始化处理
22 
((InitializingBean) bean).afterPropertiesSet();
23 
}
24 
}
25
26
if (mbd != null && bean.getClass() != NullBean.class) {
27
String initMethodName = mbd.getInitMethodName();
28
if (StringUtils.hasLength(initMethodName) &&
29
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
30
!mbd.isExternallyManagedInitMethod(initMethodName)) {
31
// 激活用户自定义的初始化方法
32 
invokeCustomInitMethod(beanName, bean, mbd);
33 
}
34 
}
35
}

分析:

  • 首先检查当前bean是否实现了InitializingBean接口,如果实现了,则调用其afterPropertiesSet方法。
  • 然后再检查是否指定了init-method,如果指定了init-method方法,则通过反射进行调用。

init-method

对init-method进行示例,只需根据上面示例进行一点调整即可。

1 <bean id="userDefinedInitializingBean" class="com.dev.basebean.initializingbean.UserDefinedInitializingBean"
2 
p:msg="i am msg!!!" init-method="initMethod"/>

在UserDefinedInitializingBean中增加如下代码:

1 public void initMethod() {
2
System.out.println("通过init-method方法对msg属性进行修改");
3
this.msg = "修改了msg,msg=hello init-method!!!!!!";
4
}

运行结果如下:

从结果上可以看到init-method方法是在afterPropertiesSet方法之后,并且达到了同样的效果,对代码无侵入性。

分析到这里其实已经把bean的生命周期都总结出来,下篇文章进行具体总结,这里想来看本篇小结。

总结

从invokeInitMethods方法中,我们知道init-method指定的方法会在afterPropertiesSet方法后执行,如果afterPropertiesSet方法执行过程中出现异常,init-method方法是不会执行的。使用init-method使其对业务代码的侵入降低,虽然init-method是基于xml配置文件的,但我们也可以通过@PostConstruct注解的形式来进行替换。

至此InitializingBean和init-method已分析完毕,对于DisposableBean和destroy-method与init相似,这里不再进行赘述。


by Shawn Chen,2019.05.05,下午。

转载于:https://www.cnblogs.com/developer_chan/p/10812172.html

最后

以上就是愉快茉莉为你收集整理的【spring源码分析】IOC容器初始化——查漏补缺(三)的全部内容,希望文章能够帮你解决【spring源码分析】IOC容器初始化——查漏补缺(三)所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(38)

评论列表共有 0 条评论

立即
投稿
返回
顶部