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

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

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

服務器之家 - 編程語言 - Java教程 - Spring的初始化和XML解析的實現

Spring的初始化和XML解析的實現

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

這篇文章主要介紹了Spring的初始化和XML解析的實現,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

spring是什么?它是一個應用程序框架,為應用程序的開發提供強大的支持,例如對事務處理和持久化的支持等;它也是一個bean容器,管理bean對象的整個生命周期,維護bean的各種存在狀態,例如bean對象的實例化、銷毀、bean的單實例和多實例狀態等。

spring作為java發展史上不可忽視的存在,說他重新定義了java也不為過。它功能強大,著實為日常開發提供了大大的便利。表面越簡單的東西,背后越復雜。
從本章節開始,我們一起分析spring的源碼,看它到底是怎么樣來實現我們常說常用的諸如ioc、annotation、aop、事務等功能的。

1、spring的入口

在我們的項目中,web.xml必不可少,其中就定義了spring的監聽器。

?
1
2
3
4
5
<listener>
   <listener-class>
      org.springframework.web.context.contextloaderlistener
   </listener-class>
</listener>

我們來看contextloaderlistener類,可以看到它實現了servletcontextlistener接口,
contextinitialized就是spring初始化的入口方法。

spring還有一個入口,叫做org.springframework.web.servlet.dispatcherservlet,它們之間是父子容器的關系,最終都會調用到同一個方法org.springframework.context.support.abstractapplicationcontext.refresh()。

2、初始化

spring的初始化第一步就是要加載配置文件,然后解析里面的配置項。

ok,我們來到xmlwebapplicationcontext類的loadbeandefinitions方法。

?
1
2
3
4
5
6
7
8
protected void loadbeandefinitions(xmlbeandefinitionreader reader) throws ioexception {
  string[] configlocations = getconfiglocations();
  if (configlocations != null) {
    for (string configlocation : configlocations) {
      reader.loadbeandefinitions(configlocation);
    }
  }
}

可以看到,configlocations是一個數組,它獲取的就是配置文件。在筆者的項目中,只有一個配置文件,名字是applicationcontext.xml。下一步就是通過loadbeandefinitions這個方法解析這個配置文件。

3、解析xml配置

首先把一個配置文件封裝成一個resource對象,然后獲取resource對象的輸入流,轉換成inputsource對象,最后解析成document對象。下面代碼只保留了主要部分。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public int loadbeandefinitions(string location, set<resource> actualresources)
             throws beandefinitionstoreexception {
    resourceloader resourceloader = getresourceloader();
    if (resourceloader instanceof resourcepatternresolver) {
      // resource pattern matching available.
      try {
        //這里的location就是配置文件-applicationcontext.xml,轉成resource對象
        resource[] resources=resourceloader).getresources(location);
        //獲取resources對象的輸入流 再轉成jdk的inputsource對象,最后解析成document
        inputstream inputstream = resources.getinputstream();
        inputsource inputsource = new inputsource(inputstream);
        document doc = doloaddocument(inputsource, resource);
      }
      catch (ioexception ex) {
        throw new beandefinitionstoreexception(
            "could not resolve bean definition resource pattern [" + location + "]", ex);
      }
    }
  }

applicationcontext.xml配置文件解析成document對象,它的root節點信息如下:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
  [#text:],
  [context:component-scan: null],
  [#text:],
  [bean: null],
  [#text:],
  [bean: null],
  [#text:],
  [bean: null],
  [#text:],
  [bean: null],
  [#text:],
  [#comment: 指定了表現層資源的前綴和后綴
    viewclass:jstlview表示jsp模板頁面需要使用jstl標簽庫
    prefix 和suffix:查找視圖頁面的前綴和后綴,比如傳進來的邏輯視圖名為hello,則該該
            jsp視圖頁面應該存放在“web-inf/jsp/hello.jsp”],
  [#text:],
  [bean: null],
  [#text: ]
]

4、加載bean信息

上一步我們看到spring已經把applicationcontext.xml這個配置文件解析成了document對象,接下來就是關鍵的一步。先看源碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
//這里拿到的是document對象的根節點,根節點信息參考上圖
protected void parsebeandefinitions(element root, beandefinitionparserdelegate delegate) {
  if (delegate.isdefaultnamespace(root)) {
    nodelist nl = root.getchildnodes();
    for (int i = 0; i < nl.getlength(); i++) {
      node node = nl.item(i);
      if (node instanceof element) {
        element ele = (element) node;
        //這里有兩個分支。
        //一個是處理默認的節點(import、alias、bean、beans)
        //一個是處理自定義的節點(context:component-scan)
        if (delegate.isdefaultnamespace(ele)) {
          parsedefaultelement(ele, delegate);
        }
        else {
          delegate.parsecustomelement(ele);
        }
      }
    }
  }
  else {
    delegate.parsecustomelement(root);
  }
}

4.1 component-scan的解析

首先定位到自定義解析方法delegate.parsecustomelement(ele);

最終調用了org.springframework.context.annotation.componentscanbeandefinitionparser.parse(element element, parsercontext parsercontext),不過它是怎么調用到這個類的呢?說起來就比較有意思了。

我們先來看spring里面的一個配置文件,/meta-inf/spring.handlers

http\://www.springframework.org/schema/context=org.springframework.context.config.contextnamespacehandler
http\://www.springframework.org/schema/jee=org.springframework.ejb.config.jeenamespacehandler
http\://www.springframework.org/schema/lang=org.springframework.scripting.config.langnamespacehandler
http\://www.springframework.org/schema/task=org.springframework.scheduling.config.tasknamespacehandler
http\://www.springframework.org/schema/cache=org.springframework.cache.config.cachenamespacehandler

這里面配置了不同標簽的處理類,比如context標簽處理類就是contextnamespacehandler,然后通過反射實例化這個處理類,調用它的init()方法。init()方法里面它又注冊了一堆處理類,其中就有我們很感興趣的component-scan。

?
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
public namespacehandler resolve(string namespaceuri) {
  //handlermappings里有個方法loadallproperties(),獲取spring所有的配置項
  map<string, object> handlermappings = gethandlermappings();
  object handlerorclassname = handlermappings.get(namespaceuri);
  if (handlerorclassname == null) {
    return null;
  }
  else if (handlerorclassname instanceof namespacehandler) {
    return (namespacehandler) handlerorclassname;
  }
  else {
    string classname = (string) handlerorclassname;
    try {
      //以context:component-scan舉例
      //這里拿到的classname就是org.springframework.context.config.contextnamespacehandler
      //通過反射,實例化這個contextnamespacehandler,然后調用init方法
      class<?> handlerclass = classutils.forname(classname, this.classloader);
      namespacehandler namespacehandler = beanutils.instantiateclass(handlerclass);
      namespacehandler.init();
      handlermappings.put(namespaceuri, namespacehandler);
      return namespacehandler;
    }
  }
}
public void init() {
  registerbeandefinitionparser("annotation-config",
     new annotationconfigbeandefinitionparser());
  registerbeandefinitionparser("component-scan",
     new componentscanbeandefinitionparser());
  //...未完
}

最終spring就可以通過component-scan這個標簽,拿到componentscanbeandefinitionparser類,調用它的parse()方法。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
public beandefinition parse(element element, parsercontext parsercontext) {
   //獲取包掃描路徑,對應配置文件中的base-package="com.viewscenes.netsupervisor"
   string basepackage = element.getattribute(base_package_attribute);
   basepackage = parsercontext.getreadercontext().getenvironment().
      resolveplaceholders(basepackage);
   //這里可能有多個包路徑,分割成數組
   string[] basepackages = stringutils.tokenizetostringarray(basepackage,
       configurableapplicationcontext.config_location_delimiters);
 
   /**
    * configurescanner 配置掃描器。
    * scanner.doscan 掃描執行
    * registercomponents 這里重點是對registercomponents的支持
    *
    * @return
    */
   classpathbeandefinitionscanner scanner = configurescanner(parsercontext, element);
   set<beandefinitionholder> beandefinitions = scanner.doscan(basepackages);
   registercomponents(parsercontext.getreadercontext(), beandefinitions, element);
 
   return null;
 }

4.1.1 configurescanner 配置掃描器

這里面重點就是注冊了默認的過濾器。use-default-filters,默認值是true,如果配置文件配置了此屬性的值為false,有些注解就加不進來,到下一步掃描的時候就注冊不了bean。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
protected void registerdefaultfilters() {
  //這個就是配置的use-default-filters,如果配置了false。那么下面的
  // component、managedbean、named注解都不會被掃描到
  if (usedefaultfilters) {
    this.includefilters.add(new annotationtypefilter(component.class));
    classloader cl = classpathscanningcandidatecomponentprovider.class.getclassloader();
    try {
      this.includefilters.add(new annotationtypefilter(
      ((class<? extends annotation>) classutils.forname("javax.annotation.managedbean", cl)),
                                     false));
      logger.debug("jsr-250 'javax.annotation.managedbean'
                       found and supported for component scanning");
    }
    catch (classnotfoundexception ex) {
      // jsr-250 1.1 api (as included in java ee 6) not available - simply skip.
    }  
    //...未完
  }
}

4.1.2 doscan掃描

doscan分為三個步驟。

  • findcandidatecomponents 掃描包路徑下的所有class文件,過濾有component注解的類,轉換成beandefinition對象,加入一個linkedhashset中。
  • 循環上一步返回的linkedhashset,設置基本屬性,比如setlazyinit、setscope。
  • 注冊beandefinition對象,向map容器中緩存beanname和beandefinition,向list中加入beanname。
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
protected set<beandefinitionholder> doscan(string... basepackages) {
    set<beandefinitionholder> beandefinitions = new linkedhashset<beandefinitionholder>();
    for (string basepackage : basepackages) {
      //findcandidatecomponents方法掃描class文件,判斷component注解,轉成beandefinition對象返回。
      //值得注意的是,component不止是@component,還有
      //@controller、@service、@repository,因為在這三個注解上面還有個@component。
     //這就相當于它們都是component的子注解。
      set<beandefinition> candidates = findcandidatecomponents(basepackage);
      for (beandefinition candidate : candidates) {
        scopemetadata scopemetadata = this.scopemetadataresolver.
                              resolvescopemetadata(candidate);
        //設置屬性,沒有配置的都是默認值
        candidate.setscope(scopemetadata.getscopename());
        candidate.setxxx(scopemetadata.getxxxname());
        string beanname = this.beannamegenerator.generatebeanname(candidate, this.registry);
        //registerbeandefinition方法 注冊beandefinition,等同于下面兩句
        //this.beandefinitionmap.put(beanname, beandefinition);
        //this.beandefinitionnames.add(beanname);
        registerbeandefinition(definitionholder, this.registry);
      }
    }
    return beandefinitions;
  }

最后整個方法返回的就是beandefinition對象的set集合,以兩個controller為例。

?
1
2
3
4
5
  generic bean: class [com.viewscenes.netsupervisor.controller.indexcontroller]; scope=; abstract=false; lazyinit=false; autowiremode=0; dependencycheck=0; autowirecandidate=true; primary=false; factorybeanname=null; factorymethodname=null; initmethodname=null; destroymethodname=null; defined in file [d:\apache-tomcat-7.0.78\webapps\springmvc_dubbo_producer\web-inf\classes\com\viewscenes\netsupervisor\controller\indexcontroller.class],
  
  generic bean: class [com.viewscenes.netsupervisor.controller.usercontroller]; scope=; abstract=false; lazyinit=false; autowiremode=0; dependencycheck=0; autowirecandidate=true; primary=false; factorybeanname=null; factorymethodname=null; initmethodname=null; destroymethodname=null; defined in file [d:\apache-tomcat-7.0.78\webapps\springmvc_dubbo_producer\web-inf\classes\com\viewscenes\netsupervisor\controller\usercontroller.class]
]

4.1.3 對annotation-config的支持

我們知道,在spring配置文件有個配置是context:annotation-config 但如果配置了context:component-scan 就不必再配置config,這是因為在解析component-scan的時候已經默認添加了annotation-config的支持,除非你手動設置了annotation-config="false",不過這可不太妙,因為在ioc的時候就沒辦法支持@autowired等注解了。

?
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 registercomponents(xmlreadercontext readercontext,
           set<beandefinitionholder> beandefinitions, element element) {
  boolean annotationconfig = true;
  if (element.hasattribute(annotation_config_attribute)) {
    annotationconfig = boolean.valueof(element.getattribute(annotation_config_attribute));
  }
  if (annotationconfig) { //判斷annotation-config屬性的值
    set<beandefinitionholder> beandefs = new linkedhashset<beandefinitionholder>(4);
    if (!registry.containsbeandefinition(autowired_annotation_processor_bean_name)) {
      rootbeandefinition def = new rootbeandefinition(autowiredannotationbeanpostprocessor.class);
      beandefs.add(registerpostprocessor(registry, def, autowired_annotation_processor_bean_name));
    }
    if (!registry.containsbeandefinition(required_annotation_processor_bean_name)) {
      rootbeandefinition def = new rootbeandefinition(requiredannotationbeanpostprocessor.class);
      beandefs.add(registerpostprocessor(registry, def, required_annotation_processor_bean_name));
    }
    if (jsr250present && !registry.containsbeandefinition(common_annotation_processor_bean_name)) {
      rootbeandefinition def = new rootbeandefinition(commonannotationbeanpostprocessor.class);
      beandefs.add(registerpostprocessor(registry, def, common_annotation_processor_bean_name));
    }
      ......未完
  }
}

4.2 bean標簽的解析

bean標簽的解析,就是默認的處理方法。

獲取bean標簽的id,并且把beanname賦值為id,設置別名。新建abstractbeandefinition對象,通過反射設置beanclass,解析property屬性名稱和值。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
public beandefinitionholder parsebeandefinitionelement(element ele, beandefinition containingbean) {
    //獲取bean_id
    string id = ele.getattribute(id_attribute);
    string beanname = id;
    abstractbeandefinition beandefinition =
               parsebeandefinitionelement(ele, beanname, containingbean);
    string[] aliasesarray = stringutils.tostringarray(aliases);
    //最后返回已經包含了beanname、class對象和一系列方法的beandefinition對象
    return new beandefinitionholder(beandefinition, beanname, aliasesarray);
}
public abstractbeandefinition parsebeandefinitionelement(element ele,
                  string beanname, beandefinition containingbean) {
    string classname = ele.getattribute(class_attribute).trim();
    try {
      //根據classname反射設置setbeanclass和setbeanclassname
      abstractbeandefinition bd = createbeandefinition(classname, parent);
      //設置默認方法 setscope、setlazyinit、setautowiremode...
      parsebeandefinitionattributes(ele, beanname, containingbean, bd);
      //設置property屬性 <bean><property name="id" value="1001"></property></bean>
      parsepropertyelements(ele, bd);
      return bd;
    }
    return null;
}

注冊beandefinition對象,和component-scan掃描的bean注冊一樣。向容器中填充對象。

不管是xml配置的bean,還是通過component-scan掃描注冊的bean它們最后都是殊途同歸的,會轉換成一個beandefinition對象。記錄著這個bean對象的屬性和方法,最后都注冊到容器中,等待在實例化和ioc的時候遍歷它們。

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

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

延伸 · 閱讀

精彩推薦
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
主站蜘蛛池模板: a免费视频 | 亚洲国产精品久久久 | 国产一级大片 | 亚洲区视频 | 日本伊人网 | 午夜视频网 | 久久综合一区 | 波多野结衣一区二区三区 | 日本一区二区高清视频 | 欧美狠狠操| 俺来也俺也啪www色 性色视频在线 | 网友自拍第一页 | 91新视频| 免费国产视频 | 亚洲第一视频 | 欧美日韩精品一区二区三区四区 | 在线日韩欧美 | 亚洲精品一 | 成人在线欧美 | 91精品国产综合久久香蕉的用户体验 | 红桃成人少妇网站 | 91精品综合久久久久久五月天 | 国产精品成人观看视频国产奇米 | 欧美精品在线视频 | 国产精品视频区 | 欧洲精品在线视频 | 国产伦精品一区二区三区高清 | 高清日韩av | 在线99| 毛片免费在线播放 | 国产一区二区h | 国产成人一区二区三区 | 亚洲欧美中文日韩在线v日本 | 香蕉久久夜色精品国产使用方法 | 亚洲男人网 | 一区二区三区国产 | 免费av电影网站 | 正在播放国产一区 | 国内自拍偷拍视频 | 91视频免费在线 | 天天操夜夜爽 |