日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

配置管理之PackageProvider接口

發布時間:2025/4/16 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 配置管理之PackageProvider接口 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
?PackageProvider的開始

從前面幾章中我們了解到了一點:想知道如何加載相關配置文件就必須去找StrutsXmlConfigurationProvider類和XmlConfigurationProvider類。而StrutsXmlConfigurationProvider類和XmlConfigurationProvider類是在Dispatcher類的init_TraditionalXmlConfigurations方法里面被調用。代碼如下。

Dispatcher類:

1 private void init_TraditionalXmlConfigurations() {2 String configPaths = initParams.get("config");3 if (configPaths == null) {4 configPaths = DEFAULT_CONFIGURATION_PATHS;5 }6 String[] files = configPaths.split("\\s*[,]\\s*");7 for (String file : files) {8 if (file.endsWith(".xml")) {9 if ("xwork.xml".equals(file)) { 10 configurationManager.addContainerProvider(createXmlConfigurationProvider(file, false)); 11 } else { 12 configurationManager 13 .addContainerProvider(createStrutsXmlConfigurationProvider(file, false, servletContext)); 14 } 15 } else { 16 throw new IllegalArgumentException("Invalid configuration file name"); 17 } 18 } 19 }

看了上面的代碼。相信讀者也明白struts2會先去找過濾參數(initParams)里面是否有指定要去加載哪些配置文件。如果沒有的話,就用DEFAULT_CONFIGURATION_PATHS常量的值來加載。即是用"struts-default.xml,struts-plugin.xml,struts.xml"來解析加載。看樣子不用筆者多講大家都明白了。加載相關配置文件的代碼其實就在這里開始發生的。然后就是進行供應者注冊的工作。(相關的內容在《Struts2 源碼分析——配置管理之ContainerProvider接口》也有講到) 這里筆者想提一下上面提到的struts-plugin.xml配置文件。這個置配文件是在插件包里面。如struts2-convention-plugin-2.5.2.jar等。也就是說XmlConfigurationProvider類也有加載插件包的配置信息功能。這一點在XmlConfigurationProvider類的loadConfigurationFiles方法里面體現的很明顯。而loadConfigurationFiles方法就是用于初始化時候,加載對應的配置文件。看一下代碼吧。

XmlConfigurationProvider類:

1 public void init(Configuration configuration) { 2 this.configuration = configuration; 3 this.includedFileNames = configuration.getLoadedFileNames(); 4 loadDocuments(configFileName); 5 }

XmlConfigurationProvider類 :

1 private void loadDocuments(String configFileName) {2 try {3 loadedFileUrls.clear();4 documents = loadConfigurationFiles(configFileName, null);5 } catch (ConfigurationException e) {6 throw e;7 } catch (Exception e) {8 throw new ConfigurationException("Error loading configuration file " + configFileName, e);9 } 10 }

XmlConfigurationProvider類的loadConfigurationFiles方法:

1 Iterator<URL> urls = null;2 InputStream is = null;3 4 IOException ioException = null;5 try {6 urls = getConfigurationUrls(fileName);//獲得配置文件所以在的URLS。就是找到哪里包里面有fileName值的URLS7 } catch (IOException ex) {8 ioException = ex;9 } 10 11 if (urls == null || !urls.hasNext()) { 12 if (errorIfMissing) { 13 throw new ConfigurationException("Could not open files of the name " + fileName, ioException); 14 } else { 15 LOG.trace("Unable to locate configuration files of the name {}, skipping", fileName); 16 return docs; 17 } 18 }

筆者沒有把關于loadConfigurationFiles方法的代碼他全部貼出來。只是貼出一部分。主要是想讓讀者知道。加載插件包的配置文件是如何進行的。為了什么要講這個呢?reloadContainer方法里面在加載package元素的時候,進行了倆個部分的加載工作。一分部是加載當前提供的供應者。另一部分就是加載插件包里面的供應者。所以就必須知道原來還有插件包里面的供應者。代碼如下:

1 ActionContext oldContext = ActionContext.getContext();2 try {3 4 setContext(bootstrap);//創建一個Action上下文5 container = builder.create(false);//新建一個Container容器6 setContext(container);//創建一個Action上下文7 objectFactory = container.getInstance(ObjectFactory.class);8 9 // 處理用戶配置里面的供應者,如果是PackageProvider,就是加載對應的package元素信息 10 for (final ContainerProvider containerProvider : providers) 11 { 12 if (containerProvider instanceof PackageProvider) { 13 container.inject(containerProvider); 14 ((PackageProvider)containerProvider).loadPackages(); 15 packageProviders.add((PackageProvider)containerProvider); 16 } 17 } 18 19 // 然后處理當前插件供應者,加載對應的package元素信息 20 Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class); 21 for (String name : packageProviderNames) { 22 PackageProvider provider = container.getInstance(PackageProvider.class, name); 23 provider.init(this); 24 provider.loadPackages(); 25 packageProviders.add(provider); 26 } 27 28 rebuildRuntimeConfiguration();//新建運行時候,用的配置 29 } finally { 30 if (oldContext == null) { 31 ActionContext.setContext(null); 32 } 33 }
PackageProvider的內容

相信到這里,大家都知道加載package元素在哪里開始執行的。而關于加載package元素中卻用到很多東西。讓筆者一個個講給大家聽吧。首先讓我們一下XmlConfigurationProvider類的loadPackages方法吧。這里才是正真加載工作。代碼如下?

XmlConfigurationProvider類:

1 public void loadPackages() throws ConfigurationException {2 List<Element> reloads = new ArrayList<Element>();3 verifyPackageStructure();4 5 for (Document doc : documents) {6 Element rootElement = doc.getDocumentElement();7 NodeList children = rootElement.getChildNodes();8 int childSize = children.getLength();9 10 for (int i = 0; i < childSize; i++) { 11 Node childNode = children.item(i); 12 13 if (childNode instanceof Element) { 14 Element child = (Element) childNode; 15 16 final String nodeName = child.getNodeName(); 17 18 if ("package".equals(nodeName)) {//判斷是否是package元素。 19 PackageConfig cfg = addPackage(child);//如果是增加package元素 20 if (cfg.isNeedsRefresh()) {//判斷是否需要重新加載 21 reloads.add(child); 22 } 23 } 24 } 25 } 26 loadExtraConfiguration(doc); 27 } 28 29 if (reloads.size() > 0) { 30 reloadRequiredPackages(reloads); 31 } 32 33 for (Document doc : documents) { 34 loadExtraConfiguration(doc); 35 } 36 37 documents.clear(); 38 declaredPackages.clear(); 39 configuration = null; 40 }

看到了上面的代碼,大家都知道相關增加package元素的工作在addPackage方法里面進行的。而方法最后會返回一個PackageConfig類。PackageConfig類就是用于存放package元素信息的。為了方便讀者學習,筆者希望讀者能了解一下struts-2.5.dtd這個文件。筆者現在不清楚有多少人了解過DTD的相關語法。或許很多人不知道DTD是什么東東。那么為什么要了解這個DTD文件呢?讓我們看一下DTD文件里面的一段代碼吧。

<!ELEMENT package (result-types?, interceptors?, default-interceptor-ref?, default-action-ref?, default-class-ref?, global-results?, global-allowed-methods?, global-exception-mappings?, action*)> <!ATTLIST packagename CDATA #REQUIREDextends CDATA #IMPLIEDnamespace CDATA #IMPLIEDabstract CDATA #IMPLIEDstrict-method-invocation (true|false) "true" >

從上面的DTD信息我們很快了解到package元素節點到底有些什么內容。同時了解到package元素有哪里子節點。通過上面的信息在和PackageConfig類的成員變量進行對比學習的話,就比較清楚的知道為什么會有這個成員變量了。所以讓我們看一段關于PackageConfig類的代碼。如下

1 protected Map<String, ActionConfig> actionConfigs;//action的配置信息2 protected Map<String, ResultConfig> globalResultConfigs;//結果的配置信息3 protected Set<String> globalAllowedMethods;//公共允許的方法4 protected Map<String, Object> interceptorConfigs;//攔截器5 protected Map<String, ResultTypeConfig> resultTypeConfigs;//結果類型的配置信息6 protected List<ExceptionMappingConfig> globalExceptionMappingConfigs;//異常的配置信息7 protected List<PackageConfig> parents;//package元素的父配置信息8 protected String defaultInterceptorRef;//默認的攔截器9 protected String defaultActionRef;//默認的action 10 protected String defaultResultType;//默認的result信息 11 protected String defaultClassRef; 12 protected String name;//名字 13 protected String namespace = "";//命名空間 14 protected boolean isAbstract = false;//是否為抽象 15 protected boolean needsRefresh;//需要重新刷新 16 protected boolean strictMethodInvocation = true;

讓筆者簡單的講解一下關于每個變量的作用吧。如下

1.Map<String, ActionConfig> actionConfigs:用于存放action的配置信息。我們都知道一個package可以對應多的action配置。

2.Map<String, ResultConfig> globalResultConfigs:用于存入對應的公共結果。也許有一種情況,那就是多個action共用一個結果。

3.Set<String> globalAllowedMethods:就是action允許被調用的方法。在struts-default.xml配置文件里面設置默認的值:execute,input,back,cancel,browse,save,delete,list,index。

4.Map<String, Object> interceptorConfigs:用于存放當前package元素的攔截器。對于攔截器的概念的話。后面的章節會講到。

5.Map<String, ResultTypeConfig> resultTypeConfigs:用于存放action返回的結果類型。

6.List<ExceptionMappingConfig> globalExceptionMappingConfigs:用于存放action發生異常的異常配置。

7.ist<PackageConfig> parents:用于存放當前package元素的父package元素的信息。

8.String defaultActionRef:標示當前package元素的默認action。

9.String defaultResultType:標示當前action返回的默認結果類型。

10.String defaultClassRef:action類默認的父類。

11.String name:package元素的名稱

12.String namespace :package元素的命名空間

13.boolean isAbstract:package元素是否為抽象

14.boolean needsRefresh:標示是否需要重新刷新。

15.boolean strictMethodInvocation:標示是否啟動SMI.關于SMI請找相關的知識點。

好了。理解了PackageConfig類的信息之后,讓我們看一下addPackage方法代碼吧。

1 protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {2 String packageName = packageElement.getAttribute("name");3 PackageConfig packageConfig = configuration.getPackageConfig(packageName);4 if (packageConfig != null) {5 LOG.debug("Package [{}] already loaded, skipping re-loading it and using existing PackageConfig [{}]", packageName, packageConfig);6 return packageConfig;7 }8 9 PackageConfig.Builder newPackage = buildPackageContext(packageElement); 10 11 if (newPackage.isNeedsRefresh()) { 12 return newPackage.build(); 13 } 14 15 LOG.debug("Loaded {}", newPackage); 16 17 // 增加結果類型到newPackage里面去。 18 addResultTypes(newPackage, packageElement); 19 20 // 增加攔截器和攔截棧到newPackage里面去。 21 loadInterceptors(newPackage, packageElement); 22 23 // 設置newPackage的默認攔截器 24 loadDefaultInterceptorRef(newPackage, packageElement); 25 26 // 設置newPackage的默認類,即是action類的父類 27 loadDefaultClassRef(newPackage, packageElement); 28 29 // 增加公共結果到newPackage里面去。 30 loadGlobalResults(newPackage, packageElement); 31 //設置允許的方法 32 loadGlobalAllowedMethods(newPackage, packageElement); 33 34 // 增加異常處理newPackage里面去。 35 loadGlobalExceptionMappings(newPackage, packageElement); 36 37 // 加載對應的action信息。并增加到newPackage里面去。 38 NodeList actionList = packageElement.getElementsByTagName("action"); 39 40 for (int i = 0; i < actionList.getLength(); i++) { 41 Element actionElement = (Element) actionList.item(i); 42 addAction(actionElement, newPackage); 43 } 44 45 // 設置newPackage默認的ACTION 46 loadDefaultActionRef(newPackage, packageElement); 47 48 PackageConfig cfg = newPackage.build(); 49 configuration.addPackageConfig(cfg.getName(), cfg);//增加到配置類里面 50 return cfg; 51 }

從上面的代碼中我們可以發現最后獲得package元素信息都會增加Configuration接口對應的實例。即是DefaultConfiguration類的實例。這個方法也面也調用了很多方法來完成增加package元素。這些方法筆者并不想講解。請讀者自行根據筆者對方法的定義去查看源碼。而這里面有一點到是值得筆者注意的。那便是在PackageConfig類的實例的時候,好像用到建造者模式來實現。所以讀者在查看源碼的時候,如果不懂為什么作者要這樣子寫的話。請自行去查看相關的建造者模式的知識點。而加載package元素信息的工作到這里就算是結束了。

在加載package元素信息的工作結束之后,還有一件工作也是值得注意的。那便是上面reloadContainer方法代碼中出現的rebuildRuntimeConfiguration方法。這個方法做了什么呢?在筆者理解為創建一個運行時的配置信息,用于方便調用。在什么時候調用呢?至少筆者在DefaultActionProxy類的prepare方法調用到了。這個prepare方法是在action請求執行action將用到。詳細的內容筆者會在后面的章節里面講到。rebuildRuntimeConfiguration方法最后會創建一個叫RuntimeConfiguration接口的實例,即是RuntimeConfigurationImpl類的實例。

本章總結

本章的重點是知道struts2是如何加載相關的package元素節點信息的。那為什么要知道這部分的內容。相信筆者心里面應該筆者更清楚。如果不知道package元素的信息。那么struts2如何根據用戶輸入的URL來處理和運行相關的action類呢?不知道筆者是否還記得核心機制的圖片。可以這么說吧。到這一章相關橙黃色(Servlet Filters)部分的知識可以都結束了。我們知道如何加載相關的配置信息,知道如何加載package元素信息。而下一章筆者將對藍色(Struts core)部分的知識進行講解。即是根據現有的配置信息來處理用戶發來的action請求。

轉載于:https://www.cnblogs.com/chenliyang/p/6552575.html

總結

以上是生活随笔為你收集整理的配置管理之PackageProvider接口的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 国产女人18毛片水18精 | 免费av国产| 九九精品久久 | 久久国产精品久久精品国产 | 狠狠搞狠狠干 | 国产精品xxx | 奶波霸巨乳一二三区乳 | 99re久久| 夜夜春很很躁夜夜躁 | 一本一道久久综合狠狠老精东影业 | 最近中文字幕无免费 | 樱桃视频污污 | 激情综合网五月天 | 国产精品成人一区 | 老司机成人在线 | 亚洲性大片 | 深夜的私人秘书 | 免费黄色小说视频 | 黄色a级免费 | 免费成人电影在线观看 | 国产精品视频一二三 | 国产精品卡一卡二 | 国产精品原创 | 一级黄大片 | 日韩精品一区二区三区在线播放 | 已满18岁免费观看电视连续剧 | 亚洲美女视频在线 | 国产免费看av| 啪啪网站免费看 | 久久好色| 色婷婷色丁香 | 日日操天天 | 99ri视频 | 久久久久香蕉视频 | 伊人精品久久 | 亚洲日本香蕉 | 午夜影院在线视频 | 成人午夜精品 | 日韩一区二区三免费高清在线观看 | 96超碰在线 | 秘密基地在线观看完整版免费 | 久色影视 | 男女啪动最猛动态图 | 午夜视频91 | 日本a级黄色 | 日韩一区二区三区免费 | 欧美日韩无 | 成人羞羞网站 | 国产av国片偷人妻麻豆 | 无码人妻精品一区二区 | 女人喷潮完整视频 | 色综合狠狠操 | 黄色免费一级 | 怒海潜沙秦岭神树 | 国产精品三级久久久久久电影 | 爱情岛亚洲品质自拍极速福利网站 | 国产夫妻在线视频 | 国模叶桐尿喷337p人体 | 国产成人精品视频ⅴa片软件竹菊 | 色月婷婷| 日韩乱码人妻无码系列中文字幕 | 午夜视频网 | 把高贵美妇调教成玩物 | 91福利片 | 久久国产成人精品国产成人亚洲 | 亚洲AV无码AV吞精久久中文版 | 天天插天天插 | 亚洲成熟毛多妇女av毛片 | 欧美三级在线看 | 正在播放av | 中文字幕日本在线观看 | 国产麻豆91视频 | 日本精品不卡 | 欧美性受xxx | 日韩精品一区二区在线视频 | 亚洲第一页在线 | 国产成人无码精品久久久电影 | 欧美一道本 | 久久国产片 | 亚洲天堂影视 | 国产jk精品白丝av在线观看 | 黄色大片久久 | 国产一区二区在线观看免费 | 四虎福利 | 最新av电影网站 | 西西人体高清44rt·net | av黄网站| 国产一级av毛片 | 在线播放精品视频 | 久久精品国产一区二区 | 天天综合在线观看 | 中文字幕免费在线看线人动作大片 | 黄色性视频 | 国产清纯白嫩初高中在线观看性色 | 丝袜脚交国产在线观看 | 久久狠 | 国内国产精品天干天干 | 99视频免费在线观看 | 日韩一级视频在线观看 |