spring 之 init-method & InitializingBean
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的更多相关文章
- spring init method destroy method
在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...
- 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 ...
- 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 ...
- 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 ...
- 003-Spring4 扩展分析-spring类初始化@PostConstruct > InitializingBean > init-method、ApplicationContext、BeanPostProcessor、BeanFactoryPostProcessor、BeanDefinitionRegistryPostProcessor
一.spring类初始化@PostConstruct > InitializingBean > init-method InitializingBean接口为bean提供了初始化方法的方式 ...
- java代码中init method和destroy method的三种使用方式
在java的实际开发过程中,我们可能常常需要使用到init method和destroy method,比如初始化一个对象(bean)后立即初始化(加载)一些数据,在销毁一个对象之前进行垃圾回收等等. ...
- 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 ...
- 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 ...
- 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 ...
- SSH项目练习的时候报错:[applicationContext.xml]: Invocation of init method failed;
这里是控制台的报错信息:org.springframework.beans.factory.BeanCreationException: Error creating bean with name ' ...
随机推荐
- ThinkPHP 3.1.2 输出和模型使用 配置项等 - 2
一.ThinkPHP 3 的输出 (重点) a.通过 echo 等PHP原生的输出方式在页面中输出 b.通过display方法输出 想分配变量可以使用assign方法 c.修改左右定界符 休 ...
- CEF中弹出窗口的处理
CEF开发如果不想在弹出窗口中打开网页,即想要在当前窗体加载目标Url, 就需要重写OnBeforePopup,它是属于CefLifeSpanHandler类中的. /*--cef(optional_ ...
- 黄聪:超实用的PHPExcel[导入][导出]实现方法总结
首先需要去官网https://github.com/PHPOffice/PHPExcel/下载PHPExcel,下载后只需要Classes目录下的文件即可. 1.PHPExcel导出方法实现过程 /* ...
- 【Graphite】使用dropwizard.metrics向Graphite中写入指标项数据
graphite 定时向Graphite中写入指标项数据,指标项模拟个数3000个 使用的类库 官方文档 dropwizard的github地址 Metric官方文档 metrics.dropwi ...
- Hadoop错误集:Journal Storage Directory not formatted
类型一: 当你从异常信息中看到JournalNode not formatted,如果在异常中看到三个节点都提示需要格式化JournalNode. 如果你是新建集群,你可以重新格式化NameNode, ...
- go get golang.org/x 包失败解决方法
由于墙的原因,国内使用 go get安装golang 官方包可能会失败 解决方法 方法1 [不需要FQ] Win10下相关配置: GOPATH : E:\go 安装记录: E:\>go get ...
- JavaScript之图片操作7
前面总结了很多了有关于图片操作的案例,本次是基于前面的基础,做一个综合的图片轮播效果,需要实现以下功能: 没有任何操作时,图片自动轮播 鼠标悬浮时,图片停止轮播:当鼠标移开,轮播继续 鼠标悬浮时,出现 ...
- 搭建DUBBO项目解决DUBBO.XML标签报错的问题(转载)
https://www.cnblogs.com/ajax-li/p/7856393.html 报错内容: Multiple annotations found at this line: - cvc- ...
- 1124 Raffle for Weibo Followers (20 分)
1124 Raffle for Weibo Followers (20 分) John got a full mark on PAT. He was so happy that he decided ...
- 利用队列Queue实现一个多并发“线程池”效果的Socket程序
本例通过利用类Queue建立了一个存放着Thread对象的“容器对象”,当Client端申请与Server端通信时,在Server端的“链接循环”中每次拿出一个Thread对象去创建“线程链接”,从而 ...