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

[经验分享] 浅析Tomcat之StandardWrapper

[复制链接]

尚未签到

发表于 2017-1-28 14:42:25 | 显示全部楼层 |阅读模式
Wrapper是Context的子容器,它代表了在应用部署描述中的一个单独的servlet.它通过Servlet的init和destroy方法掌管了底层的Servlet的生命周期.并且其中的阀还负责调用Servlet响应用户请求的功能.Wrapper的默认实现是StandardWrapper.
首先,还是很老套地说StandardWrapper的构造函数还是跟StandardContext等类似.也是设置了阀.与它的上层容器不同的是,StandardWrapper已经没有下层容器了,所以在它的addChild方法实现上是直接抛出一个IllegalStateException异常.下面看看几个重要的属性.

/**
* The load-on-startup order value (negative value means load on
* first call) for this servlet.
*/  
protected int loadOnStartup = -1;  
/**
* The initialization parameters for this servlet, keyed by
* parameter name.
*/  
protected HashMap<String, String> parameters = new HashMap<String, String>();  
/**
* Does this servlet implement the SingleThreadModel interface?
*/  
protected volatile boolean singleThreadModel = false;
   loadOnStartup代表的是在Servlet在容器启动的时候的加载顺序,如果为负数的话就是Servlet在第一次被使用的时候进行加载实例化.parameters 应该很熟悉,它代表是是Servlet的参数,这是一个Map.也就是web.xml中所配置的启动参数.singleThreadModel代表是单线程模式,是保证一个特定 servlet 实例的 service 方法在一个时刻仅能被一个线程执行,此保证仅适用于每一个 servlet 实例,因此容器可以选择池化这些对象.
借着loadOnStartup属性我们串一串几个Wrapper中初始化中两个重要的方法.它们是load和loadServlet.那么loadOnStartup在哪里被使用呢?这个可以追溯到Context里面,在Context生命周期的start中调用了它自己的一个函数loadOnStartup,该方法的注释为Load and initialize all servlets marked “load on startup” in the web application deployment descriptor.

TreeMap<Integer, ArrayList<Wrapper>> map =new TreeMap<Integer, ArrayList<Wrapper>>();  
for (int i = 0; i < children.length; i++) {  
Wrapper wrapper = (Wrapper) children;  
int loadOnStartup = wrapper.getLoadOnStartup();  
if (loadOnStartup < 0)  
continue;  
Integer key = Integer.valueOf(loadOnStartup);  
ArrayList<Wrapper> list = map.get(key);  
if (list == null) {  
list = new ArrayList<Wrapper>();  
map.put(key, list);  
}  
list.add(wrapper);  
}  
// Load the collected "load on startup" servlets  
for (ArrayList<Wrapper> list : map.values()) {  
for (Wrapper wrapper : list) {  
try {  
wrapper.load();  
} catch (ServletException e) {  
getLogger().error(sm.getString("standardWrapper.loadException",  
getName()), StandardWrapper.getRootCause(e));  
// NOTE: load errors (including a servlet that throws  
// UnavailableException from tht init() method) are NOT  
// fatal to application startup  
}  
}  
}  
  上述代码的上半段是根据Wrapper的loadOnStartup属性对Wrapper进行处理,大于0的进行分类.下半段对已分类好的Wrapper进行便利调用其load方法.TreeMap已经根据其key从小到大进行排序.那么看看Wrapper得load方法.

public synchronized void load() throws ServletException {  
instance = loadServlet();  
if (!instanceInitialized) {  
initServlet(instance);  
}  
if (isJspServlet) {  
StringBuilder oname =  
new StringBuilder(MBeanUtils.getDomain(getParent()));  
oname.append(":type=JspMonitor,name=");  
oname.append(getName());  
oname.append(getWebModuleKeyProperties());  
try {  
jspMonitorON = new ObjectName(oname.toString());  
Registry.getRegistry(null, null)  
.registerComponent(instance, jspMonitorON, null);  
} catch( Exception ex ) {  
log.info("Error registering JSP monitoring with jmx " +  
instance);  
}  
}  
}  
   从上述代码中可以清晰地看出,最开始是调用了loadServlet方法加载Servlet,接着判断是否该Servlet已经初始化,如果没有的话则调用init方法进行初始化.Servlet是一个接口,具体的init方法在其子类中实现.后面基本是一些JMX的注册.我们看看loadServlet.

public synchronized Servlet loadServlet() throws ServletException {  
// Nothing to do if we already have an instance or an instance pool  
if (!singleThreadModel && (instance != null))  
return instance;  
PrintStream out = System.out;  
if (swallowOutput) {  
SystemLogHandler.startCapture();  
}  
Servlet servlet;  
try {  
long t1=System.currentTimeMillis();  
// Complain if no servlet class has been specified  
if (servletClass == null) {  
unavailable(null);  
throw new ServletException  
(sm.getString("standardWrapper.notClass", getName()));  
}  
InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager();  
try {  
servlet = (Servlet) instanceManager.newInstance(servletClass);  
} catch (ClassCastException e) {  
unavailable(null);  
// Restore the context ClassLoader  
throw new ServletException  
(sm.getString("standardWrapper.notServlet", servletClass), e);  
} catch (Throwable e) {  
e = ExceptionUtils.unwrapInvocationTargetException(e);  
ExceptionUtils.handleThrowable(e);  
unavailable(null);  
// Added extra log statement for Bugzilla 36630:  
// http://issues.apache.org/bugzilla/show_bug.cgi?id=36630  
if(log.isDebugEnabled()) {  
log.debug(sm.getString("standardWrapper.instantiate", servletClass), e);  
}  
// Restore the context ClassLoader  
throw new ServletException  
(sm.getString("standardWrapper.instantiate", servletClass), e);  
}  
if (multipartConfigElement == null) {  
MultipartConfig annotation =  
servlet.getClass().getAnnotation(MultipartConfig.class);  
if (annotation != null) {  
multipartConfigElement =  
new MultipartConfigElement(annotation);  
}  
}  
processServletSecurityAnnotation(servlet.getClass());  
// Special handling for ContainerServlet instances  
if ((servlet instanceof ContainerServlet) &&  
(isContainerProvidedServlet(servletClass) ||  
((Context) getParent()).getPrivileged() )) {  
((ContainerServlet) servlet).setWrapper(this);  
}  
classLoadTime=(int) (System.currentTimeMillis() -t1);  
if (servlet instanceof SingleThreadModel) {  
if (instancePool == null) {  
instancePool = new Stack<Servlet>();  
}  
singleThreadModel = true;  
}  
initServlet(servlet);  
fireContainerEvent("load", this);  
loadTime=System.currentTimeMillis() -t1;  
} finally {  
.....  
}  
return servlet;  
}  
  上述代码实现的功能是Servlet的初始化.最主要的是servlet = (Servlet) instanceManager.newInstance(servletClass);它实例化了web.xml中描述的servlet.下面的大部分代码是异常捕获和调用初始化方法.
经过分析,我们知道Wrapper是在Context初始化的时候根据web.xml中的部署描述进行实例化的,Context不仅根据部署描述进行Wrapper的创建,还调用了其load方法进行了其中Servlet的创建以及初始化.Servlet一旦被加载后,便能为web用户服务.后续博文将介绍请求到达Wrapper后,它是怎样使用Servlet进行请求处理的.
 
 
首发于泛泛之辈 - http://www.lihongkun.com/archives/157

运维网声明 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-334579-1-1.html 上篇帖子: 浅析Tomcat之AbstractProtocol 下篇帖子: tomcat 迁移 weblogic session丢失
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

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

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

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

扫描微信二维码查看详情

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


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


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


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



合作伙伴: 青云cloud

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