您的位置:首页 > 运维架构 > Tomcat

Tomcat源码阅读之StandarWrapper源码分析

2014-03-24 20:34 435 查看
这几天有点杂事,没有怎么看代码了,今天来把最下层的Container对象看了吧,这里之所以说它是最下层的container对象,是因为它不能在调用addChild方法来添加其他的子container对象了。。。

StandarWrapper,嗯,其实可以将其理解为对servlet对象的包装。。。先来看看简单的继承结构吧:



这里的继承体系还算是比较简单吧,首先是继承了ContainerBase,让StandarWrapper有了基本的对Container的管理能力,其实是先了ServletConfig接口,这个接口应该比较熟悉吧,在servlet的初始化的时候,传进去的就是这个参数,另外就是还有实现了Wrapper接口和NotificationEmitter。。。

从前面可以知道,Wrapper对象是在ContextConfig对象中解析web应用程序的配置的时候创建的,它会读取配置文件里面申明的class属性,name,以及一些参数等。。。

这里先来看看Wrapper接口的定义吧://wrapper接口的定义,这里可以理解为对servlet的包装
public interface Wrapper extends Container {
//一些事件的定义,主要是添加和移除map的信息
public static final String ADD_MAPPING_EVENT = "addMapping";
public static final String REMOVE_MAPPING_EVENT = "removeMapping";

// 返回这个servlet还需要多长时间可以用
public long getAvailable();

//
public void setAvailable(long available);

//是否要在加载的时候启动,如果是负的话,那么表示在第一次调用的时候启动
public int getLoadOnStartup();

public void setLoadOnStartup(int value);
public String getRunAs();

public void setRunAs(String runAs);

//servlet的class
public String getServletClass();

// 设置servlet的class
public void setServletClass(String servletClass);

//servlet支持的所有方法
public String[] getServletMethods() throws ServletException;

//现在是否不能用
public boolean isUnavailable();

//返回servlet对象
public Servlet getServlet();

//设置关联的servlet对象
public void setServlet(Servlet servlet);

//添加servlet的初始化参数
public void addInitParameter(String name, String value);

//添加监听
public void addInstanceListener(InstanceListener listener);

//为当前servlet添加map信息
public void addMapping(String mapping);

public void addSecurityReference(String name, String link);

//这里表示分配一个servlet对象,这里会区分当前servlet的环境,如果不是单线程模式的吧,那么所有的都返回同一个对象
public Servlet allocate() throws ServletException;

//表示返回一个servlet到pool里面,只有在servlet配置为单线程模式的时候才有用
public void deallocate(Servlet servlet) throws ServletException;

//获取一个初始化的参数的值
public String findInitParameter(String name);

//返回所有的初始化参数的名字
public String[] findInitParameters();

//返回这个servlet所有的map信息
public String[] findMappings();

public String findSecurityReference(String name);

public String[] findSecurityReferences();

//增加错误计数
public void incrementErrorCount();

//加载并初始化servlet对象
public void load() throws ServletException;

//移除一个初始化的参数
public void removeInitParameter(String name);

//移除listener
public void removeInstanceListener(InstanceListener listener);

//移除一个mapping信息
public void removeMapping(String mapping);

public void removeSecurityReference(String name);

public void unavailable(UnavailableException unavailable);

//这里表示卸载所有的servlet实例
public void unload() throws ServletException;

public MultipartConfigElement getMultipartConfigElement();

public void setMultipartConfigElement(
MultipartConfigElement multipartConfig);

//该servlet是否支持异步
public boolean isAsyncSupported();

public void setAsyncSupported(boolean asyncSupport);

//当前关联的servlet是否可用
public boolean isEnabled();

public void setEnabled(boolean enabled);

public void setServletSecurityAnnotationScanRequired(boolean b);

public void servletSecurityAnnotationScan() throws ServletException;

public boolean isOverridable();

public void setOverridable(boolean overridable);
}

嗯,方法的定义虽然还比较的多,但其实都还算是比较简答的,首先是两个事件的定义,分别是添加和移除map的信息,然后就还有一些属性的设置和获取的方法,最后还有比较重要的就是load方法,用于加载servlet对象。。

这里先来看看构造方法和一些重要的属性申明吧: protected static final String[] DEFAULT_SERVLET_METHODS = new String[] {
"GET", "HEAD", "POST" };
public StandardWrapper() {

super();
swValve=new StandardWrapperValve(); //创建pipeline上的basic的valve对象
pipeline.setBasic(swValve);
broadcaster = new NotificationBroadcasterSupport();

}

protected long available = 0L; //还需要多少事件当前servlet可以用,如果是0的话,那么表示servlet现在就可以用了

protected final NotificationBroadcasterSupport broadcaster;

protected final AtomicInteger countAllocated = new AtomicInteger(0); //已经分配了servlet对象的数目,单线程模式下

protected final StandardWrapperFacade facade = new StandardWrapperFacade(this); //servletConfig对象,用于维护servlet的初始化参数什么的,其实是对standerWrapper进行了包装

protected volatile Servlet instance = null; //共享模式下的对象

protected volatile boolean instanceInitialized = false; //用于标记servlet对象是否初始化

protected final InstanceSupport instanceSupport = new InstanceSupport(this); //用于处理一些实例的事件

protected int loadOnStartup = -1; //是否在加载的时候启动servlet,默认不是

protected final ArrayList<String> mappings = new ArrayList<>(); //这个servlet的所有mapping信息

protected HashMap<String, String> parameters = new HashMap<>(); //初始化参数

protected HashMap<String, String> references = new HashMap<>();

protected String runAs = null;

protected long sequenceNumber = 0; //通知的序列号

protected String servletClass = null; //servlet对象的class

protected volatile boolean singleThreadModel = false; //是否是单线程模型,如果是的话,每一个线程将会独占一个servlet对象

protected boolean unloading = false; //当前是否在卸载servlet对象

protected int maxInstances = 20; //最大的servlet对象数量

protected int nInstances = 0; //当前已经实例化的servlet对象数量(在单线程模式下用)

protected Stack<Servlet> instancePool = null; //在单线程模式下,将会维护一个servlet的对象池

protected long unloadDelay = 2000;

protected boolean isJspServlet; //是不是jsp的servlet

protected ObjectName jspMonitorON;

protected boolean swallowOutput = false; //是否要重定向servlet的system.out到log

// To support jmx attributes
protected StandardWrapperValve swValve; //pipeline上面的基本valve对象
protected long loadTime=0;
protected int classLoadTime=0;

protected MultipartConfigElement multipartConfigElement = null; //multipart的配置

protected boolean asyncSupported = false; //是否支持异步

protected boolean enabled = true; //是否可用

protected volatile boolean servletSecurityAnnotationScanRequired = false; //安全注释扫描

private boolean overridable = false;
这里构造方法其实主要是在pipeline上面添加一个basic类型的valve对象。。然后对于下面属性的申明,应该注释也说的比较清楚吧。。。

这里再来看看比较重要的load方法吧,看看是如何加载servlet对象的。。。 //加载并初始化servlet,还要在jmx上面注册
public synchronized void load() throws ServletException {
instance = loadServlet();

if (!instanceInitialized) {
initServlet(instance);
}

// 如果是jsp的servlet的话,那么需要进行jmx上面的注册
if (isJspServlet) {
StringBuilder oname = new StringBuilder(getDomain());

oname.append(":type=JspMonitor");

oname.append(getWebModuleKeyProperties());

oname.append(",name=");
oname.append(getName());

oname.append(getJ2EEKeyProperties());

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对象,用instance来引用。。然后调用initServlet方法来初始化servlet.好了,那就先来看看loadServlet方法吧: // 加载servlet对象
public synchronized Servlet loadServlet() throws ServletException {

// Nothing to do if we already have an instance or an instance pool
if (!singleThreadModel && (instance != null)) //如果不是单线程模式,而且有instanc了,那么直接返回吧
return instance;

PrintStream out = System.out;
if (swallowOutput) { //是否将servle的system.out输出定向到log
SystemLogHandler.startCapture();
}

Servlet servlet;
try {
long t1=System.currentTimeMillis(); //获取当前时间
// Complain if no servlet class has been specified
if (servletClass == null) { //这里都没有class,那么返回错误吧
unavailable(null);
throw new ServletException
(sm.getString("standardWrapper.notClass", getName()));
}
//其实最终还是调用webappclassLoader来载入class,然后再创建对象的
InstanceManager instanceManager = ((StandardContext)getParent()).getInstanceManager(); //获取所属context的instanceManager对象
try {
servlet = (Servlet) instanceManager.newInstance(servletClass); //调用instanceManager来加载servlet的class,并创建
} 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); //获取multipart的注释申明
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<>();
}
singleThreadModel = true;
}

initServlet(servlet); // 初始化servlet

fireContainerEvent("load", this);

loadTime=System.currentTimeMillis() -t1;
} finally {
if (swallowOutput) {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
if (getServletContext() != null) {
getServletContext().log(log);
} else {
out.println(log);
}
}
}
}
return servlet;

}
代码应该很简单吧,无非是调用context的instanceManager对象来创建servlet对象,当然这里还要区分servlet是否是单线程模式。。。其他的代码上面注释应该也还算比较清楚吧。。都比较的简单。。。

那么再来看看如何初始化servlet吧: //初始化serlvet
private synchronized void initServlet(Servlet servlet)
throws ServletException {

if (instanceInitialized && !singleThreadModel) return;

// Call the initialization method of this servlet
try {
instanceSupport.fireInstanceEvent(InstanceEvent.BEFORE_INIT_EVENT,
servlet);

if( Globals.IS_SECURITY_ENABLED) {
boolean success = false;
try {
Object[] args = new Object[] { facade };
SecurityUtil.doAsPrivilege("init",
servlet,
classType,
args);
success = true;
} finally {
if (!success) {
// destroy() will not be called, thus clear the reference now
SecurityUtil.remove(servlet);
}
}
} else {
servlet.init(facade); //初始化servlet
}

instanceInitialized = true;

instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
servlet);
} catch (UnavailableException f) {
instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
servlet, f);
unavailable(f);
throw f;
} catch (ServletException f) {
instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
servlet, f);
// If the servlet wanted to be unavailable it would have
// said so, so do not call unavailable(null).
throw f;
} catch (Throwable f) {
ExceptionUtils.handleThrowable(f);
getServletContext().log("StandardWrapper.Throwable", f );
instanceSupport.fireInstanceEvent(InstanceEvent.AFTER_INIT_EVENT,
servlet, f);
// If the servlet wanted to be unavailable it would have
// said so, so do not call unavailable(null).
throw new ServletException
(sm.getString("standardWrapper.initException", getName()), f);
}
}
这里其实init方法传入的是facade对象,它是一个门面模式吧,其实是对当前standarWrapper对象的一个包装。。。

好了,其实到这里standardWrapper的主要的东西都差不多了。。这里再来看看StandardWrapperValve类型吧,其实最终处理请求还是调用它的invoke方法来处理的。。。

先来看看一些基本的属性的定义: private volatile long processingTime; //请求的处理事件
private volatile long maxTime; //处理这里http请求的最大耗费的时间
private volatile long minTime = Long.MAX_VALUE; //处理这次http请求最短耗费的时间
private final AtomicInteger requestCount = new AtomicInteger(0); //用于请求的计数
private final AtomicInteger errorCount = new AtomicInteger(0); //用于记录错误数量
嗯,其实从名字就基本上就能知道这些属性是干嘛的。。。

接下来来看看最重要的invoke方法吧: // 在context的pipeline里面会调用wrapper对象的pipeline来处理请求
public final void invoke(Request request, Response response)
throws IOException, ServletException {

// Initialize local variables we may need
boolean unavailable = false; //初始化的时候可用
Throwable throwable = null;
// This should be a Request attribute...
long t1=System.currentTimeMillis(); //当前时间
requestCount.incrementAndGet(); //请求计数加1
StandardWrapper wrapper = (StandardWrapper) getContainer(); //获取所属的container对象,其实也就是wrapper
Servlet servlet = null;
Context context = (Context) wrapper.getParent(); //获取context

// Check for the application being marked unavailable
if (!context.getState().isAvailable()) { //如果context不可用,那么表示当前服务不可用,返回错误就好了
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardContext.isUnavailable"));
unavailable = true;
}

// Check for the servlet being marked unavailable
if (!unavailable && wrapper.isUnavailable()) { //当前servlet暂时不可用
container.getLogger().info(sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
long available = wrapper.getAvailable(); //还要多久可用
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available); //返回重试报文
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
unavailable = true;
}

// Allocate a servlet instance to process this request
try {
if (!unavailable) { //当前的servlet可以用
servlet = wrapper.allocate(); //获取servlet对象
}
} catch (UnavailableException e) {
container.getLogger().error(
sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
} catch (ServletException e) {
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), StandardWrapper.getRootCause(e));
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.allocateException",
wrapper.getName()), e);
throwable = e;
exception(request, response, e);
servlet = null;
}

// Identify if the request is Comet related now that the servlet has been allocated
boolean comet = false;
if (servlet instanceof CometProcessor && request.getAttribute( //看当前servlet是否支持comet
Globals.COMET_SUPPORTED_ATTR) == Boolean.TRUE) {
comet = true;
request.setComet(true);
}

MessageBytes requestPathMB = request.getRequestPathMB(); //获取当前请求的path /examples 啥的
DispatcherType dispatcherType = DispatcherType.REQUEST; //设置当前请求的类型
if (request.getDispatcherType()==DispatcherType.ASYNC) dispatcherType = DispatcherType.ASYNC;
request.setAttribute(Globals.DISPATCHER_TYPE_ATTR,dispatcherType); //设置派遣类型,是否是异步的啥的,或者就是普通的request
request.setAttribute(Globals.DISPATCHER_REQUEST_PATH_ATTR,
requestPathMB); //设置path属性
// Create the filter chain for this request
ApplicationFilterFactory factory =
ApplicationFilterFactory.getInstance(); //创建filter
ApplicationFilterChain filterChain = //创建filterChain,先调用filter来处理请求,在调用servlet的servie方法
factory.createFilterChain(request, wrapper, servlet);

// Reset comet flag value after creating the filter chain
request.setComet(false);

// Call the filter chain for this request
// NOTE: This also calls the servlet's service() method
try {
if ((servlet != null) && (filterChain != null)) {
// Swallow output if needed
if (context.getSwallowOutput()) {
try {
SystemLogHandler.startCapture();
if (request.isAsyncDispatching()) { // 如果是异步的执行
((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
} else if (comet) { //如果是comet的话,执行这里
filterChain.doFilterEvent(request.getEvent());
request.setComet(true);
} else {
filterChain.doFilter(request.getRequest(), //一般情况下是坐这里,在filter调用完了之后,会调用servlet的service方法
response.getResponse());
}
} finally {
String log = SystemLogHandler.stopCapture();
if (log != null && log.length() > 0) {
context.getLogger().info(log);
}
}
} else {
if (request.isAsyncDispatching()) {
((AsyncContextImpl)request.getAsyncContext()).doInternalDispatch();
} else if (comet) {
request.setComet(true);
filterChain.doFilterEvent(request.getEvent());
} else {
filterChain.doFilter
(request.getRequest(), response.getResponse());
}
}

}
} catch (ClientAbortException e) {
throwable = e;
exception(request, response, e);
} catch (IOException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
} catch (UnavailableException e) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
// throwable = e;
// exception(request, response, e);
wrapper.unavailable(e);
long available = wrapper.getAvailable();
if ((available > 0L) && (available < Long.MAX_VALUE)) {
response.setDateHeader("Retry-After", available);
response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE,
sm.getString("standardWrapper.isUnavailable",
wrapper.getName()));
} else if (available == Long.MAX_VALUE) {
response.sendError(HttpServletResponse.SC_NOT_FOUND,
sm.getString("standardWrapper.notFound",
wrapper.getName()));
}
// Do not save exception in 'throwable', because we
// do not want to do exception(request, response, e) processing
} catch (ServletException e) {
Throwable rootCause = StandardWrapper.getRootCause(e);
if (!(rootCause instanceof ClientAbortException)) {
container.getLogger().error(sm.getString(
"standardWrapper.serviceExceptionRoot",
wrapper.getName(), context.getName(), e.getMessage()),
rootCause);
}
throwable = e;
exception(request, response, e);
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString(
"standardWrapper.serviceException", wrapper.getName(),
context.getName()), e);
throwable = e;
exception(request, response, e);
}

// Release the filter chain (if any) for this request
if (filterChain != null) {
if (request.isComet()) { //如果是comet类型的话,
// If this is a Comet request, then the same chain will be used for the
// processing of all subsequent events.
filterChain.reuse(); //那么可以重用这个filter链
} else {
filterChain.release(); //如果不是comet的话,那么可以释放了
}
}

// Deallocate the allocated servlet instance
try {
if (servlet != null) {
wrapper.deallocate(servlet); // 相当于释放servlet,只有在配置servlet为单线程的时候才有用,将会返还到pool
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.deallocateException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}

// If this servlet has been marked permanently unavailable,
// unload it and release this instance
try {
if ((servlet != null) &&
(wrapper.getAvailable() == Long.MAX_VALUE)) {
wrapper.unload();
}
} catch (Throwable e) {
ExceptionUtils.handleThrowable(e);
container.getLogger().error(sm.getString("standardWrapper.unloadException",
wrapper.getName()), e);
if (throwable == null) {
throwable = e;
exception(request, response, e);
}
}
long t2=System.currentTimeMillis();

long time=t2-t1;
processingTime += time; //处理耗费时间
if( time > maxTime) maxTime=time; //设置最大处理时间
if( time < minTime) minTime=time; //设置最小处理时间

}
代码够长吧,不过注释应该也交代清楚了。。首先调用allocate方法来获取一个servlet对象,然后在最终调用servlet对象的service方法来处理之前还需要先ApplicationFilterChain对象来包装filter对象,然后再调用doFilter方法,先执行filter,然后在里面才回调用servlet来处理。。

这里发现,其实每次都要构造新的ApplicationFilterChain对象,并没有做缓存。。是不是不太好呢。。?起码在jetty中这部分是做了缓存的。。。

好了,到这里standarwrapper就差不多了吧。。写的比较粗糙。。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: