init-method  是bean (第一次)实例化的时候被调用的。

先看个异常:

INFO: Overriding bean definition for bean 'office' with a different definition: replacing [Generic bean: class [com.baobaotao.Office]; scope=singleton; abstract=false; lazyInit=false; autowireMode=; dependencyCheck=; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in file [D:\code\ws\spring\hz\spring-learn\target\classes\com\baobaotao\Office.class]] with [Generic bean: class [com.baobaotao.Office]; scope=; abstract=false; lazyInit=false; autowireMode=; dependencyCheck=; autowireCandidate=true; primary=false; factoryBeanName=null; factoryMethodName=null; initMethodName=null; destroyMethodName=null; defined in class path resource [beans.xml]]
Exception in thread "main" org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'boss' defined in class path resource [beans.xml]: Invocation of init method failed; nested exception is org.springframework.beans.factory.support.BeanDefinitionValidationException: Couldn't find an init method named 'initBoss' on bean with name 'boss'
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory$.getObject(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:)
at AnnoIoCTest.main(AnnoIoCTest.java:)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:)
at java.lang.reflect.Method.invoke(Method.java:)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:)
Caused by: org.springframework.beans.factory.support.BeanDefinitionValidationException: Couldn't find an init method named 'initBoss' on bean with name 'boss'
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeCustomInitMethod(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:)
... more

从 AbstractApplicationContext.getBean 调用,可见,它是在 getBean 阶段被调用的。

再看位于AbstractAutowireCapableBeanFactory的源码:

    protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
String initMethodName = mbd.getInitMethodName();       //默认 nonPublicAccessAllowed 是true , spring 仅仅是根据 配置的名字去 对应的class 中寻找同名方法, 至于是不是 static,public,有没有返回值 都不要紧
final Method initMethod = mbd.isNonPublicAccessAllowed()?BeanUtils.findMethod(bean.getClass(), initMethodName, new Class[]):ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName, new Class[]);
if(initMethod == null) { // 如果那个方法不符合 约定(比如,如果方法有一个参数等等), 那么这里就会返回 null
if(mbd.isEnforceInitMethod()) {
throw new BeanDefinitionValidationException("Couldn\'t find an init method named \'" + initMethodName + "\' on bean with name \'" + beanName + "\'");
} else {
if(this.logger.isDebugEnabled()) {
this.logger.debug("No default init method named \'" + initMethodName + "\' found on bean with name \'" + beanName + "\'");
} }
} else {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Invoking init method \'" + initMethodName + "\' on bean with name \'" + beanName + "\'");
} if(System.getSecurityManager() != null) {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
ReflectionUtils.makeAccessible(initMethod);
return null;
}
}); try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
initMethod.invoke(bean, new Object[]);
return null;
}
}, this.getAccessControlContext());
} catch (PrivilegedActionException var9) {
InvocationTargetException ex = (InvocationTargetException)var9.getException();
throw ex.getTargetException();
}
} else {
try {
ReflectionUtils.makeAccessible(initMethod); // 方法是不是 public 不要紧, 这里会通过反射修改其可见性
initMethod.invoke(bean, new Object[]); // new Object[0] 表明了 那个方法不能有任何参数, 否则就会出现异常。
} catch (InvocationTargetException var8) {
throw var8.getTargetException();
}
} }
}

 init-method & InitializingBean

InitializingBean的原理并不复杂。 首先它是一个接口,它提供了 方法: public void afterPropertiesSet() throws Exception 。 如果我们的类实现了 它,只要我们的类归spring 管理, 那么spring 会在第一次实例化 这个类的bean的时候, 进行这些相关接口的 方法的初始化。  从afterPropertiesSet名字也可知, 这个方法是在 bean完成了所有 属性的设置后 才进行调用的。 也就是说, 方法的初始化会 晚于 属性的初始化。

init-method 和 InitializingBean  是类似的,但其原理还是有所不同的,参见AbstractAutowireCapableBeanFactory 的源码可知:

    protected void invokeInitMethods(String beanName, final Object bean, RootBeanDefinition mbd) throws Throwable {
boolean isInitializingBean = bean instanceof InitializingBean;
if(isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
if(this.logger.isDebugEnabled()) {
this.logger.debug("Invoking afterPropertiesSet() on bean with name \'" + beanName + "\'");
} if(System.getSecurityManager() != null) {
try {
AccessController.doPrivileged(new PrivilegedExceptionAction() {
public Object run() throws Exception {
((InitializingBean)bean).afterPropertiesSet();
return null;
}
}, this.getAccessControlContext());
} catch (PrivilegedActionException var6) {
throw var6.getException();
}
} else {
((InitializingBean)bean).afterPropertiesSet(); // 先是进行 InitializationBean 的初始化
}
} if(mbd != null) {
String initMethodName = mbd.getInitMethodName(); // 然后, 如果这个bean 存在 init 方法,并且如果它非InitializationBean且方法名非 aferPropertiesSet,并且这个bean不是外部管理的 ,,那么执行它。
if(initMethodName != null && (!isInitializingBean || !"afterPropertiesSet".equals(initMethodName)) && !mbd.isExternallyManagedInitMethod(initMethodName)) {
this.invokeCustomInitMethod(beanName, bean, mbd);
}
} }

spring 之 init-method & InitializingBean的更多相关文章

  1. spring init method destroy method

    在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...

  2. Spring报错: org.springframework.beans.factory.support.BeanDefinitionValidationException: Couldn't find an init method named 'init' on bean with name 'car'(待解答)

    在Spring工程里,有一个Car类的bean,Main.java主程序,MyBeanPostProcessor.java是Bean后置处理器. 文件目录结构如下: Car.java package ...

  3. MyBatis与Spring MVC结合时,使用DAO注入出现:Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: Property 'sqlSessionFactory' or 'sqlSessionTemplate' are required

    错误源自使用了这个例子:http://www.yihaomen.com/article/java/336.htm,如果运行时会出现如下错误: Invocation of init method fai ...

  4. Error creating bean with name 'sqlSessionFactory' defined in class path resource [config/spring/applicationContext.xml]: Invocation of init method failed;

    我报的错: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSes ...

  5. 003-Spring4 扩展分析-spring类初始化@PostConstruct > InitializingBean > init-method、ApplicationContext、BeanPostProcessor、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor

    一.spring类初始化@PostConstruct > InitializingBean > init-method InitializingBean接口为bean提供了初始化方法的方式 ...

  6. java代码中init method和destroy method的三种使用方式

    在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...

  7. MyBatis笔记----报错:Error creating bean with name 'sqlSessionFactory' defined in class path resource [com/ij34/mybatis/applicationContext.xml]: Invocation of init method failed; nested exception is org.sp

    四月 05, 2017 4:51:02 下午 org.springframework.context.support.ClassPathXmlApplicationContext prepareRef ...

  8. Error creating bean with name 'sessionFactory' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is org.hibernate.HibernateException: Unable t

    spring与hibernate整合然后出现如下错误: org.springframework.beans.factory.BeanCreationException: Error creating ...

  9. org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sessionFactory' defined in class path resource [bean.xml]: Invocation of init method failed; nested exception is

    在复制xml文件进行修改的时候,我经常将不小心对原文件进行修改,而导致创建bean出错.报错如下所示: Exception sending context initialized event to l ...

  10. SSH项目练习的时候报错:[applicationContext.xml]: Invocation of init method failed;

    这里是控制台的报错信息:org.springframework.beans.factory.BeanCreationException: Error creating bean with name ' ...

随机推荐

  1. WPF实现打印用户界面功能

    方式一:public bool Print(string pathStr) { try { if (File.Exists(pathStr) == false) return false; var p ...

  2. WPF Demo511 控件共用事件

    路由事件: 1.路由事件一般使用的三种策略如下所示: A.Bubble(冒泡模式):事件从自己激发一直传递到根元素; B.Direct(直接模式):只有事件源才有机会相应事件(和传统事件一样); C. ...

  3. PCM简介

    1. 差分脉冲编码调制 如果两个相邻抽样值之间的相关性很大,那么它们的差值就较小,这样,仅对差值量化可以使用较少的比特数,此即差分PCM,或DPCM. 为了理论方便,我们将采样和量化分开,并用不带上三 ...

  4. RTB业务知识之2-Open-RTB全景

    一.前言 openrtb是一套开源的竞价广告系统,来自IAB的贡献,非常好.有非常多的值得借鉴的地方,最近基于其所提供sdk api接口文档介绍,整理了相关的资料.主要包括其生态图体系.业务流程和主要 ...

  5. Android开发之内部类篇

    内部类: 1.内部类的第一个好处,隐藏你不想让别人知道的操作,也即封装性. 2.非静态内部类对象有着指向其外部类对象的引用 等等. 创建项目: 1.File---->New----->ja ...

  6. load() 方法

    jQuery ajax - load() 方法 $("button").click(function(){ $("div").load('demo_ajax_l ...

  7. 廖雪峰Java2-2数据封装-2构造方法

    在2-2-1中,创建1个实例需要3步 Person ming = new Person(); ming.setName(" 小明 "); ming.setAge(16); 问题:能 ...

  8. HDOJ 2007 平方和与立方和

    #include<iostream> #include<algorithm> using namespace std; int main() { int m, n; while ...

  9. css属性—position的使用与页面的分层介绍

    一.引言: 在css众多属性中,position算是里面用的比较多也相对来说比较重要的属性了,它对于单个标签的“定位”.标签之间的“相对位置定位”还有网页的分层来说十分重要! 二.“定位的实现”具体介 ...

  10. npm rebuild node-sass

    在使用npm安装node-sass的时候,可能会出现如下的报错: Error: ENOENT: no such file or directory, scandir 'D:\IdeaWork\code ...