In this article, we need to understand a problem. We know that a linker is associated with a container, and when is the container associated with the linker?
Before you understand this problem, you should first understand the Digester library, which simply resolves xml files. There are two concepts: Patterns and rules. The so-called schema is an xml tag, the rule is what an xml tag needs to do. Let's take a look at its three main methods:
1: addObjectCreate (String pattern, String className, String attributeName) instantiate an object className according to pattern
2: addSetProperties (String pattern) sets the attribute of this mode.
3: addSetNext (String pattern, String methodName, String paramType) adds the relationship between the modes and calls
The above may not be easy to understand. Let's see how tomcat uses Digester. apache. catalina. startup. catalina. createStartDigester () method (this method is called when the service component is started. For details, refer to Tomcat source code analysis (1)-Service Startup ), in this method, Digester is used to parse the server. xml file:
[Java]
Digester. addObjectCreate ("Server/Service ",
"Org. apache. catalina. core. StandardService ",
"ClassName"); // Add a mode "Server/Service", when in the xml file (here is the server. xml) when a Service tag under the "Server" label is encountered, an object is instantiated for the class name based on the "className" attribute of the tag Service. The default class name is "org. apache. catalina. core. standardServer"
Digester. addSetProperties ("Server/Service"); // you can specify the properties of the StandardService object.
Digester. addSetNext ("Server/Service ",
"AddService ",
"Org. apache. catalina. service "); // call the addService method of the object (namely, StandardServer) of the Server tag on the Service tag, add the Service to the Server, and set their relationship, the last parameter indicates the parameter type of the addService method.
In this way, the StandardServer and StandardService have a relationship. Now, let's see how the container and the linker are connected. Then, let's look at the createStartDigester method:
[Java]
Digester. addObjectCreate ("Server/Service/Connector ",
"Org. apache. catalina. connector. http. HttpConnector ",
"ClassName ");
Digester. addSetProperties ("Server/Service/Connector ");
Digester. addSetNext ("Server/Service/Connector ",
"AddConnector ",
"Org. apache. catalina. Connector ");
It is easy to understand here. It is the same as above. In the case of the Server/Service/Connector tag (this is simplified here, it should be the sub-tag Connector of the sub-tag Service under the tag Server, A bit of Interface), instantiate HttpConnector, and then call addConnector under its parent container StandardService at the upper level, so that the linker HttpConnector is added to the container StandardService. See the addConnector method of StandardService:
[Java]
Public void addConnector (Connector conne ){
Synchronized (connectors ){
Connector. setContainer (this. container); // the container and connector should have been associated here, but at the beginning of tomcat startup, Digester adds the linker first, so the container is still null, but it doesn't matter. There will be another link to them later. Here we should remember that containers and connectors are both in the Service.
Connector. setService (this );
Connector results [] = new Connector [connectors. length + 1];
System. arraycopy (connectors, 0, results, 0, connectors. length );
Results [connectors. length] = connector;
Connectors = results;
If (initialized ){
Try {
Connector. initialize ();
} Catch (LifecycleException e ){
E. printStackTrace (System. err );
}
}
If (started & (connector instanceof Lifecycle )){
Try {
(Lifecycle) connector). start ();
} Catch (LifecycleException e ){
;
}
}
// Report this property change to interested listeners
Support. firePropertyChange ("connector", null, connector );
}
}
This method is very simple. It is to add a connector to the ORs ors array of StandardService and associate it with the container of StandardService. The Code is also described (very important ). The connector is added to StandardService. Now we can see when the container is added to StandardService. In fact, the method is the same, and then return to the createStartDigester method:
[Java]
Digester. addRuleSet (new EngineRuleSet ("Server/Service/"); // the code is in the createStartDigester method.
Under ------------------------, enter the addRuleInstances method of the EngineRuleSet class.
Public void addRuleInstances (Digester digester ){
Digester. addObjectCreate (prefix + "Engine ",
"Org. apache. catalina. core. StandardEngine ",
"ClassName ");
Digester. addSetProperties (prefix + "Engine ");
Digester. addRule (prefix + "Engine ",
New LifecycleListenerRule
(Digester,
"Org. apache. catalina. startup. EngineConfig ",
"EngineConfigClass "));
Digester. addSetNext (prefix + "Engine ",
"SetContainer ",
"Org. apache. catalina. Container"); // call the setContainer method of StandardService to add the Container to StandardService.
First, let's not worry about how Digester enters the addRuleInstances method. When we call digester. addRuleSet (new EngineRuleSet ("Server/Service/"); method, Digester automatically calls the addRuleInstances method of the EngineRuleSet class, and adds various modes and rules to the method, according to the above rules, it is easy to know that a StandardEngine object (container) is added here, and then the relationship between StandardEngine and StandardService is added to the Server/Service in the upper-level mode of this mode, add the container to StandardService by using the setContainer method. The setContainer method of StandardService is as follows:
[Java]
Public void setContainer (Container container ){
Container oldContainer = this. container;
If (oldContainer! = Null) & (oldContainer instanceof Engine ))
(Engine) oldContainer). setService (null );
This. container = container;
If (this. container! = Null) & (this. container instanceof Engine ))
(Engine) this. container). setService (this );
If (started & (this. container! = Null )&&
(This. container instanceof Lifecycle )){
Try {
(Lifecycle) this. container). start ();
} Catch (LifecycleException e ){
;
}
} // Key point !!!!!!!!
Synchronized (connectors) {// All connectors under StandardService are associated with containers under StandardService, so that the connector is associated with the container.
For (int I = 0; I <connectors. length; I ++)
Connectors [I]. setContainer (this. container );
}
If (started & (oldContainer! = Null )&&
(OldContainer instanceof Lifecycle )){
Try {
(Lifecycle) oldContainer). stop ();
} Catch (LifecycleException e ){
;
}
}
// Report this property change to interested listeners
Support. firePropertyChange ("container", oldContainer, this. container );
}
The above Code makes various judgments, then sets the container to StandardService, and associates the container with the linker at the "synchronous code block". At this point, the container and the linker are associated. Looking back, it is actually very simple. It is to use Digester to read server. xml in the set mode, and then call two key methods setContainer and addConnector to associate the container with the linker. After Association, you can understand the code in the final process method of Tomcat source code analysis (2) -- connection processing: connector. getContainer (). the meaning of invoke (request, response. In the next article, we want to describe what happens after invoke is called.
Author: haitao111313