前言
網(wǎng)站設(shè)計(jì)制作、網(wǎng)站設(shè)計(jì)的開發(fā),更需要了解用戶,從用戶角度來建設(shè)網(wǎng)站,獲得較好的用戶體驗(yàn)。創(chuàng)新互聯(lián)多年互聯(lián)網(wǎng)經(jīng)驗(yàn),見的多,溝通容易、能幫助客戶提出的運(yùn)營(yíng)建議。作為成都一家網(wǎng)絡(luò)公司,打造的就是網(wǎng)站建設(shè)產(chǎn)品直銷的概念。選擇創(chuàng)新互聯(lián),不只是建站,我們把建站作為產(chǎn)品,不斷的更新、完善,讓每位來訪用戶感受到浩方產(chǎn)品的價(jià)值服務(wù)。
我們知道,IOC是Spring的核心。它來負(fù)責(zé)控制對(duì)象的生命周期和對(duì)象間的關(guān)系。
舉個(gè)例子,我們?nèi)绾蝸碚覍?duì)象的呢?常見的情況是,在路上要到處去看哪個(gè)MM既漂亮身材又好,符合我們的口味。就打聽她們的電話號(hào)碼,制造關(guān)聯(lián)想辦法認(rèn)識(shí)她們,然后...這里省略N步,最后談戀愛結(jié)婚。
IOC在這里就像婚介所,里面有很多適婚男女的資料,如果你有需求,直接告訴它你需要個(gè)什么樣的女朋友就好了。它會(huì)給我們提供一個(gè)MM,直接談戀愛結(jié)婚,完美!
下面就來看Spring是如何生成并管理這些對(duì)象的呢?
1、方法入口
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons()方法是今天的主角,一切從它開始。
public void preInstantiateSingletons() throws BeansException { //beanDefinitionNames就是上一節(jié)初始化完成后的所有BeanDefinition的beanName List<String> beanNames = new ArrayList<String>(this.beanDefinitionNames); for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { //getBean是主力中的主力,負(fù)責(zé)實(shí)例化Bean和IOC依賴注入 getBean(beanName); } } }
2、Bean的實(shí)例化
在入口方法getBean中,首先調(diào)用了doCreateBean方法。第一步就是通過反射實(shí)例化一個(gè)Bean。
protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) { // Instantiate the bean. BeanWrapper instanceWrapper = null; if (mbd.isSingleton()) { instanceWrapper = this.factoryBeanInstanceCache.remove(beanName); } if (instanceWrapper == null) { //createBeanInstance就是實(shí)例化Bean的過程,無非就是一些判斷加反射,最后調(diào)用ctor.newInstance(args); instanceWrapper = createBeanInstance(beanName, mbd, args); } }
3、Annotation的支持
在Bean實(shí)例化完成之后,會(huì)進(jìn)入一段后置處理器的代碼。從代碼上看,過濾實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口的類,調(diào)用其postProcessMergedBeanDefinition()方法。都是誰實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口呢?我們重點(diǎn)看三個(gè)
記不記得在Spring源碼分析(一)Spring的初始化和XML這一章節(jié)中,我們說Spring對(duì)annotation-config標(biāo)簽的支持,注冊(cè)了一些特殊的Bean,正好就包含上面這三個(gè)。下面來看它們偷偷做了什么呢?
從方法名字來看,它們做了相同一件事,加載注解元數(shù)據(jù)。方法內(nèi)部又做了相同的兩件事
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback()
看方法的參數(shù),targetClass就是Bean的Class對(duì)象。接下來就可以獲取它的字段和方法,判斷是否包含了相應(yīng)的注解,最后轉(zhuǎn)成InjectionMetadata對(duì)象,下面以一段偽代碼展示處理過程。
public static void main(String[] args) throws ClassNotFoundException { Class<?> clazz = Class.forName("com.viewscenes.netsupervisor.entity.User"); Field[] fields = clazz.getFields(); Method[] methods = clazz.getMethods(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; if (field.isAnnotationPresent(Autowired.class)) { //轉(zhuǎn)換成AutowiredFieldElement對(duì)象,加入容器 } } for (int i = 0; i < methods.length; i++) { Method method = methods[i]; if (method.isAnnotationPresent(Autowired.class)) { //轉(zhuǎn)換成AutowiredMethodElement對(duì)象,加入容器 } } return new InjectionMetadata(clazz, elements); }
InjectionMetadata對(duì)象有兩個(gè)重要的屬性:targetClass ,injectedElements,在注解式的依賴注入的時(shí)候重點(diǎn)就靠它們。
public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) { //targetClass是Bean的Class對(duì)象 this.targetClass = targetClass; //injectedElements是一個(gè)InjectedElement對(duì)象的集合 this.injectedElements = elements; } //member是成員本身,字段或者方法 //pd是JDK中的內(nèi)省機(jī)制對(duì)象,后面的注入屬性值要用到 protected InjectedElement(Member member, PropertyDescriptor pd) { this.member = member; this.isField = (member instanceof Field); this.pd = pd; }
說了這么多,最后再看下源碼里面是什么樣的,以Autowired 為例。
ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() { @Override public void doWith(Field field) throws IllegalArgumentException, IllegalAccessException { AnnotationAttributes ann = findAutowiredAnnotation(field); if (ann != null) { if (Modifier.isStatic(field.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static fields: " + field); } return; } boolean required = determineRequiredStatus(ann); currElements.add(new AutowiredFieldElement(field, required)); } } }); ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback() { @Override public void doWith(Method method) throws IllegalArgumentException, IllegalAccessException { Method bridgedMethod = BridgeMethodResolver.findBridgedMethod(method); if (!BridgeMethodResolver.isVisibilityBridgeMethodPair(method, bridgedMethod)) { return; } AnnotationAttributes ann = findAutowiredAnnotation(bridgedMethod); if (ann != null && method.equals(ClassUtils.getMostSpecificMethod(method, clazz))) { if (Modifier.isStatic(method.getModifiers())) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation is not supported on static methods: " + method); } return; } if (method.getParameterTypes().length == 0) { if (logger.isWarnEnabled()) { logger.warn("Autowired annotation should be used on methods with parameters: " + method); } } boolean required = determineRequiredStatus(ann); PropertyDescriptor pd = BeanUtils.findPropertyForMethod(bridgedMethod, clazz); currElements.add(new AutowiredMethodElement(method, required, pd)); } } });
4、依賴注入
前面完成了在doCreateBean()方法Bean的實(shí)例化,接下來就是依賴注入。
Bean的依賴注入有兩種方式,一種是配置文件,一種是注解式。
4.1、 注解式的注入過程
在上面第3小節(jié),Spring已經(jīng)過濾了Bean實(shí)例上包含@Autowired、@Resource等注解的Field和Method,并返回了包含Class對(duì)象、內(nèi)省對(duì)象、成員的InjectionMetadata對(duì)象。還是以@Autowired為例,這次調(diào)用到AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues()。
首先拿到InjectionMetadata對(duì)象,再判斷里面的InjectedElement集合是否為空,也就是說判斷在Bean的字段和方法上是否包含@Autowired。然后調(diào)用InjectedElement.inject()。InjectedElement有兩個(gè)子類AutowiredFieldElement、AutowiredMethodElement,很顯然一個(gè)是處理Field,一個(gè)是處理Method。
4.1.1 AutowiredFieldElement
如果Autowired注解在字段上,它的配置是這樣。
public class User { @Autowired Role role; }
protected void inject(Object bean, String beanName, PropertyValues pvs) throws Throwable { //以User類中的@Autowired Role role為例,這里的field就是 //public com.viewscenes.netsupervisor.entity.Role com.viewscenes.netsupervisor.entity.User.role Field field = (Field) this.member; Object value; DependencyDescriptor desc = new DependencyDescriptor(field, this.required); desc.setContainingClass(bean.getClass()); Set<String> autowiredBeanNames = new LinkedHashSet<String>(1); TypeConverter typeConverter = beanFactory.getTypeConverter(); try { //這里的beanName因?yàn)锽ean,所以會(huì)重新進(jìn)入populateBean方法,先完成Role對(duì)象的注入 //value == com.viewscenes.netsupervisor.entity.Role@7228c85c value = beanFactory.resolveDependency(desc, beanName, autowiredBeanNames, typeConverter); } catch (BeansException ex) { throw new UnsatisfiedDependencyException(null, beanName, new InjectionPoint(field), ex); } if (value != null) { //設(shè)置可訪問,直接賦值 ReflectionUtils.makeAccessible(field); field.set(bean, value); } }
4.1.2 AutowiredFieldElement
如果Autowired注解在方法上,就得這樣寫。
public class User { @Autowired public void setRole(Role role) {} }
它的inject方法和上面類似,不過最后是method.invoke。感興趣的小伙伴可以去翻翻源碼。
ReflectionUtils.makeAccessible(method); method.invoke(bean, arguments);
4.2、配置文件的注入過程
先來看一個(gè)配置文件,我們?cè)赨ser類中注入了id,name,age和Role的實(shí)例。
<bean id="user" class="com.viewscenes.netsupervisor.entity.User"> <property name="id" value="1001"></property> <property name="name" value="網(wǎng)機(jī)動(dòng)車"></property> <property name="age" value="24"></property> <property name="role" ref="role"></property> </bean> <bean id="role" class="com.viewscenes.netsupervisor.entity.Role"> <property name="id" value="1002"></property> <property name="name" value="中心管理員"></property> </bean>
在Spring源碼分析(一)Spring的初始化和XML這一章節(jié)的4.2 小節(jié),bean標(biāo)簽的解析,我們看到在反射得到Bean的Class對(duì)象后,會(huì)設(shè)置它的property屬性,也就是調(diào)用了parsePropertyElements()方法。在BeanDefinition對(duì)象里有個(gè)MutablePropertyValues屬性。
MutablePropertyValues: //propertyValueList就是有幾個(gè)property 節(jié)點(diǎn) List<PropertyValue> propertyValueList: PropertyValue: name //對(duì)應(yīng)配置文件中的name ==id value //對(duì)應(yīng)配置文件中的value ==1001 PropertyValue: name //對(duì)應(yīng)配置文件中的name ==name value //對(duì)應(yīng)配置文件中的value ==網(wǎng)機(jī)動(dòng)車
上圖就是BeanDefinition對(duì)象里面MutablePropertyValues屬性的結(jié)構(gòu)。既然已經(jīng)拿到了property的名稱和值,注入就比較簡(jiǎn)單了。從內(nèi)省對(duì)象PropertyDescriptor中拿到writeMethod對(duì)象,設(shè)置可訪問,invoke即可。PropertyDescriptor有兩個(gè)對(duì)象readMethodRef、writeMethodRef其實(shí)對(duì)應(yīng)的就是get set方法。
public void setValue(final Object object, Object valueToApply) throws Exception { //pd 是內(nèi)省對(duì)象PropertyDescriptor final Method writeMethod = this.pd.getWriteMethod()); writeMethod.setAccessible(true); final Object value = valueToApply; //以id為例 writeMethod == public void com.viewscenes.netsupervisor.entity.User.setId(java.lang.String) writeMethod.invoke(getWrappedInstance(), value); }
5、initializeBean
在Bean實(shí)例化和IOC依賴注入后,Spring留出了擴(kuò)展,可以讓我們對(duì)Bean做一些初始化的工作。
5.1、Aware
Aware是一個(gè)空的接口,什么也沒有。不過有很多xxxAware繼承自它,下面來看源碼。如果有需要,我們的Bean可以實(shí)現(xiàn)下面的接口拿到我們想要的。
//在實(shí)例化和IOC依賴注入完成后調(diào)用 private void invokeAwareMethods(final String beanName, final Object bean) { if (bean instanceof Aware) { //讓我們的Bean可以拿到自身在容器中的beanName if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } //可以拿到ClassLoader對(duì)象 if (bean instanceof BeanClassLoaderAware) { ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader()); } //可以拿到BeanFactory對(duì)象 if (bean instanceof BeanFactoryAware) { ((BeanFactoryAware) bean).setBeanFactory(AbstractAutowireCapableBeanFactory.this); } if (bean instanceof EnvironmentAware) { ((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment()); } if (bean instanceof EmbeddedValueResolverAware) { ((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver); } if (bean instanceof ResourceLoaderAware) { ((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext); } if (bean instanceof ApplicationEventPublisherAware) { ((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext); } if (bean instanceof MessageSourceAware) { ((MessageSourceAware) bean).setMessageSource(this.applicationContext); } if (bean instanceof ApplicationContextAware) { ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext); } ......未完 } }
做法如下:
public class AwareTest1 implements BeanNameAware,BeanClassLoaderAware,BeanFactoryAware{ public void setBeanName(String name) { System.out.println("BeanNameAware:" + name); } public void setBeanFactory(BeanFactory beanFactory) throws BeansException { System.out.println("BeanFactoryAware:" + beanFactory); } public void setBeanClassLoader(ClassLoader classLoader) { System.out.println("BeanClassLoaderAware:" + classLoader); } }
//輸出結(jié)果
BeanNameAware:awareTest1
BeanClassLoaderAware:WebappClassLoader
context: /springmvc_dubbo_producer
delegate: false
repositories:
/WEB-INF/classes/
----------> Parent Classloader:
java.net.URLClassLoader@2626b418
BeanFactoryAware:org.springframework.beans.factory.support.DefaultListableBeanFactory@5b4686b4: defining beans ...未完
5.2、初始化
Bean的初始化方法有三種方式,按照先后順序是,@PostConstruct、afterPropertiesSet、init-method
5.2.1 @PostConstruct
這個(gè)注解隱藏的比較深,它是在CommonAnnotationBeanPostProcessor的父類InitDestroyAnnotationBeanPostProcessor調(diào)用到的。這個(gè)注解的初始化方法不支持帶參數(shù),會(huì)直接拋異常。
if (method.getParameterTypes().length != 0) { throw new IllegalStateException("Lifecycle method annotation requires a no-arg method: " + method); } public void invoke(Object target) throws Throwable { ReflectionUtils.makeAccessible(this.method); this.method.invoke(target, (Object[]) null); } 5.2.2 afterPropertiesSet 這個(gè)要實(shí)現(xiàn)InitializingBean接口。這個(gè)也不能有參數(shù),因?yàn)樗涌诜椒ň蜎]有定義參數(shù)。 boolean isInitializingBean = (bean instanceof InitializingBean); if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) { if (logger.isDebugEnabled()) { logger.debug("Invoking afterPropertiesSet() on bean with name '" + beanName + "'"); } ((InitializingBean) bean).afterPropertiesSet(); }
5.2.3 init-method
ReflectionUtils.makeAccessible(initMethod); initMethod.invoke(bean);
6、注冊(cè)
registerDisposableBeanIfNecessary()完成Bean的緩存注冊(cè)工作,把Bean注冊(cè)到Map中。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持創(chuàng)新互聯(lián)。
網(wǎng)站欄目:Springbean的實(shí)例化和IOC依賴注入詳解
文章分享:http://www.rwnh.cn/article8/peogip.html
成都網(wǎng)站建設(shè)公司_創(chuàng)新互聯(lián),為您提供定制開發(fā)、品牌網(wǎng)站建設(shè)、營(yíng)銷型網(wǎng)站建設(shè)、品牌網(wǎng)站制作、做網(wǎng)站、網(wǎng)站內(nèi)鏈
聲明:本網(wǎng)站發(fā)布的內(nèi)容(圖片、視頻和文字)以用戶投稿、用戶轉(zhuǎn)載內(nèi)容為主,如果涉及侵權(quán)請(qǐng)盡快告知,我們將會(huì)在第一時(shí)間刪除。文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如需處理請(qǐng)聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內(nèi)容未經(jīng)允許不得轉(zhuǎn)載,或轉(zhuǎn)載時(shí)需注明來源: 創(chuàng)新互聯(lián)