First, emphasize the thread safety of struts2. In struts2, a large number of threadlocal thread local variables are used to ensure thread security. For example, dispatcher stores variable values through threadlocal, each thread has its own instance variables, which are irrelevant to each other.
Next we will start with dispatcher and look at its constructor first:
// Create a dispatcher. This class is a delegate that truly completes the redirection Based on URL parsing and reads the corresponding action. <br/> Public DISPATCHER (servletcontext, Map <string, string> initparams) {<br/> This. servletcontext = servletcontext; <br/> // configure it on the web. param parameter in XML <br/> This. initparams = initparams; <br/>}
Let's look at how to create a dispatcher in filterdispatcher:
Protected dispatcher createdispatcher (filterconfig) {<br/> Map <string, string> Params = new hashmap <string, string> (); <br/> for (enumeration E = filterconfig. getinitparameternames (); E. hasmoreelements ();) {<br/> string name = (string) E. nextelement (); <br/> string value = filterconfig. getinitparameter (name); <br/> Params. put (name, value); <br/>}< br/> You can obtain <br/> return New DISPATCHER (filterconfig. getservletcontext (), Params); <br/>}
The configuration attributes are loaded in seven steps through the configurationprovider interface. This interface provides methods such as Init (), destroy (), and register.
Initialize various configurationproviders and add the instances to the configurationmanager list.
Finally, we call the destroy () and register () methods in the list cyclically to register and destroy the properties of the configuration file.
Next we will analyze how these seven layers of effort are developed step by step.
First, init_defaultproperties ()
After the dispatcher is created, check the init () method.
The init () method is used to load user configuration files, resource files, and default configuration files.
The main steps are as follows:
Public void Init () {</P> <p> If (configurationmanager = NULL) {<br/> // set the ultframeframeworkbeanname of the configurationmanager. <br/> // here struts ult_bean_name is struts, which is the content of the xwork framework. The framework can be xwork, struts, webwork, etc. <br/> configurationmanager = new configurationmanager (beanselectionprovider. default_bean_name); <br/>}< br/> // read the properties information, default. properties, <br/> init_defaultproperties (); // [1] <br/> // read Obtain the xml configuration file <br/> init_traditionalxmlconfigurations (); // [2] <br/> // read the custom struts. properties <br/> init_legacystrutsproperties (); // [3] <br/> // custom configproviders <br/> init_customconfigurationproviders (); // [5] <br/> // load the initparams passed in by filterdispatcher <br/> init_filterinitparameters (); // [6] <br/> // map the bean in the configuration file to a specific class <br/> init_aliasstandardobjects (); // [7] </P> <p> // construct a iner object for dependent injection. <br // The above seven configurationprovider register methods will be called cyclically <br/> // The focus is the defaultconfiguration # reload () method <br/> Container = init_preloadconfiguration (); <br/> container. inject (this); <br/> init_checkconfigurationreloading (container); <br/> init_checkweblogicworkaround (container); </P> <p> If (! Dispatcherlisteners. isempty () {<br/> for (dispatcherlistener L: dispatcherlisteners) {<br/> L. dispatcherinitialized (this); <br/>}< br/>}
The configuration attributes are loaded in seven steps through the configurationprovider interface. This interface provides methods such as Init (), destroy (), and register.
Initialize various configurationproviders and add the instances to the configurationmanager list.
Finally, we call the destroy () and register () methods in the list cyclically to register and destroy the properties of the configuration file.
Next we will analyze how these seven layers of effort are developed step by step.
First, init_defaultproperties ()
Private void init_defaultproperties () {<br/> configurationmanager. addconfigurationprovider (New defaproperpropertiesprovider (); <br/>}< br/> now, properpropertiesprovider is ready. defaproperpropertiesprovider actually only implements register () method <br/> Public void register (containerbuilder builder, locatableproperties props) <br/> throws configurationexception {</P> <p> Settings defaultsettings = NULL; <br/> try {<br/> defaultsettings = new propertiessettings ("org/Apache/struts2/Default"); <br/>} catch (exception E) {<br/> throw new configurationexception ("cocould not find or error in org/Apache/struts2/default. properties ", e); <br/>}</P> <p> loadsettings (props, defaultsettings); <br/>}< br/>
// Propertiessettings construction method <br/> // read ORG/Apache/struts2/default. properties configuration information. If the project needs to be overwritten, you can use struts in classpath. <br/> Public propertiessettings (string name) {</P> <p> URL settingsurl = classloaderutils. getresource (name + ". properties ", getclass (); </P> <p> If (settingsurl = NULL) {<br/> log. debug (name + ". properties missing "); <br/> Settings = new locatableproperties (); <br/> return; <B R/>}</P> <p> Settings = new locatableproperties (New locationimpl (null, settingsurl. tostring (); </P> <p> // load Settings <br/> inputstream in = NULL; <br/> try {<br/> In = settingsurl. openstream (); <br/> Settings. load (in); <br/>}catch (ioexception e) {<br/> throw new strutsexception ("cocould not load" + name + ". properties: "+ E, E); <br/>}finally {<br/> If (in! = NULL) {<br/> try {<br/> in. close (); <br/>}catch (ioexception Io) {<br/> log. warn ("unable to close input stream", Io ); <br/>}</P> <p> // loadsettings mainly extracts the value and locale of progerty from the above propertiessettings is obtained and stored in locatableproperties props <br/> // This props is an input parameter of register. <br/> protected void loadsettings (locatableproperties props, final settings) {<br/> // we are calling the impl methods to get around the single instance of settings that is expected <br/> for (iterator I = settings. listimpl (); I. hasnext ();) {<br/> string name = (string) I. next (); <br/> props. setproperty (name, settings. getimpl (name), settings. getlocationimpl (name); <br/>}< br/>}
Next, let's take a look at Step 2: init_traditionalxmlconfigurations ()
Private void init_traditionalxmlconfigurations () {<br/> // read the Web first. config initial parameter value in XML <br/> // use the default default_configuration_paths: "struts-default.xml, struts-plugin.xml, struts. XML ", <br/> // you can see why the default configuration file must be named <br/> // if you do not want to use the default name, directly on the web. configure the config initial parameters in XML. <br/> string configpaths = initparams. get ("Config"); <br/> If (configpaths = NULL) {<br/> configpaths = default_configuration_paths; <br/>}< br/> string [] files = configpaths. split ("// s * [,] // s *"); <br/> for (string file: Files) {<br/> If (file. endswith (". XML ") {<br/> If (" xwork. XML ". equals (File) {<br/> // xmlconfigurationprovider is responsible for parsing xwork. XML <br/> configurationmanager. addconfigurationprovider (New xmlconfigurationprovider (file, false); <br/>}else {<br/> // other XML files are parsed by strutsxmlconfigurationprovider. <br/> configurationmanager. addconfigurationprovider (New strutsxmlconfigurationprovider (file, false, servletcontext )); <br/>}< br/>}else {<br/> throw new illegalargumentexception ("invalid configuration file name "); <br/>}< br/>
Only use strutsxmlconfigurationprovider for other configuration files. This class inherits xmlconfigurationprovider, and xmlconfigurationprovider implements the configurationprovider interface.
Xmlconfigurationprovider is responsible for reading and parsing configuration files,
First, use loaddocuments (configfilename) in Init ();
Public static document parse (inputsource, Map <string, string> dtdmappings) parses the configfilename configuration file into a document object according to dtdmappings through the sax parsing method.
Then, load the "Bean" and "constant" attributes using the Register () method of the provider, and then load the attributes in the package and package through loadpackages ().
The addaction () method reads the <action> tag and stores the data in actionconfig;
The addresulttypes () method converts the <result-type> label into a resulttypeconfig object;
The loadinterceptors () method converts the <interceptor> label to an interceptorconfi object;
The loadinterceptorstack () method converts the <Interceptor-ref> label into an interceptorstackconfig object;
The loadinterceptorstacks () method converts the <Interceptor-stack> label into an interceptorstackconfig object.
The above method will eventually be called by the addpackage () method, and the addpackage will be called by the loadpackages () of the provider to collect the read data into the packageconfig object.
Protected packageconfig addpackage (element packageelement) throws configurationexception {<br/> packageconfig. builder newpackage = buildpackagecontext (packageelement); </P> <p> If (newpackage. isneedsrefresh () {<br/> return newpackage. build (); <br/>}< br/> // Add result types (and default result) to this package <br/> addresulttypes (newpackage, packageelement ); <br/> // load the interceptors and Interceptor stacks for this package <br/> loadinterceptors (newpackage, packageelement); <br/> // load the default interceptor reference for this package <br/> loaddefainterinterceptorref (newpackage, packageelement); <br/> // load the default class ref for this package <br/> loaddefaclasclassref (newpackage, packageelement ); <br/> // load the global result list for this package <br/> loadglobalresults (Newpackage, packageelement); <br/> // load the global exception handler list for this package <br/> loadgobalexceptionmappings (newpackage, packageelement ); <br/> // get actions <br/> nodelist actionlist = packageelement. getelementsbytagname ("action"); <br/> for (INT I = 0; I <actionlist. getlength (); I ++) {<br/> element actionelement = (element) actionlist. item (I); <br/> addaction (actionelement, Newpackage); <br/>}< br/> // load the default action reference for this package <br/> loaddefaactionactionref (newpackage, packageelement ); <br/> packageconfig CFG = newpackage. build (); <br/> configuration. addpackageconfig (CFG. getname (), CFG); <br/> return CFG; <br/>}</P> <p> loadconfigurationfiles parse and read the content in XML <br/> private list <document> loadconfigurationfiles (string filename, element includeelement) {<Br/>... <br/> // use domhelper to call Sax for XML parsing <br/> Doc = domhelper. parse (in, dtdmappings); <br/>... <br/> element rootelement = Doc. getdocumentelement (); <br/> nodelist children = rootelement. getchildnodes (); <br/> int childsize = children. getlength (); </P> <p> for (INT I = 0; I <childsize; I ++) {<br/> node childnode = children. item (I); </P> <p> If (childnode instanceof element) {<br/> element chil D = (element) childnode; </P> <p> final string nodename = child. getnodename (); </P> <p> If ("include ". equals (nodename) {<br/> string includefilename = child. getattribute ("file"); </P> <p> // parse the configuration of each action, you can use the wildcard * to configure the include file <br/> // such as struts. <include file = "actions _*. XML "/> <br/> If (includefilename. indexof ('*')! =-1) {<br/> classpathfinder wildcardfinder = new classpathfinder (); <br/> wildcardfinder. setpattern (includefilename); <br/> vector <string> wildcardmatches = wildcardfinder. findmatches (); <br/> for (String Match: wildcardmatches) {<br/> // recursively load <include/> <br/> docs. addall (loadconfigurationfiles (match, child); <br/>}< br/>} else {</P> <p> docs. addall (loadconfigurationfiles (includefilename, child); <br/>}< br/> docs. add (DOC); <br/> loadedfileurls. add (URL. tostring (); <br/>... <br/> return docs; <br/>}< br/>
Come from: http://qidaoxp.javaeye.com/blog/494444