您的位置:首页 > 编程语言 > Java开发

Struts2源码阅读(三)_Dispatcher&ConfigurationProvider

2010-11-12 00:39 381 查看
首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.

接下来就从Dispatcher开始看起,先看其构造函数:

1. //创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方
2.     public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
3.         this.servletContext = servletContext;
4.         //配置在web.xml中的param参数
5.         this.initParams = initParams;
6.     }


再看在FilterDispatcher创建Dispatcher的:

1. protected Dispatcher createDispatcher(FilterConfig filterConfig) {
2.     Map<String, String> params = new HashMap<String, String>();
3.     for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) {
4.         String name = (String) e.nextElement();
5.         String value = filterConfig.getInitParameter(name);
6.         params.put(name, value);
7.     }
8. 都可以从FilterConfig中得到
9.     return new Dispatcher(filterConfig.getServletContext(), params);
10. }


创建Dispatcher之后,来看init()方法

init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.

主要分七步走,看下面注释

1.   public void init() {
2.
3.     if (configurationManager == null) {
4.     //设置ConfigurationManager的defaultFrameworkBeanName.
5.     //这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等
6.         configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
7.     }
8.       //读取properties信息,默认的default.properties,
9.     init_DefaultProperties(); // [1]
10. //读取xml配置文件
11.       init_TraditionalXmlConfigurations(); // [2]
12. //读取用户自定义的struts.properties
13.       init_LegacyStrutsProperties(); // [3]
14. //自定义的configProviders
15.       init_CustomConfigurationProviders(); // [5]
16. //载入FilterDispatcher传进来的initParams
17.       init_FilterInitParameters() ; // [6]
18. //将配置文件中的bean与具体的类映射
19.       init_AliasStandardObjects() ; // [7]
20.
21. //构建一个用于依赖注射的Container对象
22. //在这里面会循环调用上面七个ConfigurationProvider的register方法
23. //其中的重点就是DefaultConfiguration的#reload()方法
24.       Container container = init_PreloadConfiguration();
25.       container.inject(this);
26.       init_CheckConfigurationReloading(container);
27.       init_CheckWebLogicWorkaround(container);
28.
29.       if (!dispatcherListeners.isEmpty()) {
30.           for (DispatcherListener l : dispatcherListeners) {
31.               l.dispatcherInitialized(this);
32.           }
33.       }
34.   }


分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.

将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.

最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.

下面将分析这七层功夫是怎样一步步练成的.

首先是init_DefaultProperties()

1. private void init_DefaultProperties() {
2.     configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
3. }
4. 接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法
5. public void register(ContainerBuilder builder, LocatableProperties props)
6.         throws ConfigurationException {
7.
8.     Settings defaultSettings = null;
9.     try {
10.         defaultSettings = new PropertiesSettings("org/apache/struts2/default");
11.     } catch (Exception e) {
12.         throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e);
13.     }
14.
15.     loadSettings(props, defaultSettings);
16. }


1. //PropertiesSettings构造方法
2.     //读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写
3.     public PropertiesSettings(String name) {
4.
5.         URL settingsUrl = ClassLoaderUtils.getResource(name + ".properties", getClass());
6.
7.         if (settingsUrl == null) {
8.             LOG.debug(name + ".properties missing");
9.             settings = new LocatableProperties();
10.             return;
11.         }
12.
13.         settings = new LocatableProperties(new LocationImpl(null, settingsUrl.toString()));
14.
15.         // Load settings
16.         InputStream in = null;
17.         try {
18.             in = settingsUrl.openStream();
19.             settings.load(in);
20.         } catch (IOException e) {
21.             throw new StrutsException("Could not load " + name + ".properties:" + e, e);
22.         } finally {
23.             if(in != null) {
24.                 try {
25.                     in.close();
26.                 } catch(IOException io) {
27.                     LOG.warn("Unable to close input stream", io);
28.                 }
29.             }
30.         }
31.     }
32.
33.     //loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props
34.     //这个props是register的一个入参.
35.     protected void loadSettings(LocatableProperties props, final Settings settings) {
36.         // We are calling the impl methods to get around the single instance of Settings that is expected
37.         for (Iterator i = settings.listImpl(); i.hasNext(); ) {
38.             String name = (String) i.next();
39.             props.setProperty(name, settings.getImpl(name), settings.getLocationImpl(name));
40.         }
41.     }


再来看第二步:init_TraditionalXmlConfigurations()

1. private void init_TraditionalXmlConfigurations() {
2.  //首先读取web.xml中的config初始参数值
3.     //如果没有配置就使用默认的DEFAULT_CONFIGURATION_PATHS:"struts-default.xml,struts-plugin.xml,struts.xml",
4.     //这儿就可以看出为什么默认的配置文件必须取名为这三个名称了
5.     //如果不想使用默认的名称,直接在web.xml中配置config初始参数即可
6.     String configPaths = initParams.get("config");
7.     if (configPaths == null) {
8.         configPaths = DEFAULT_CONFIGURATION_PATHS;
9.     }
10.     String[] files = configPaths.split("//s*[,]//s*");
11.     for (String file : files) {
12.         if (file.endsWith(".xml")) {
13.             if ("xwork.xml".equals(file)) {
14.     //XmlConfigurationProvider负责解析xwork.xml
15.                 configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));
16.             } else {
17.     //其它xml都是由StrutsXmlConfigurationProvider来解析
18.                 configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));
19.             }
20.         } else {
21.             throw new IllegalArgumentException("Invalid configuration file name");
22.         }
23.     }
24. }


对于其它配置文件只用StrutsXmlConfigurationProvider,此类继承XmlConfigurationProvider,而XmlConfigurationProvider又实现ConfigurationProvider接口。

类XmlConfigurationProvider负责配置文件的读取和解析,

首先通过init()中的loadDocuments(configFileName);利用DomHelper中的

public
static Document parse(InputSource inputSource, Map<String,
String> dtdMappings)
将configFileName配置文件通过SAX解析方式按照DtdMappings解析成Document对象.

然后通过Provider的register()方法加载"bean"和"constant"属性,再通过loadPackages()加载package及package中的属性

addAction()方法负责读取<action>标签,并将数据保存在ActionConfig中;

addResultTypes()方法负责将<result-type>标签转化为ResultTypeConfig对象;

loadInterceptors()方法负责将<interceptor>标签转化为InterceptorConfi对象;

loadInterceptorStack()方法负责将<interceptor-ref>标签转化为InterceptorStackConfig对象;

loadInterceptorStacks()方法负责将<interceptor-stack>标签转化成InterceptorStackConfig对象。

而上面的方法最终会被addPackage()方法调用,addPackage又会被Provider的loadPackages()调用,将所读取到的数据汇集到PackageConfig对象中。

1.  protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {
2.      PackageConfig.Builder newPackage = buildPackageContext(packageElement);
3.
4.      if (newPackage.isNeedsRefresh()) {
5.          return newPackage.build();
6.      }
7.      // add result types (and default result) to this package
8.      addResultTypes(newPackage, packageElement);
9.      // load the interceptors and interceptor stacks for this package
10.      loadInterceptors(newPackage, packageElement);
11.      // load the default interceptor reference for this package
12.      loadDefaultInterceptorRef(newPackage, packageElement);
13.      // load the default class ref for this package
14.      loadDefaultClassRef(newPackage, packageElement);
15.      // load the global result list for this package
16.      loadGlobalResults(newPackage, packageElement);
17.      // load the global exception handler list for this package
18.      loadGobalExceptionMappings(newPackage, packageElement);
19.      // get actions
20.      NodeList actionList = packageElement.getElementsByTagName("action");
21.      for (int i = 0; i < actionList.getLength(); i++) {
22.          Element actionElement = (Element) actionList.item(i);
23.          addAction(actionElement, newPackage);
24.      }
25.      // load the default action reference for this package
26.      loadDefaultActionRef(newPackage, packageElement);
27.      PackageConfig cfg = newPackage.build();
28.      configuration.addPackageConfig(cfg.getName(), cfg);
29.      return cfg;
30.  }
31.
32. loadConfigurationFiles解析读取xml中的内容
33.  private List<Document> loadConfigurationFiles(String fileName, Element includeElement) {
34.    ...
35. //通过DomHelper调用SAX进行解析xml
36. doc = DomHelper.parse(in, dtdMappings);
37. ...
38.    Element rootElement = doc.getDocumentElement();
39.    NodeList children = rootElement.getChildNodes();
40.    int childSize = children.getLength();
41.
42.    for (int i = 0; i < childSize; i++) {
43.      Node childNode = children.item(i);
44.
45.      if (childNode instanceof Element) {
46.        Element child = (Element) childNode;
47.
48.        final String nodeName = child.getNodeName();
49.
50.        if ("include".equals(nodeName)) {
51.          String includeFileName = child.getAttribute("file");
52.
53.       //解析每个action配置是,对于include文件可以使用通配符*来进行配置
54.          //如Struts.xml中可配置成<include file="actions_*.xml"/>
55.          if (includeFileName.indexOf('*') != -1) {
56.            ClassPathFinder wildcardFinder = new ClassPathFinder();
57.            wildcardFinder.setPattern(includeFileName);
58.            Vector<String> wildcardMatches = wildcardFinder.findMatches();
59.            for (String match : wildcardMatches) {
60.        //递归Load子file中的<include/>
61.              docs.addAll(loadConfigurationFiles(match, child));
62.            }
63.          } else {
64.
65.            docs.addAll(loadConfigurationFiles(includeFileName, child));
66.          }
67.        }
68.      }
69.    }
70.    docs.add(doc);
71.    loadedFileUrls.add(url.toString());
72.    ...
73.    return docs;
74.  }


http://qidaoxp.javaeye.com/blog/494444
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: