Struts2源码阅读(三)_Dispatcher&ConfigurationProvider
2010-11-12 00:39
381 查看
首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.
接下来就从Dispatcher开始看起,先看其构造函数:
再看在FilterDispatcher创建Dispatcher的:
创建Dispatcher之后,来看init()方法
init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.
主要分七步走,看下面注释
分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.
将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.
最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.
下面将分析这七层功夫是怎样一步步练成的.
首先是init_DefaultProperties()
再来看第二步:init_TraditionalXmlConfigurations()
对于其它配置文件只用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对象中。
http://qidaoxp.javaeye.com/blog/494444
接下来就从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
相关文章推荐
- Struts2源码阅读(四)_Dispatcher&ConfigurationProvider续
- Struts2源码阅读(三)_Dispatcher&ConfigurationProvider .
- Struts2源码阅读(四)_Dispatcher&ConfigurationProvider续 .
- Struts2源码阅读(二)_Dispatcher&ConfigurationProvider
- Struts2源码阅读(三)_Dispatcher&ConfigurationProvider
- Struts2源码阅读(四)_Dispatcher&ConfigurationProvider续
- Struts2源码阅读(三)_Dispatcher&ConfigurationProvider
- Struts2源码阅读(三)_Dispatcher&ConfigurationProvider
- Struts2源码阅读(五)_FilterDispatcher核心控制器
- Struts2源码阅读(五)_FilterDispatcher核心控制器
- Struts2源码阅读(六)_ActionProxy&ActionInvocation
- Struts2源码阅读(六)_ActionProxy&ActionInvocation
- Struts2源码阅读(六)_ActionProxy&ActionInvocation
- Struts2源码阅读(五)_FilterDispatcher核心控制器 .
- Struts2源码阅读(六)_ActionProxy&ActionInvocation
- Struts2源码阅读(五)_FilterDispatcher核心控制器
- Struts2源码阅读(三)_FilterDispatcher核心控制器
- Struts2源码阅读之Dispatcher
- Struts2源码阅读(五)_FilterDispatcher核心控制器
- Struts2源码阅读(五)_FilterDispatcher核心控制器