CoyoteAdapter.service():
if (postParseRequest(req, request, res, response)) {
// Calling the container
//Http1.1调用StandardEngineValve.invoke(request,response)
connector.getContainer().getPipeline().getFirst().invoke(request, response);
......
}
postParseRequest()还需要对请求进行封装:
connector.getMapper().map(serverName, decodedURI,
request.getMappingData());
request.setContext((Context) request.getMappingData().context);
这个connector是在Connector.init()方法中,创建CayoteAdapter对象的时候赋值的:
adapter = new CoyoteAdapter(this);
this即使Connector对象自身,connector.getMapper()返回的是Mapper对象,在Connector属性中new出来的:
protected Mapper mapper = new Mapper();
Mapper.map():
public void map(MessageBytes host, MessageBytes uri,
MappingData mappingData)
throws Exception {
if (host.isNull()) {
host.getCharChunk().append(defaultHostName);
}
host.toChars();
uri.toChars();
internalMap(host.getCharChunk(), uri.getCharChunk(), mappingData);
}
根据uri将,mapper中的Host、Context、Wrapper对象赋值到request.mappingData中。
Mapper.internalMap():
/**
* Map the specified URI.
*/
private final void internalMap(CharChunk host, CharChunk uri,
MappingData mappingData)
throws Exception {
uri.setLimit(-1);
Context[] contexts = null;
Context context = null;
int nesting = 0;
// Virtual host mapping
if (mappingData.host == null) {
Host[] hosts = this.hosts;
int pos = findIgnoreCase(hosts, host);
if ((pos != -1) && (host.equalsIgnoreCase(hosts[pos].name))) {
mappingData.host = hosts[pos].object;
contexts = hosts[pos].contextList.contexts;
nesting = hosts[pos].contextList.nesting;
} else {
if (defaultHostName == null) {
return;
}
pos = find(hosts, defaultHostName);
if ((pos != -1) && (defaultHostName.equals(hosts[pos].name))) {
mappingData.host = hosts[pos].object;
contexts = hosts[pos].contextList.contexts;
nesting = hosts[pos].contextList.nesting;
} else {
return;
}
}
}
// Context mapping
if (mappingData.context == null) {
int pos = find(contexts, uri);
if (pos == -1) {
return;
}
int lastSlash = -1;
int uriEnd = uri.getEnd();
int length = -1;
boolean found = false;
while (pos >= 0) {
if (uri.startsWith(contexts[pos].name)) {
length = contexts[pos].name.length();
if (uri.getLength() == length) {
found = true;
break;
} else if (uri.startsWithIgnoreCase("/", length)) {
found = true;
break;
}
}
if (lastSlash == -1) {
lastSlash = nthSlash(uri, nesting + 1);
} else {
lastSlash = lastSlash(uri);
}
uri.setEnd(lastSlash);
pos = find(contexts, uri);
}
uri.setEnd(uriEnd);
if (!found) {
if (contexts[0].name.equals("")) {
context = contexts[0];
}
} else {
context = contexts[pos];
}
if (context != null) {
mappingData.context = context.object;
mappingData.contextPath.setString(context.name);
}
}
// Wrapper mapping
if ((context != null) && (mappingData.wrapper == null)) {
internalMapWrapper(context, uri, mappingData);
}
}
而Mapper中的Host、Context、Wrapper类只是简单的内部类,并非之前的StandardContext、StandardHost、StandardWrapper。
// ------------------------------------------------------- Host Inner Class
protected static final class Host
extends MapElement {
public ContextList contextList = null;
}
// ------------------------------------------------ ContextList Inner Class
protected static final class ContextList {
public Context[] contexts = new Context[0];
public int nesting = 0;
}
// ---------------------------------------------------- Context Inner Class
protected static final class Context
extends MapElement {
public String path = null;
public String[] welcomeResources = new String[0];
public javax.naming.Context resources = null;
public Wrapper defaultWrapper = null;
public Wrapper[] exactWrappers = new Wrapper[0];
public Wrapper[] wildcardWrappers = new Wrapper[0];
public Wrapper[] extensionWrappers = new Wrapper[0];
public int nesting = 0;
}
// ---------------------------------------------------- Wrapper Inner Class
protected static class Wrapper
extends MapElement {
public String path = null;
public boolean jspWildCard = false;
}
他们都继承了MapElement类:
protected static abstract class MapElement {
public String name = null;
public Object object = null;
}
就几个字段,用来存储所有的容器类。那这些类是什么时候存储的,又是如何存储的呢?
Connector.start():
mapperListener.setDomain( domain );
//mapperListener.setEngine( service.getContainer().getName() );
mapperListener.init();
mapperListener来自Connector的属性:
protected MapperListener mapperListener = new MapperListener(mapper, this);
传入的参数是前面的mapper对象和Connector自身对象。
MapperListener.init():
public void init() {
try {
mBeanServer = Registry.getRegistry(null, null).getMBeanServer();
registerEngine();
// Query hosts
String onStr = domain + ":type=Host,*";
ObjectName objectName = new ObjectName(onStr);
Set set = mBeanServer.queryMBeans(objectName, null);
Iterator iterator = set.iterator();
while (iterator.hasNext()) {
ObjectInstance oi = (ObjectInstance) iterator.next();
registerHost(oi.getObjectName());
}
// Query contexts
onStr = "*:j2eeType=WebModule,*";
objectName = new ObjectName(onStr);
set = mBeanServer.queryMBeans(objectName, null);
iterator = set.iterator();
while (iterator.hasNext()) {
ObjectInstance oi = (ObjectInstance) iterator.next();
registerContext(oi.getObjectName());
}
// Query wrappers
onStr = "*:j2eeType=Servlet,*";
objectName = new ObjectName(onStr);
set = mBeanServer.queryMBeans(objectName, null);
iterator = set.iterator();
while (iterator.hasNext()) {
ObjectInstance oi = (ObjectInstance) iterator.next();
registerWrapper(oi.getObjectName());
}
onStr = "JMImplementation:type=MBeanServerDelegate";
objectName = new ObjectName(onStr);
mBeanServer.addNotificationListener(objectName, this, null, null);
} catch (Exception e) {
log.warn("Error registering contexts",e);
}
}
MapperListener.registerContext():
private void registerContext(ObjectName objectName)
throws Exception {
String name = objectName.getKeyProperty("name");
// If the domain is the same with ours or the engine
// name attribute is the same... - then it's ours
String targetDomain=objectName.getDomain();
if( ! domain.equals( targetDomain )) {
try {
targetDomain = (String) mBeanServer.getAttribute
(objectName, "engineName");
} catch (Exception e) {
// Ignore
}
if( ! domain.equals( targetDomain )) {
// not ours
return;
}
}
String hostName = null;
String contextName = null;
if (name.startsWith("//")) {
name = name.substring(2);
}
int slash = name.indexOf("/");
if (slash != -1) {
hostName = name.substring(0, slash);
contextName = name.substring(slash);
} else {
return;
}
// Special case for the root context
if (contextName.equals("/")) {
contextName = "";
}
if(log.isDebugEnabled())
log.debug(sm.getString
("mapperListener.registerContext", contextName));
Object context =
mBeanServer.invoke(objectName, "findMappingObject", null, null);
//mBeanServer.getAttribute(objectName, "mappingObject");
javax.naming.Context resources = (javax.naming.Context)
mBeanServer.invoke(objectName, "findStaticResources", null, null);
//mBeanServer.getAttribute(objectName, "staticResources");
String[] welcomeFiles = (String[])
mBeanServer.getAttribute(objectName, "welcomeFiles");
mapper.addContext(hostName, contextName, context,
welcomeFiles, resources);
}
Tomcat使用JMX管理资源。
JmxMBeanServer作为管理MBean的容器:
1.使用registerMBean(Object object, ObjectName name)往里边保存bean。registerMBean的第一个参数为继承了BaseModuleBean的对象。第二个参数为封装了唯一性String的ObjectName对象。
2.需要调用BaseModuleBean的方法时,用MBeanServer.invoke()方法。第一个参数为唯一性ObjectName,第二个参数为需要调用的方法名。MBeanServer根据ObjectName找到对应的BaseModuleBean,然后调用其名为第二个参数的方法。
Object context = mBeanServer.invoke(objectName, "findMappingObject", null, null);
调用objectName对应的StandardContext对象的findMappingObject方法,最终将返回StandardContext对象自身。
3.需要返回 BaseModuleBean的属性时,用MBeanServer.getAttribute() 方法。第一个参数为唯一性ObjectName,第二个参数为参数名。
String[] welcomeFiles = (String[])
mBeanServer.getAttribute(objectName, "welcomeFiles");
将返回StandardContext对象的的welcomeFiles属性。
那么这些相关的bean是什么时候放到MBeanServer中的呢?
StandardContext.start()时候已经进行了注册。
private void preRegisterJMX() {
try {
StandardHost host = (StandardHost) getParent();
if ((oname == null)
|| (oname.getKeyProperty("j2eeType") == null)) {
oname = createObjectName(host.getDomain(), host.getJmxName());
controller = oname;
}
} catch(Exception ex) {
if(log.isInfoEnabled())
log.info("Error registering ctx with jmx " + this + " " +
oname + " " + ex.toString(), ex );
}
}
createObjectName():
public ObjectName createObjectName(String hostDomain, ObjectName parentName)
throws MalformedObjectNameException
{
String onameStr;
StandardHost hst=(StandardHost)getParent();
String pathName=getName();
String hostName=getParent().getName();
String name= "//" + ((hostName==null)? "DEFAULT" : hostName) +
(("".equals(pathName))?"/":pathName );
String suffix=",J2EEApplication=" +
getJ2EEApplication() + ",J2EEServer=" +
getJ2EEServer();
onameStr="j2eeType=WebModule,name=" + name + suffix;
if( log.isDebugEnabled())
log.debug("Registering " + onameStr + " for " + oname);
// default case - no domain explictely set.
if( getDomain() == null ) domain=hst.getDomain();
ObjectName oname=new ObjectName(getDomain() + ":" + onameStr);
return oname;
}
以上只是创建ObjectName,registerJMX();
private void registerJMX() {
try {
if (log.isDebugEnabled()) {
log.debug("Checking for " + oname );
}
if(! Registry.getRegistry(null, null)
.getMBeanServer().isRegistered(oname)) {
controller = oname;
Registry.getRegistry(null, null)
.registerComponent(this, oname, null);
// Send j2ee.object.created notification
if (this.getObjectName() != null) {
Notification notification = new Notification(
"j2ee.object.created",
this.getObjectName(),
sequenceNumber++);
broadcaster.sendNotification(notification);
}
}
Container children[] = findChildren();
for (int i=0; children!=null && i<children.length; i++) {
((StandardWrapper)children[i]).registerJMX( this );
}
} catch (Exception ex) {
if(log.isInfoEnabled())
log.info("Error registering wrapper with jmx " + this + " " +
oname + " " + ex.toString(), ex );
}
}
Registry.getRegistry(null, null).registerComponent(this, oname, null);
public void registerComponent(Object bean, ObjectName oname, String type)
throws Exception
{
if( log.isDebugEnabled() ) {
log.debug( "Managed= "+ oname);
}
if( bean ==null ) {
log.error("Null component " + oname );
return;
}
try {
if( type==null ) {
type=bean.getClass().getName();
}
ManagedBean managed = findManagedBean(bean.getClass(), type);
// The real mbean is created and registered
DynamicMBean mbean = managed.createMBean(bean);
if( getMBeanServer().isRegistered( oname )) {
if( log.isDebugEnabled()) {
log.debug("Unregistering existing component " + oname );
}
getMBeanServer().unregisterMBean( oname );
}
getMBeanServer().registerMBean( mbean, oname);
} catch( Exception ex) {
log.error("Error registering " + oname, ex );
throw ex;
}
}
getMBeanServer().registerMBean( mbean, oname);既是将mbean存入MBeanServer。
回到MapperListener.registerContext():
mapper.addContext(hostName, contextName, context,
welcomeFiles, resources);
Mapper.addContext():
public void addContext
(String hostName, String path, Object context,
String[] welcomeResources, javax.naming.Context resources) {
Host[] hosts = this.hosts;
int pos = find(hosts, hostName);
if( pos <0 ) {
addHost(hostName, new String[0], "");
hosts = this.hosts;
pos = find(hosts, hostName);
}
if (pos < 0) {
logger.error("No host found: " + hostName);
}
Host host = hosts[pos];
if (host.name.equals(hostName)) {
int slashCount = slashCount(path);
synchronized (host) {
Context[] contexts = host.contextList.contexts;
// Update nesting
if (slashCount > host.contextList.nesting) {
host.contextList.nesting = slashCount;
}
Context[] newContexts = new Context[contexts.length + 1];
Context newContext = new Context();
newContext.name = path;
newContext.object = context;
newContext.welcomeResources = welcomeResources;
newContext.resources = resources;
if (insertMap(contexts, newContexts, newContext)) {
host.contextList.contexts = newContexts;
}
}
}
}
创建一个Mapper内部类Context。将StandardContext保存到Context.object属性中,再将Context添加的上级组件Host的ContextList中。
也就是说到组件启动完成后,服务器上的Host、Context、Wrapper对象都会保存到Connector对象的mapper属性中,等待请求。
当收到请求后,会调用Mapper.map()对uri进行解析,匹配出相关的Host、Context、Wrapper对象,放置到请求request的参数中。
还是以Context为例,在Mapper的internalMap方法中:
// Context mapping
if (mappingData.context == null) {
int pos = find(contexts, uri);
if (pos == -1) {
return;
}
int lastSlash = -1;
int uriEnd = uri.getEnd();
int length = -1;
boolean found = false;
while (pos >= 0) {
if (uri.startsWith(contexts[pos].name)) {
length = contexts[pos].name.length();
if (uri.getLength() == length) {
found = true;
break;
} else if (uri.startsWithIgnoreCase("/", length)) {
found = true;
break;
}
}
if (lastSlash == -1) {
lastSlash = nthSlash(uri, nesting + 1);
} else {
lastSlash = lastSlash(uri);
}
uri.setEnd(lastSlash);
pos = find(contexts, uri);
}
uri.setEnd(uriEnd);
if (!found) {
if (contexts[0].name.equals("")) {
context = contexts[0];
}
} else {
context = contexts[pos];
}
if (context != null) {
mappingData.context = context.object;
mappingData.contextPath.setString(context.name);
}
}
将context.object(StandardContext对象)设置到mappingData.context,Mapper.map()执行完后,会将mappingData.context赋值个request.context,CoyoteAdapter.postParseRequest():
request.setContext((Context) request.getMappingData().context);
至此,request已经封装的差不多了,已经知道要交由哪些组件来处理。