本系列轉載自?http://blog.csdn.net/haitao111313/article/category/1179996?
? 我們知道,在Tomcat的世界里,一個Host容器代表一個虛機器資源,Context容器代表一個應用,所謂的部署器就是能夠把Context容器添加進Host容器中去的一個組件。顯然,一個Host容器應該擁有一個部署器組件。簡單的部署代碼應該是下面這樣的:
- Context?context?=? new ?StandardContext();??
- Host?host?=? new ?StandardHost();??
- host.addChild(context);??
- public ? void ?lifecycleEvent(LifecycleEvent?event)?{??
- ??
- ???????? //?Identify?the?host?we?are?associated?with ??
- ???????? try ?{??
- ????????????host?=?(Host)?event.getLifecycle();??
- ???????????? if ?(host? instanceof ?StandardHost)?{? //如果監聽到的事件對象類型是StandardHost就設置相關屬性。 ??
- ???????????????? int ?hostDebug?=?((StandardHost)?host).getDebug();??
- ???????????????? if ?(hostDebug?>? this .debug)?{??
- ???????????????????? this .debug?=?hostDebug;??
- ????????????????}??
- ????????????????setDeployXML(((StandardHost)?host).isDeployXML()); //是否發布xml文件的標識,默認為true ??
- ????????????????setLiveDeploy(((StandardHost)?host).getLiveDeploy()); //是否動態部署標識,默認為true ??
- ????????????????setUnpackWARs(((StandardHost)?host).isUnpackWARs()); //是否要將war文件解壓縮,默認為true ??
- ????????????}??
- ????????}? catch ?(ClassCastException?e)?{??
- ????????????log(sm.getString( "hostConfig.cce" ,?event.getLifecycle()),?e);??
- ???????????? return ;??
- ????????}??
- ??
- ???????? //?Process?the?event?that?has?occurred ??
- ???????? if ?(event.getType().equals(Lifecycle.START_EVENT))? //監聽到容器開始,則調用start方法,方法里面調用了部署應用的代碼 ??
- ????????????start();??
- ???????? else ? if ?(event.getType().equals(Lifecycle.STOP_EVENT))??
- ????????????stop();??
- ??
- ????}??
- protected ? void ?start()?{??
- ??
- ??????? if ?(debug?>=? 1 )??
- ???????????log(sm.getString( "hostConfig.start" ));??
- ??
- ??????? if ?(host.getAutoDeploy())?{??
- ???????????deployApps(); //發布應用 ??
- ???????}??
- ??
- ??????? if ?(isLiveDeploy())?{??
- ???????????threadStart(); //動態發布應用,因為HostConfig也實現了Runnable接口,threadStart啟動該線程來實現動態發布 ??
- ???????}??
- ??
- ???}??
- ??--------------------》deployApps方法,該方法會把webapps目錄下的所有目錄都看作成一個應用程序??
- ???? protected ? void ?deployApps()?{??
- ??
- ??????? if ?(!(host? instanceof ?Deployer))??
- ??????????? return ;??
- ??????? if ?(debug?>=? 1 )??
- ???????????log(sm.getString( "hostConfig.deploying" ));??
- ??
- ???????File?appBase?=?appBase(); //返回webapps目錄 ??
- ??????? if ?(!appBase.exists()?||?!appBase.isDirectory())??
- ??????????? return ;??
- ???????String?files[]?=?appBase.list(); //列出webapps目錄下的所有文件 ??
- ??
- ???????deployDescriptors(appBase,?files); //通過描述符發布應用 ??
- ???????deployWARs(appBase,?files); //發布war文件的應用 ??
- ???????deployDirectories(appBase,?files); //發布目錄型的應用 ??
- ??
- ???}??
以上三個發布應用的方式大同小異,所以只說說常用的發布方式--目錄型的應用,下面看看deployDirectories方法,只寫了關鍵的邏輯:
- protected ? void ?deployDirectories(File?appBase,?String[]?files)?{??
- ??
- ????? for ?( int ?i?=? 0 ;?i?<?files.length;?i++)?{??
- ??
- ????????? if ?(files[i].equalsIgnoreCase( "META-INF" ))??
- ????????????? continue ;??
- ????????? if ?(files[i].equalsIgnoreCase( "WEB-INF" ))??
- ????????????? continue ;??
- ????????? if ?(deployed.contains(files[i]))??
- ????????????? continue ;??
- ?????????File?dir?=? new ?File(appBase,?files[i]);??
- ????????? if ?(dir.isDirectory())?{??
- ??
- ?????????????deployed.add(files[i]);??
- ??
- ????????????? //?Make?sure?there?is?an?application?configuration?directory ??
- ????????????? //?This?is?needed?if?the?Context?appBase?is?the?same?as?the ??
- ????????????? //?web?server?document?root?to?make?sure?only?web?applications ??
- ????????????? //?are?deployed?and?not?directories?for?web?space. ??
- ?????????????File?webInf?=? new ?File(dir,? "/WEB-INF" );??
- ????????????? if ?(!webInf.exists()?||?!webInf.isDirectory()?||??
- ?????????????????!webInf.canRead())??
- ????????????????? continue ;??
- ??
- ????????????? //?Calculate?the?context?path?and?make?sure?it?is?unique ??
- ?????????????String?contextPath?=? "/" ?+?files[i];??
- ????????????? if ?(files[i].equals( "ROOT" ))??
- ?????????????????contextPath?=? "" ;??
- ????????????? if ?(host.findChild(contextPath)?!=? null )??
- ????????????????? continue ;??
- ??
- ????????????? //?Deploy?the?application?in?this?directory ??
- ?????????????log(sm.getString( "hostConfig.deployDir" ,?files[i]));??
- ????????????? try ?{??
- ?????????????????URL?url?=? new ?URL( "file" ,? null ,?dir.getCanonicalPath()); //得到應用的路徑,路徑的寫法是???file://應用名稱 ??
- ?????????????????((Deployer)?host).install(contextPath,?url);? //安裝應用到目錄下 ??
- ?????????????}? catch ?(Throwable?t)?{??
- ?????????????????log(sm.getString( "hostConfig.deployDir.error" ,?files[i]),??
- ?????????????????????t);??
- ?????????????}??
- ??
- ?????????}??
- ??
- ?????}??
- ??
- ?}??
((Deployer) host).install(contextPath, url);會調用到StandardHost的install方法,再由StandardHost轉交給StandardHostDeployer的install方法,StandardHostDeployer是一個輔助類,幫助StandardHost來實現發布應用,它實現了Deployer接口,看它的install(URL config, URL war)方法(它有兩個install方法,分別用來發布上面不同方式的應用):
- public ? synchronized ? void ?install(String?contextPath,?URL?war)??
- ??????? throws ?IOException?{??
- ??
- ?????..............................................??
- ??
- ??????? //?Calculate?the?document?base?for?the?new?web?application ??
- ???????host.log(sm.getString( "standardHost.installing" ,??
- ?????????????????????????????contextPath,?war.toString()));??
- ???????String?url?=?war.toString();??
- ???????String?docBase?=? null ;??
- ??????? if ?(url.startsWith( "jar:" ))?{??? //如果是war類型的應用 ??
- ???????????url?=?url.substring( 4 ,?url.length()?-? 2 );??
- ???????}??
- ??????? if ?(url.startsWith( "file://" ))//如果是目錄類型的應用??
- ???????????docBase?=?url.substring( 7 );??
- ??????? else ? if ?(url.startsWith( "file:" ))??
- ???????????docBase?=?url.substring( 5 );??
- ??????? else ??
- ??????????? throw ? new ?IllegalArgumentException??
- ???????????????(sm.getString( "standardHost.warURL" ,?url));??
- ??
- ??????? //?Install?the?new?web?application ??
- ??????? try ?{??
- ???????????Class?clazz?=?Class.forName(host.getContextClass()); //host.getContextClass得到的其實是StandardContext, ??
- ???????????Context?context?=?(Context)?clazz.newInstance();??
- ???????????context.setPath(contextPath); //設置該context的訪問路徑為contextPath,即我們的應用訪問路徑 ??
- ?????????????
- ???????????context.setDocBase(docBase); //設置該應用在磁盤的路徑 ??
- ??????????? if ?(context? instanceof ?Lifecycle)?{??
- ???????????????clazz?=?Class.forName(host.getConfigClass()); //實例化host的監聽器類,并關聯上context ??
- ???????????????LifecycleListener?listener?=??
- ???????????????????(LifecycleListener)?clazz.newInstance();??
- ???????????????((Lifecycle)?context).addLifecycleListener(listener);??
- ???????????}??
- ???????????host.fireContainerEvent(PRE_INSTALL_EVENT,?context);??
- ???????????host.addChild(context);??????????? //添加到host實例,即把context應用發布到host。 ??
- ???????????host.fireContainerEvent(INSTALL_EVENT,?context);??
- ???????}? catch ?(Exception?e)?{??
- ???????????host.log(sm.getString( "standardHost.installError" ,?contextPath),??
- ????????????????????e);??
- ??????????? throw ? new ?IOException(e.toString());??
- ???????}??
- ??
- ???}??
經過上面的代碼分析,已經完全了解了怎么發布一個目錄型的應用到StandardHost中,其他war包和文件描述符類型的應用發布跟StandardHost大體類似,在這里就不說了,有興趣的可以自己查看源代碼。
更多文章、技術交流、商務合作、聯系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號聯系: 360901061
您的支持是博主寫作最大的動力,如果您喜歡我的文章,感覺我的文章對您有幫助,請用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點擊下面給點支持吧,站長非常感激您!手機微信長按不能支付解決辦法:請將微信支付二維碼保存到相冊,切換到微信,然后點擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對您有幫助就好】元
