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=0; dependencyCheck=0; 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=0; dependencyCheck=0; 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:1589)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:554)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483)at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1081)at AnnoIoCTest.main(AnnoIoCTest.java:10)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:601)at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144) 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:1677)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1656)at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1585)... 13 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[0]):ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName, new Class[0]);if(initMethod == null) { // 如果那個方法不符合 約定(比如,如果方法有一個參數等等), 那么這里就會返回 nullif(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[0]);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[0]); // 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);}}}?
posted on 2017-11-11 20:05 CanntBelieve 閱讀(...) 評論(...) 編輯 收藏轉載于:https://www.cnblogs.com/FlyAway2013/p/7819860.html
總結
以上是生活随笔為你收集整理的spring 之 init-method InitializingBean的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JS 数字左补零函数
- 下一篇: 查看git提交细节