国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院

首頁 > 開發(fā) > Java > 正文

Spring bean的實(shí)例化和IOC依賴注入詳解

2024-07-14 08:43:40
字體:
供稿:網(wǎng)友

前言

我們知道,IOC是Spring的核心。它來負(fù)責(zé)控制對象的生命周期和對象間的關(guān)系。

舉個(gè)例子,我們?nèi)绾蝸碚覍ο蟮哪??常見的情況是,在路上要到處去看哪個(gè)MM既漂亮身材又好,符合我們的口味。就打聽她們的電話號碼,制造關(guān)聯(lián)想辦法認(rèn)識她們,然后...這里省略N步,最后談戀愛結(jié)婚。

IOC在這里就像婚介所,里面有很多適婚男女的資料,如果你有需求,直接告訴它你需要個(gè)什么樣的女朋友就好了。它會給我們提供一個(gè)MM,直接談戀愛結(jié)婚,完美!

下面就來看Spring是如何生成并管理這些對象的呢?

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í)例化完成之后,會進(jìn)入一段后置處理器的代碼。從代碼上看,過濾實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口的類,調(diào)用其postProcessMergedBeanDefinition()方法。都是誰實(shí)現(xiàn)了MergedBeanDefinitionPostProcessor接口呢?我們重點(diǎn)看三個(gè)

  • AutowiredAnnotationBeanPostProcessor
  • CommonAnnotationBeanPostProcessor
  • RequiredAnnotationBeanPostProcessor

記不記得在Spring源碼分析(一)Spring的初始化和XML這一章節(jié)中,我們說Spring對annotation-config標(biāo)簽的支持,注冊了一些特殊的Bean,正好就包含上面這三個(gè)。下面來看它們偷偷做了什么呢?

從方法名字來看,它們做了相同一件事,加載注解元數(shù)據(jù)。方法內(nèi)部又做了相同的兩件事

ReflectionUtils.doWithLocalFields(targetClass, new ReflectionUtils.FieldCallback() ReflectionUtils.doWithLocalMethods(targetClass, new ReflectionUtils.MethodCallback()

看方法的參數(shù),targetClass就是Bean的Class對象。接下來就可以獲取它的字段和方法,判斷是否包含了相應(yīng)的注解,最后轉(zhuǎn)成InjectionMetadata對象,下面以一段偽代碼展示處理過程。

  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對象,加入容器      }    }    for (int i = 0; i < methods.length; i++) {      Method method = methods[i];      if (method.isAnnotationPresent(Autowired.class)) {        //轉(zhuǎn)換成AutowiredMethodElement對象,加入容器      }    }    return new InjectionMetadata(clazz, elements);  }

InjectionMetadata對象有兩個(gè)重要的屬性:targetClass ,injectedElements,在注解式的依賴注入的時(shí)候重點(diǎn)就靠它們。

  public InjectionMetadata(Class<?> targetClass, Collection<InjectedElement> elements) {    //targetClass是Bean的Class對象    this.targetClass = targetClass;     //injectedElements是一個(gè)InjectedElement對象的集合    this.injectedElements = elements;  }  //member是成員本身,字段或者方法  //pd是JDK中的內(nèi)省機(jī)制對象,后面的注入屬性值要用到  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對象、內(nèi)省對象、成員的InjectionMetadata對象。還是以@Autowired為例,這次調(diào)用到AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues()。

首先拿到InjectionMetadata對象,再判斷里面的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,所以會重新進(jìn)入populateBean方法,先完成Role對象的注入    //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è)配置文件,我們在User類中注入了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對象后,會設(shè)置它的property屬性,也就是調(diào)用了parsePropertyElements()方法。在BeanDefinition對象里有個(gè)MutablePropertyValues屬性。

MutablePropertyValues: //propertyValueList就是有幾個(gè)property 節(jié)點(diǎn) List<PropertyValue> propertyValueList:  PropertyValue:   name   //對應(yīng)配置文件中的name  ==id   value   //對應(yīng)配置文件中的value ==1001   PropertyValue:   name   //對應(yīng)配置文件中的name  ==name   value   //對應(yīng)配置文件中的value ==網(wǎng)機(jī)動(dòng)車 

上圖就是BeanDefinition對象里面MutablePropertyValues屬性的結(jié)構(gòu)。既然已經(jīng)拿到了property的名稱和值,注入就比較簡單了。從內(nèi)省對象PropertyDescriptor中拿到writeMethod對象,設(shè)置可訪問,invoke即可。PropertyDescriptor有兩個(gè)對象readMethodRef、writeMethodRef其實(shí)對應(yīng)的就是get set方法。

public void setValue(final Object object, Object valueToApply) throws Exception {  //pd 是內(nèi)省對象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ò)展,可以讓我們對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對象      if (bean instanceof BeanClassLoaderAware) {        ((BeanClassLoaderAware) bean).setBeanClassLoader(getBeanClassLoader());      }      //可以拿到BeanFactory對象      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ù),會直接拋異常。

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、注冊

registerDisposableBeanIfNecessary()完成Bean的緩存注冊工作,把Bean注冊到Map中。

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VeVb武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到JAVA教程頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗(yàn)證碼: 匿名發(fā)表
国产激情自拍_国产9色视频_丁香花在线电影小说观看 _久久久久国产精品嫩草影院
sese在线视频| 国产人成精品| 99综合精品久久| 国产福利免费观看| 精品99又大又爽又硬少妇毛片| 国产精品爱久久久久久久小说| 国产激情小视频在线| 91亚洲欧美| 久热av在线| 国产精品18久久久久网站| 精品av中文字幕在线毛片| 性网站在线播放| 日本中文字幕高清视频| 国产激情网址| 在线视频色在线| 狠狠干天天干| 国产91在线视频蝌蚪| jizz性欧美| 国产区av在线| 久久综合精品视频| av男人的天堂网| 国产丝袜护土调教在线视频| av网站在线播放| 国产日本在线| а天堂8中文最新版在线官网| 99视频免费在线观看| 在线观看精品视频一区二区三区| 牛牛在线精品视频| 国产wwww| 黄色av免费在线| 先锋av资源网| 在线免费日韩| 国产精品186在线观看在线播放 | 综合激情亚洲| 日本免费视频www| 99久久国产视频| 国产精品白浆流出视频| 国产乱xxⅹxx国语对白| 开心婷婷激情五月| 日本在线视频www鲁啊鲁| 国产精品冒白浆免费视频| 九色自拍视频| 国产中文字幕av| 可以免费看污视频的网站| 天天干天天摸| gogogogo高清视频在线| 伊人中文字幕在线| 99re热在线观看| 亚洲欧美小说国产图片| 中文字幕av免费| 精品麻豆一区二区三区| 伊人网在线观看| 欧美日韩性视频一区二区三区| 在线亚洲电影| 伊人影院在线观看| 在线观看的网站你懂的| sese在线视频| 尤物视频在线免费观看| 最近最好的中文字幕2019免费 | 日本亚洲精品| 九九色在线观看| 日本中文字幕高清视频| 国产网站在线播放| 91视频久色| 欧美性猛交xxxx免费看蜜桃| 久热中文字幕在线观看| 成人超碰在线| 国产网站观看9久| 伊人免费视频| 中文字幕在线免费观看| 精品视频二区三区| 久久久久久国产视频| 国产免费视频在线| 天天草天天操| 91精品国产91久久久久久青草| 四虎国产精品永久在线| 尤物视频在线观看| 日本高清中文字幕在线| 国产乱妇乱子在线播视频播放网站| 国产青青草在线| 欧美成人久久电影香蕉| 国产精品蜜臀| 快射av在线播放一区| 国产二区三区在线| 欧美日韩国产亚洲沙发| 91麻豆福利| 国产亚洲精品久久久久久青梅| av男人的天堂网| 国产日本韩国在线播放| 丁香六月婷婷| 久久一本精品| 热99在线观看| 青青青手机在线视频观看| 中文av在线播放| 国产成免费视频| 99视频免费| 国产一区二区三区四区尤物| www.九九热.com| 伊人色综合网| 99reav在线| av在线不卡网站| 日韩国产成人| 狠狠狠狠狠狠操| 国产乱在线观看视频| 国产乱子视频| 国产激情在线观看| 91高清国产| 在线观看wwww| h网址在线观看| 美女网站在线观看| 久热国产在线视频| 天堂在线免费观看| 中文字幕国产视频| 国产男女无套在线播放| 午夜视频在线| 99久久99久久免费精品小说| 99re在线视频| 可以免费看污视频的网站| 国产免费av网站| 国产网站av| 日本高清中文字幕在线| 五月婷婷丁香激情| 精品国语对白精品自拍视| 国产不卡在线| 欧洲有码在线视频| 尤物在线网址| 日本欧美在线视频免费观看| 二区中文字幕| 国产日韩网站| 青青草视频在线免费观看| 国产男女无套在线播放| 91蜜桃在线视频| 国产中文字幕在线视频| 国产精品久久麻豆| 久热中文字幕| 制服丝袜中文字幕在线观看| 伊人中文字幕在线| 国产美女视频一区二区三区| 97国产视频| 天堂资源最新版在线视频观看免费网| 国产三级视频在线播放线观看| 亚洲大香人伊一本线| 国产区视频在线| jizz在线视频| 精品国产免费第一区二区| 狠狠干天天爱| 欧美精品一区二区三区免费| 精品国产一区二区三区四区阿崩 | 国产欧美日韩第一页| 日本电影在线观看| 精品视频三区| 国产成人夜间影院在线观看| 国产美女福利在线观看| 四虎影院成人| 国产三级视频在线| 黄色av网站在线免费观看| 亚洲视频精品在线观看| 国产黄色免费看| 午夜免费视频在线国产| 超碰国产在线| 超碰在线观看免费版| 中文字幕av在线播放| 国产porny蝌蚪视频| 国产精品伦一区二区三区视频| 国产美女福利在线| 九七电影韩国女主播在线观看| av在线资源网| 亚洲网站视频在线观看| 影音先锋中文字幕在线| 国产高清一区二区三区视频| 国产亚av手机在线观看| 国产污视频在线| 国产黄色免费网站| 精品久久亚洲一级α| 亚洲v片在线观看| 日本高清中文字幕在线| 黄色国产网站在线观看| 国产一二区视频| 精品国内一区二区三区免费视频| 97在线超碰| 久久精品视频观看| 国产午夜在线视频| 在线观看av中文| 国产在线小视频| 午夜不卡视频| 天天操天天曰| 99re热在线观看| 丁香综合五月| 亚洲精品视频在线免费| 国产麻豆高清视频在线第一页| 国产视频2区| 超碰在线观看免费| 99综合精品久久| 国产麻豆高清视频在线第一页| 国产区av在线| 黄网在线免费| 在线观看的网站你懂的| 天堂资源中文在线| 欧美高清视频| 99在线免费观看|