長沙seo搜索東莞百度推廣排名優(yōu)化
正文
一個(gè) bean 經(jīng)歷了 createBeanInstance()
被創(chuàng)建出來,然后又經(jīng)過一番屬性注入,依賴處理,歷經(jīng)千辛萬苦,千錘百煉,終于有點(diǎn)兒 bean 實(shí)例的樣子,能堪大任了,只需要經(jīng)歷最后一步就破繭成蝶了。這最后一步就是初始化,也就是 initializeBean()
,所以這篇文章我們分析 doCreateBean()
中最后一步:初始化 bean。
我回到之前的doCreateBean方法中,如下
在populateBean方法下面有一個(gè)initializeBean(beanName, exposedObject, mbd)方法,這個(gè)就是用來執(zhí)行用戶設(shè)定的初始化操作。我們看下方法體:
最全面的Java面試網(wǎng)站
protected Object initializeBean(final String beanName, final Object bean, @Nullable RootBeanDefinition mbd) {if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {// 激活 Aware 方法invokeAwareMethods(beanName, bean);return null;}, getAccessControlContext());}else {// 對(duì)特殊的 bean 處理:Aware、BeanClassLoaderAware、BeanFactoryAwareinvokeAwareMethods(beanName, bean);}Object wrappedBean = bean;if (mbd == null || !mbd.isSynthetic()) {// 后處理器wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);}try {// 激活用戶自定義的 init 方法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;
}
初始化 bean 的方法其實(shí)就是三個(gè)步驟的處理,而這三個(gè)步驟主要還是根據(jù)用戶設(shè)定的來進(jìn)行初始化,這三個(gè)過程為:
- 激活 Aware 方法
- 后置處理器的應(yīng)用
- 激活自定義的 init 方法
激Aware方法
我們先了解一下Aware方法的使用。Spring中提供了一些Aware接口,比如BeanFactoryAware,ApplicationContextAware,ResourceLoaderAware,ServletContextAware等,實(shí)現(xiàn)這些Aware接口的bean在被初始化后,可以取得一些相對(duì)應(yīng)的資源,例如實(shí)現(xiàn)BeanFactoryAware的bean在初始化之后,Spring容器將會(huì)注入BeanFactory實(shí)例,而實(shí)現(xiàn)ApplicationContextAware的bean,在bean被初始化后,將會(huì)被注入ApplicationContext實(shí)例等。我們先通過示例方法了解下Aware的使用。
定義普通bean,如下代碼:
public class HelloBean {public void say(){System.out.println("Hello");}
}
定義beanFactoryAware類型的bean
public class MyBeanAware implements BeanFactoryAware {private BeanFactory beanFactory;public void setBeanFactory(BeanFactory beanFactory) throws BeansException {this.beanFactory = beanFactory;}public void testAware(){//通過hello這個(gè)bean id從beanFactory獲取實(shí)例 HelloBean hello = (HelloBean)beanFactory.getBean("hello");hello.say();}
}
分享一份大彬精心整理的大廠面試手冊(cè),包含計(jì)算機(jī)基礎(chǔ)、Java基礎(chǔ)、多線程、JVM、數(shù)據(jù)庫、Redis、Spring、Mybatis、SpringMVC、SpringBoot、分布式、微服務(wù)、設(shè)計(jì)模式、架構(gòu)、校招社招分享等高頻面試題,非常實(shí)用,有小伙伴靠著這份手冊(cè)拿過字節(jié)offer~
需要的小伙伴可以自行下載:
http://mp.weixin.qq.com/s?__biz=Mzg2OTY1NzY0MQ==&mid=2247485445&idx=1&sn=1c6e224b9bb3da457f5ee03894493dbc&chksm=ce98f543f9ef7c55325e3bf336607a370935a6c78dbb68cf86e59f5d68f4c51d175365a189f8#rd
進(jìn)行測(cè)試
public class Test {public static void main(String[] args) {ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");MyBeanAware test = (MyBeanAware)ctx.getBean("myBeanAware");test.testAware();}
}<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="myBeanAware" class="com.dabin.spring.MyBeanAware"></bean><bean id="hello" class="com.dabin.spring.HelloBean"></bean>
</beans>
輸出
Hello
上面的方法我們獲取到Spring中BeanFactory,并且可以根據(jù)BeanFactory獲取所有的bean,以及進(jìn)行相關(guān)設(shè)置。還有其他Aware的使用都是大同小異,看一下Spring的實(shí)現(xiàn)方式:
private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } if (bean instanceof BeanClassLoaderAware) { ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); } if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } }
}
處理器的應(yīng)用
BeanPostPrecessor我們經(jīng)常看到Spring中使用,這是Spring開放式架構(gòu)的一個(gè)必不可少的亮點(diǎn),給用戶充足的權(quán)限去更改或者擴(kuò)展Spring,而除了BeanPostProcessor外還有很多其他的PostProcessor,當(dāng)然大部分都以此為基礎(chǔ),集成自BeanPostProcessor。BeanPostProcessor在調(diào)用用戶自定義初始化方法前或者調(diào)用自定義初始化方法后分別會(huì)調(diào)用BeanPostProcessor的postProcessBeforeInitialization和postProcessAfterinitialization方法,使用戶可以根據(jù)自己的業(yè)務(wù)需求就行相應(yīng)的處理。
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessBeforeInitialization(result, beanName); if (result == null) { return result; } } return result;
}public Object applyBeanPostProcessorsAfterInitialization(Object existingBean, String beanName) throws BeansException { Object result = existingBean; for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) { result = beanProcessor.postProcessAfterInitialization(result, beanName); if (result == null) { return result; } } return result;
}
激活自定義的init方法
客戶定制的初始化方法除了我們熟知的使用配置init-method外,還有使自定義的bean實(shí)現(xiàn)InitializingBean接口,并在afterPropertiesSet中實(shí)現(xiàn)自己的初始化業(yè)務(wù)邏輯。
init-method與afterPropertiesSet都是在初始化bean時(shí)執(zhí)行,執(zhí)行順序是afterPropertiesSet先執(zhí)行,而init-method后執(zhí)行。
在invokeInitMethods方法中就實(shí)現(xiàn)了這兩個(gè)步驟的初始化調(diào)用。
protected void invokeInitMethods(String beanName, final Object bean, @Nullable RootBeanDefinition mbd)throws Throwable {// 是否實(shí)現(xiàn) InitializingBean// 如果實(shí)現(xiàn)了 InitializingBean 接口,則只掉調(diào)用bean的 afterPropertiesSet()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((PrivilegedExceptionAction<Object>) () -> {((InitializingBean) bean).afterPropertiesSet();return null;}, getAccessControlContext());}catch (PrivilegedActionException pae) {throw pae.getException();}}else {// 直接調(diào)用 afterPropertiesSet()((InitializingBean) bean).afterPropertiesSet();}}if (mbd != null && bean.getClass() != NullBean.class) {// 判斷是否指定了 init-method(),// 如果指定了 init-method(),則再調(diào)用制定的init-methodString initMethodName = mbd.getInitMethodName();if (StringUtils.hasLength(initMethodName) &&!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&!mbd.isExternallyManagedInitMethod(initMethodName)) {// 利用反射機(jī)制執(zhí)行invokeCustomInitMethod(beanName, bean, mbd);}}
}
首先檢測(cè)當(dāng)前 bean 是否實(shí)現(xiàn)了 InitializingBean 接口,如果實(shí)現(xiàn)了則調(diào)用其 afterPropertiesSet()
,然后再檢查是否也指定了 init-method()
,如果指定了則通過反射機(jī)制調(diào)用指定的 init-method()
。
init-method()
public class InitializingBeanTest {private String name;public String getName() {return name;}public void setName(String name) {this.name = name;}public void setOtherName(){System.out.println("InitializingBeanTest setOtherName...");this.name = "dabin";}
}// 配置文件
<bean id="initializingBeanTest" class="com.dabin.spring.InitializingBeanTest"init-method="setOtherName"><property name="name" value="dabin123"/>
</bean>
執(zhí)行結(jié)果:
dabin
我們可以使用 <beans>
標(biāo)簽的 default-init-method
屬性來統(tǒng)一指定初始化方法,這樣就省了需要在每個(gè) <bean>
標(biāo)簽中都設(shè)置 init-method
這樣的繁瑣工作了。比如在 default-init-method
規(guī)定所有初始化操作全部以 initBean()
命名。如下:
我們看看 invokeCustomInitMethod 方法:
protected void invokeCustomInitMethod(String beanName, final Object bean, RootBeanDefinition mbd)throws Throwable {String initMethodName = mbd.getInitMethodName();Assert.state(initMethodName != null, "No init method set");Method initMethod = (mbd.isNonPublicAccessAllowed() ?BeanUtils.findMethod(bean.getClass(), initMethodName) :ClassUtils.getMethodIfAvailable(bean.getClass(), initMethodName));if (initMethod == null) {if (mbd.isEnforceInitMethod()) {throw new BeanDefinitionValidationException("Could not find an init method named '" +initMethodName + "' on bean with name '" + beanName + "'");}else {if (logger.isTraceEnabled()) {logger.trace("No default init method named '" + initMethodName +"' found on bean with name '" + beanName + "'");}// Ignore non-existent default lifecycle methods.return;}}if (logger.isTraceEnabled()) {logger.trace("Invoking init method '" + initMethodName + "' on bean with name '" + beanName + "'");}Method methodToInvoke = ClassUtils.getInterfaceMethodIfPossible(initMethod);if (System.getSecurityManager() != null) {AccessController.doPrivileged((PrivilegedAction<Object>) () -> {ReflectionUtils.makeAccessible(methodToInvoke);return null;});try {AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () ->methodToInvoke.invoke(bean), 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();}}
}
我們看出最后是使用反射的方式來執(zhí)行初始化方法。