国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|JavaScript|易語言|

服務器之家 - 編程語言 - Java教程 - Spring bean的實例化和IOC依賴注入詳解

Spring bean的實例化和IOC依賴注入詳解

2021-07-22 15:37清幽之地 Java教程

這篇文章主要介紹了Spring bean的實例化和IOC依賴注入詳解,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

我們知道,ioc是spring的核心。它來負責控制對象的生命周期和對象間的關系。

舉個例子,我們如何來找對象的呢?常見的情況是,在路上要到處去看哪個mm既漂亮身材又好,符合我們的口味。就打聽她們的電話號碼,制造關聯想辦法認識她們,然后...這里省略n步,最后談戀愛結婚。

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

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

1、方法入口
org.springframework.beans.factory.support.defaultlistablebeanfactory.preinstantiatesingletons()方法是今天的主角,一切從它開始。

?
1
2
3
4
5
6
7
8
9
10
11
public void preinstantiatesingletons() throws beansexception {
   //beandefinitionnames就是上一節初始化完成后的所有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是主力中的主力,負責實例化bean和ioc依賴注入
       getbean(beanname);
     }
   }
 }

2、bean的實例化

在入口方法getbean中,首先調用了docreatebean方法。第一步就是通過反射實例化一個bean。

?
1
2
3
4
5
6
7
8
9
10
11
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就是實例化bean的過程,無非就是一些判斷加反射,最后調用ctor.newinstance(args);
    instancewrapper = createbeaninstance(beanname, mbd, args);
  }
}

3、annotation的支持

在bean實例化完成之后,會進入一段后置處理器的代碼。從代碼上看,過濾實現了mergedbeandefinitionpostprocessor接口的類,調用其postprocessmergedbeandefinition()方法。都是誰實現了mergedbeandefinitionpostprocessor接口呢?我們重點看三個

  • autowiredannotationbeanpostprocessor
  • commonannotationbeanpostprocessor
  • requiredannotationbeanpostprocessor

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

從方法名字來看,它們做了相同一件事,加載注解元數據。方法內部又做了相同的兩件事

?
1
2
reflectionutils.dowithlocalfields(targetclass, new reflectionutils.fieldcallback()
reflectionutils.dowithlocalmethods(targetclass, new reflectionutils.methodcallback()

看方法的參數,targetclass就是bean的class對象。接下來就可以獲取它的字段和方法,判斷是否包含了相應的注解,最后轉成injectionmetadata對象,下面以一段偽代碼展示處理過程。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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)) {
      //轉換成autowiredfieldelement對象,加入容器
    }
  }
  for (int i = 0; i < methods.length; i++) {
    method method = methods[i];
    if (method.isannotationpresent(autowired.class)) {
      //轉換成autowiredmethodelement對象,加入容器
    }
  }
  return new injectionmetadata(clazz, elements);
}

injectionmetadata對象有兩個重要的屬性:targetclass ,injectedelements,在注解式的依賴注入的時候重點就靠它們。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
public injectionmetadata(class<?> targetclass, collection<injectedelement> elements) {
  //targetclass是bean的class對象
  this.targetclass = targetclass;
  //injectedelements是一個injectedelement對象的集合
  this.injectedelements = elements;
}
//member是成員本身,字段或者方法
//pd是jdk中的內省機制對象,后面的注入屬性值要用到
protected injectedelement(member member, propertydescriptor pd) {
  this.member = member;
  this.isfield = (member instanceof field);
  this.pd = pd;
}

說了這么多,最后再看下源碼里面是什么樣的,以autowired 為例。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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的實例化,接下來就是依賴注入。

bean的依賴注入有兩種方式,一種是配置文件,一種是注解式。

4.1、 注解式的注入過程

在上面第3小節,spring已經過濾了bean實例上包含@autowired、@resource等注解的field和method,并返回了包含class對象、內省對象、成員的injectionmetadata對象。還是以@autowired為例,這次調用到autowiredannotationbeanpostprocessor.postprocesspropertyvalues()。

首先拿到injectionmetadata對象,再判斷里面的injectedelement集合是否為空,也就是說判斷在bean的字段和方法上是否包含@autowired。然后調用injectedelement.inject()。injectedelement有兩個子類autowiredfieldelement、autowiredmethodelement,很顯然一個是處理field,一個是處理method。

4.1.1 autowiredfieldelement

如果autowired注解在字段上,它的配置是這樣。

?
1
2
3
4
public class user {
  @autowired
  role role;
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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因為bean,所以會重新進入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) {
    //設置可訪問,直接賦值
    reflectionutils.makeaccessible(field);
    field.set(bean, value);
  }
}

4.1.2 autowiredfieldelement

如果autowired注解在方法上,就得這樣寫。

?
1
2
3
4
public class user {
  @autowired
  public void setrole(role role) {}
}

它的inject方法和上面類似,不過最后是method.invoke。感興趣的小伙伴可以去翻翻源碼。

?
1
2
reflectionutils.makeaccessible(method);
method.invoke(bean, arguments);

4.2、配置文件的注入過程

先來看一個配置文件,我們在user類中注入了id,name,age和role的實例。

?
1
2
3
4
5
6
7
8
9
10
<bean id="user" class="com.viewscenes.netsupervisor.entity.user">
  <property name="id" value="1001"></property>
  <property name="name" value="網機動車"></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這一章節的4.2 小節,bean標簽的解析,我們看到在反射得到bean的class對象后,會設置它的property屬性,也就是調用了parsepropertyelements()方法。在beandefinition對象里有個mutablepropertyvalues屬性。

?
1
2
3
4
5
6
7
8
9
mutablepropertyvalues:
 //propertyvaluelist就是有幾個property 節點
 list<propertyvalue> propertyvaluelist:
  propertyvalue:
   name   //對應配置文件中的name  ==id
   value   //對應配置文件中的value ==1001
  propertyvalue:
   name   //對應配置文件中的name  ==name
   value   //對應配置文件中的value ==網機動車

上圖就是beandefinition對象里面mutablepropertyvalues屬性的結構。既然已經拿到了property的名稱和值,注入就比較簡單了。從內省對象propertydescriptor中拿到writemethod對象,設置可訪問,invoke即可。propertydescriptor有兩個對象readmethodref、writemethodref其實對應的就是get set方法。

?
1
2
3
4
5
6
7
8
public void setvalue(final object object, object valuetoapply) throws exception {
  //pd 是內省對象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實例化和ioc依賴注入后,spring留出了擴展,可以讓我們對bean做一些初始化的工作。

5.1、aware

aware是一個空的接口,什么也沒有。不過有很多xxxaware繼承自它,下面來看源碼。如果有需要,我們的bean可以實現下面的接口拿到我們想要的。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
//在實例化和ioc依賴注入完成后調用
  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);
    }
    ......未完
  }
}

做法如下:

?
1
2
3
4
5
6
7
8
9
10
11
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);
  }
}

//輸出結果
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

這個注解隱藏的比較深,它是在commonannotationbeanpostprocessor的父類initdestroyannotationbeanpostprocessor調用到的。這個注解的初始化方法不支持帶參數,會直接拋異常。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
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
這個要實現initializingbean接口。這個也不能有參數,因為它接口方法就沒有定義參數。
  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

?
1
2
reflectionutils.makeaccessible(initmethod);
initmethod.invoke(bean);

6、注冊

registerdisposablebeanifnecessary()完成bean的緩存注冊工作,把bean注冊到map中。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持服務器之家。

原文鏈接:https://www.jianshu.com/p/00f1a6739a9e

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 91网站在线看 | 99国产视频 | 四虎免费在线播放 | 黄色av大全 | 久久精品99 | 一级毛片免费 | 久久久免费电影 | 精品国产成人 | 精品久久久久久久久久 | 毛片91| 日韩在线视频在线观看 | av网站免费看 | 四虎av成人 | 国产精品去看片 | 欧美久久成人 | 夜夜操导航 | 中文字幕一区二区三区四区 | 爱干视频 | 91精品国产欧美一区二区 | 久久成人精品视频 | 国产精品中文字幕在线观看 | 国产精品一区在线观看 | 欧美劲爆第一页 | 午夜成人在线视频 | 在线观看亚洲 | 激情五月综合 | 毛片免费观看 | 黄色小视频在线观看 | 国产成人久久精品一区二区三区 | 日韩亚洲 | 亚洲高清视频在线观看 | 久久久久久久国产精品免费播放 | 亚洲一区二区在线免费观看 | 久久久久99 | 中文字幕在线免费看 | 中文字幕一区二区三区四区 | 亚洲情网站| 日韩精品一级毛片 | 亚洲国内精品 | 成人免费视频亚洲 | 国产一区二区三区在线免费观看 |