设为首页 收藏本站
查看: 673|回复: 0

[经验分享] jetty_dm

[复制链接]

尚未签到

发表于 2017-2-25 11:34:56 | 显示全部楼层 |阅读模式
1.概述
  1. jetty的deploymentManager作用是帮助创建ContextHandler并加入到jetty的合适位置,以方便提供静态和动态的服务。比如,把某个位置的war包部署到jetty。
2. deploymentManager一个主要功能是连接app Provider和applifecycle。
  3. 有两种典型的appProvider,一种是webappProvider,主要是监视某目录的*.war,并把他们提交到app lifecycle graph中。一种是contextProvider,监视一个目录的*.xml文件,并用jetty xml为app lifecycle graph创建contextHandler(通常是WebAppContext)
4. webAppProvider的start和stop和server是同步的,server.start的时候调用deployer的start。context是在将要部署的war包中发现的。在monitoredDirName中的所有war包和名称非CVS的目录都会被部署,war包的context名称是报名,root.war是/.如果extractWars被设置为true,那么war包会先被解压到一个tmp dir,如果有未编译的jsp等东西,就需要解压。
  (如果war包没有解压servletContxt.getRealPath就会返回一个空,这样导致vmx的处理会出问题。)

2.初始化过程
  在使用java -jar start.jar命令启动时,start.jar 的main函数在解析完命令行,设置好classpath等后调用invokeMain时,默认是调用Xmlconfiguration的main函数,这里会把一个个的xml拿出来解析(通过configure函数),参照文档中的标签逐一处理,代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


  for (; i < cfg.size(); i++)
{
Object o = cfg.get(i);
if (o instanceof String) continue;
XmlParser.Node node = (XmlParser.Node) o;
 
try
{
String tag = node.getTag();
if ("Set".equals(tag))
set(obj, node);
else if ("Put".equals(tag))
put(obj, node);
else if ("Call".equals(tag))
call(obj, node);
else if ("Get".equals(tag))
get(obj, node);

}


  考虑如下的jetty配置:
  <Call name=”addBean”>
<Arg>
<New id=”DeploymentManager” class=”org.eclipse.jetty.deploy.DeploymentManager”>
<Set name=”contexts”>
<Ref id=”Contexts” />
</Set>
  <Call name=”setContextAttribute”>
<Arg>org.eclipse.jetty.server.webapp.ContainerIncludeJarPattern</Arg>
<Arg>.*/jsp-api-[^/]*\.jar$|.*/jsp-[^/]*\.jar$</Arg>
</Call>
<!– Providers of Apps via WAR file existence.
Configured to behave similar to the legacy WebAppDeployer –>
<Call name=”addAppProvider”>
<Arg>
<New class=”org.eclipse.jetty.deploy.providers.WebAppProvider”>
<Set name=”monitoredDir”>D:/alibaba/web-deploy/jetty-server/webapps</Set>
<Set name=”scanInterval”>0</Set>
<Set name=”extractWars”><Property name=”jetty.extractWars” default=”true”/></Set>
<Set name=”defaultsDescriptor”>D:/alibaba/web-deploy/jetty-server/conf/webdefault.xml</Set>
</New>
</Arg>
</Call>
</New>
</Arg>
</Call>
  显然会调用call方法,先new出一个org.eclipse.jetty.deploy.DeploymentManager,然后在new出一个org.eclipse.jetty.deploy.providers.WebAppProvider,并调用addAppProvider方法,将new出来的WebAppProvider加入到DeploymentManager中。

3.启动过程
  在jetty的server调用server.start()的时候,会调用到DeploymentManager的dostart()方法如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


    @Override
protected void doStart() throws Exception
{
if (_useStandardBindings)
{
Log.debug("DeploymentManager using standard bindings");
addLifeCycleBinding(new StandardDeployer());
addLifeCycleBinding(new StandardStarter());
addLifeCycleBinding(new StandardStopper());
addLifeCycleBinding(new StandardUndeployer());
}
 
// Start all of the AppProviders
for (AppProvider provider : _providers)
{
startAppProvider(provider);
}
super.doStart();
}


  先初始化几个类,然后启动provider。
  配置中使用的WebAppProvider继承了ScanningAppProvider,WebAppProvider自身没有覆盖doStart方法,因此会调用ScanningAppProvider的dostart方法。顾名思义ScanningAppProvider就是扫描一个文件夹,并部署文件夹下jar包的类,其doStart的代码如下:


1
2
3
4
5
6
7
8
9
10


        File scandir = _monitoredDir.getFile();
Log.info("Deployment monitor " + scandir + " at interval " + _scanInterval);
_scanner = new Scanner();
_scanner.setScanDirs(Collections.singletonList(scandir));
_scanner.setScanInterval(_scanInterval);
_scanner.setRecursive(_recursive);
_scanner.setFilenameFilter(_filenameFilter);
_scanner.setReportDirs(true);
_scanner.addListener(_scannerListener);
_scanner.start();


  可以看到,new出来的Scanner是个核心逻辑,其start方法会调用scan方法,代码如下:


1
2
3
4
5
6
7


public synchronized void scan ()
{
scanFiles();
reportDifferences(_currentScan, _prevScan);
_prevScan.clear();
_prevScan.putAll(_currentScan);
}


  这里根据设置的目录调用:private void scanFile (File f, Map scanInfoMap, int depth)
把文件名和lastModify时间取出来,放到map,然后调用reportDifferences(_currentScan, _prevScan);
该方法把list中每个新旧文件时间比较,将新出现的文件调用reportAddition,修改时间大于间隔的调用reportChange,并将这两种文件加入到一个list bulkChanges中。再调用reportBulkChanges(bulkChanges);总之就是把新的war包或者修改了的war包重新处理一下。
  主要看看reportAddition方法,本质是通过内部类取出Scanner中的ScanningAppProvider (通_scannerListener)
然后调用


1
2
3
4
5
6
7
8
9
10


protected void fileAdded(String filename) throws Exception
{
if (Log.isDebugEnabled()) Log.debug("added ",filename);
App app = ScanningAppProvider.this.createApp(filename);
if (app != null)
{
_appMap.put(filename,app);
_deploymentManager.addApp(app);
}
}


  上面代码先创建app,然后用_deploymentManager去deploy,在_deploymentManager调用它的核心方法requestAppGoal,其方法会调用binding.ProcessBinding(这个AppLifeCycle.Binding接口有多个实现,包括StandardDeployer,StandardStarter,StandardStopper,StandardUnDeployer等),
  在这里先调用StandardDeployer.ProcessBinding,代码如下:


1
2


ContextHandler handler = app.getContextHandler();
app.getDeploymentManager().getContexts().addHandler(handler);


  其中app.getContextHandler()的具体代码如下:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17


    public ContextHandler getContextHandler() throws Exception
{
if (_context == null)
{
_context = getAppProvider().createContextHandler(this);
 
AttributesMap attributes = _manager.getContextAttributes();
if (attributes!=null && attributes.size()>0)
{
// Merge the manager attributes under the existing attributes
attributes = new AttributesMap(attributes);
attributes.addAll(_context.getAttributes());
_context.setAttributes(attributes);
}
}
return _context;
}


  核心逻辑是createContextHandler,这里AppProvider为WebAppProvider,因此调用它的createContextHandler方法该方法


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19


public ContextHandler createContextHandler(final App app) throws Exception
{
Resource resource = Resource.newResource(app.getOriginId());
File file = resource.getFile();
String context = file.getName();
根据是否war包等再处理下..
WebAppContext wah = new WebAppContext();
wah.setDisplayName(context);
再处理下root等特殊路径(比如 if (context.equalsIgnoreCase("root")) context="/";)
wah.setContextPath(context);
 
wah.setWar(file.getAbsolutePath());
if (_defaultsDescriptor != null)  wah.setDefaultsDescriptor(_defaultsDescriptor);
wah.setExtractWAR(_extractWars);
wah.setParentLoaderPriority(_parentLoaderPriority);
if (_configurationClasses != null)  wah.setConfigurationClasses(_configurationClasses);
if (_tempDirectory != null) wah.setAttribute(WebAppContext.BASETEMPDIR,_tempDirectory);
return wah;
}


  这个关键方法就把WebAppContext搞出来了,跟我们以前对WebAppContext的分析接上了。
  WebAppContext搞出来之后,还要设置到server中去,和connector对接起来。回到前面的 app.getDeploymentManager().getContexts().addHandler(handler);这句,在jetty.xml配置的
,因此把new出来的WebAppContext加进去,作为他的一个Handler。
  在ContextHandlerCollection的handle方法中,会根据context的值取出对应的handler,然后处理,这样保证多个war包也可以很好的处理。
  然后再通过生命周期的starting阶段,调用StandardStarter,调用handler.start()把这个handler启动起来,这里详见以前对WebAppContext的分析。
所有生命周期过完之后,这个war包就部署好了

回到reportDifferences方法,进行下一个war包的reportAddition处理,这里不详述了,文件夹也是一样。

4.其他


  • 对于拷贝到webapp目录下就可以服务的静态文件,主要是因为servletHandler有个default的Servlet,叫org.eclipse.jetty.servlet.DefaultServlet可以提供静态资源服务的。
  • WebAppContext是一个HandlerWrapper,他具体的handler是在start的过程中new出来的。具体在ServletContextHandler的startContext方法。

5.实际调用栈
  这里给出一个实际启动的调用栈


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


       at com.alibaba.webx.WebxLoader.configureAllServices(WebxLoader.java:694)
at com.alibaba.webx.WebxLoader.configure(WebxLoader.java:266)
at com.alibaba.webx.WebxControllerServlet.configure(WebxControllerServlet.java:54)
at com.alibaba.webx.controller.AbstractWebxControllerServlet.init(AbstractWebxControllerServlet.java:43)
at javax.servlet.GenericServlet.init(GenericServlet.java:241)
at org.eclipse.jetty.servlet.ServletHolder.initServlet(ServletHolder.java:431)
at org.eclipse.jetty.servlet.ServletHolder.doStart(ServletHolder.java:259)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
at org.eclipse.jetty.servlet.ServletHandler.initialize(ServletHandler.java:762)
at org.eclipse.jetty.servlet.ServletContextHandler.startContext(ServletContextHandler.java:244)
at org.eclipse.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1132)
at org.eclipse.jetty.server.handler.ContextHandler.doStart(ContextHandler.java:577)
at org.eclipse.jetty.webapp.WebAppContext.doStart(WebAppContext.java:491)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
at org.eclipse.jetty.deploy.bindings.StandardStarter.processBinding(StandardStarter.java:36)
at org.eclipse.jetty.deploy.AppLifeCycle.runBindings(AppLifeCycle.java:180)
at org.eclipse.jetty.deploy.DeploymentManager.requestAppGoal(DeploymentManager.java:497)
at org.eclipse.jetty.deploy.DeploymentManager.addApp(DeploymentManager.java:135)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider.fileAdded(ScanningAppProvider.java:144)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider$1.fileAdded(ScanningAppProvider.java:57)
at org.eclipse.jetty.util.Scanner.reportAddition(Scanner.java:436)
at org.eclipse.jetty.util.Scanner.reportDifferences(Scanner.java:349)
at org.eclipse.jetty.util.Scanner.scan(Scanner.java:306)
at org.eclipse.jetty.util.Scanner.start(Scanner.java:242)
at org.eclipse.jetty.deploy.providers.ScanningAppProvider.doStart(ScanningAppProvider.java:121)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
at org.eclipse.jetty.deploy.DeploymentManager.startAppProvider(DeploymentManager.java:562)
at org.eclipse.jetty.deploy.DeploymentManager.doStart(DeploymentManager.java:212)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
at org.eclipse.jetty.server.Server.doStart(Server.java:226)
at org.eclipse.jetty.util.component.AbstractLifeCycle.start(AbstractLifeCycle.java:55)
at org.eclipse.jetty.xml.XmlConfiguration$1.run(XmlConfiguration.java:1046)
at java.security.AccessController.doPrivileged(Native Method)
at org.eclipse.jetty.xml.XmlConfiguration.main(XmlConfiguration.java:983)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.jetty.start.Main.invokeMain(Main.java:490)
at org.eclipse.jetty.start.Main.start(Main.java:634)
at org.eclipse.jetty.start.Main.parseCommandLine(Main.java:280)
at org.eclipse.jetty.start.Main.main(Main.java:82)



 
  附:参考文献
官方文档:http://wiki.eclipse.org/Jetty/Feature/Deployment_Manager

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-347015-1-1.html 上篇帖子: 实战 Jetty 下篇帖子: Jetty介绍
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表