- 浏览: 21105 次
- 性别:
- 来自: 上海
最新评论
-
liangfuming:
看了之后受益匪浅
Struts2 -- ActionProxy&ActionInvocation -
nianien:
你好,我怎么找不到哪个地方有写加载struts.propert ...
Struts2--Dispatcher&ConfigurationProvider
首先强调一下struts2的线程程安全,在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.
接下来就从Dispatcher开始看起,先看其构造函数:
- //创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方
- public Dispatcher(ServletContext servletContext, Map<String, String> initParams) {
- this.servletContext = servletContext;
- //配置在web.xml中的param参数
- this.initParams = initParams;
- }
//创建Dispatcher,此类是一个Delegate,它是真正完成根据url解析转向,读取对应Action的地方 public Dispatcher(ServletContext servletContext, Map<String, String> initParams) { this.servletContext = servletContext; //配置在web.xml中的param参数 this.initParams = initParams; }
我们再看在FilterDispatcher创建Dispatcher的:
- protected Dispatcher createDispatcher(FilterConfig filterConfig) {
- Map<String, String> params = new HashMap<String, String>();
- for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) {
- String name = (String) e.nextElement();
- String value = filterConfig.getInitParameter(name);
- params.put(name, value);
- }
- 都可以从FilterConfig中得到
- return new Dispatcher(filterConfig.getServletContext(), params);
- }
protected Dispatcher createDispatcher(FilterConfig filterConfig) { Map<String, String> params = new HashMap<String, String>(); for (Enumeration e = filterConfig.getInitParameterNames(); e.hasMoreElements();) { String name = (String) e.nextElement(); String value = filterConfig.getInitParameter(name); params.put(name, value); } //都可以从FilterConfig中得到 return new Dispatcher(filterConfig.getServletContext(), params); }
创建Dispatcher之后,来看init()方法
init()方法是用来Load用户配置文件,资源文件以及默认的配置文件.
主要分七步走,看下面注释
- public void init() {
- if (configurationManager == null) {
- //设置ConfigurationManager的defaultFrameworkBeanName.
- //这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等
- configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME);
- }
- //读取properties信息,默认的default.properties,
- init_DefaultProperties(); // [1]
- //读取xml配置文件
- init_TraditionalXmlConfigurations(); // [2]
- //读取用户自定义的struts.properties
- init_LegacyStrutsProperties(); // [3]
- //自定义的configProviders
- init_CustomConfigurationProviders(); // [5]
- //载入FilterDispatcher传进来的initParams
- init_FilterInitParameters() ; // [6]
- //将配置文件中的bean与具体的类映射
- init_AliasStandardObjects() ; // [7]
- //构建一个用于依赖注射的Container对象
- //在这里面会循环调用上面七个ConfigurationProvider的register方法
- //其中的重点就是DefaultConfiguration的#reload()方法
- Container container = init_PreloadConfiguration();
- container.inject(this);
- init_CheckConfigurationReloading(container);
- init_CheckWebLogicWorkaround(container);
- if (!dispatcherListeners.isEmpty()) {
- for (DispatcherListener l : dispatcherListeners) {
- l.dispatcherInitialized(this);
- }
- }
- }
public void init() { if (configurationManager == null) { //设置ConfigurationManager的defaultFrameworkBeanName. //这里DEFAULT_BEAN_NAME为struts,这是xwork框架的内容,Framework可以是xwork,struts,webwork等 configurationManager = new ConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME); } //读取properties信息,默认的default.properties, init_DefaultProperties(); // [1] //读取xml配置文件 init_TraditionalXmlConfigurations(); // [2] //读取用户自定义的struts.properties init_LegacyStrutsProperties(); // [3] //自定义的configProviders init_CustomConfigurationProviders(); // [5] //载入FilterDispatcher传进来的initParams init_FilterInitParameters() ; // [6] //将配置文件中的bean与具体的类映射 init_AliasStandardObjects() ; // [7] //构建一个用于依赖注射的Container对象 //在这里面会循环调用上面七个ConfigurationProvider的register方法 //其中的重点就是DefaultConfiguration的#reload()方法 Container container = init_PreloadConfiguration(); container.inject(this); init_CheckConfigurationReloading(container); init_CheckWebLogicWorkaround(container); if (!dispatcherListeners.isEmpty()) { for (DispatcherListener l : dispatcherListeners) { l.dispatcherInitialized(this); } } }
分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法.
将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面.
最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能.
下面将分析这七层功夫是怎样一步步练成的.
首先是init_DefaultProperties()
- private void init_DefaultProperties() {
- configurationManager.addConfigurationProvider(new DefaultPropertiesProvider());
- }
- 接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法
- public void register(ContainerBuilder builder, LocatableProperties props)
- throws ConfigurationException {
- Settings defaultSettings = null;
- try {
- defaultSettings = new PropertiesSettings("org/apache/struts2/default");
- } catch (Exception e) {
- throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e);
- }
- loadSettings(props, defaultSettings);
- }
private void init_DefaultProperties() { configurationManager.addConfigurationProvider(new DefaultPropertiesProvider()); } //直接来看DefaultPropertiesProvider好了,DefaultPropertiesProvider实际上只是实现了register()方法 public void register(ContainerBuilder builder, LocatableProperties props) throws ConfigurationException { Settings defaultSettings = null; try { defaultSettings = new PropertiesSettings("org/apache/struts2/default"); } catch (Exception e) { throw new ConfigurationException("Could not find or error in org/apache/struts2/default.properties", e); } loadSettings(props, defaultSettings); }
- //PropertiesSettings构造方法
- //读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写
- public PropertiesSettings(String name) {
- URL settingsUrl = ClassLoaderUtils.getResource(name + ".properties", getClass());
- if (settingsUrl == null) {
- LOG.debug(name + ".properties missing");
- settings = new LocatableProperties();
- return;
- }
- settings = new LocatableProperties(new LocationImpl(null, settingsUrl.toString()));
- // Load settings
- InputStream in = null;
- try {
- in = settingsUrl.openStream();
- settings.load(in);
- } catch (IOException e) {
- throw new StrutsException("Could not load " + name + ".properties:" + e, e);
- } finally {
- if(in != null) {
- try {
- in.close();
- } catch(IOException io) {
- LOG.warn("Unable to close input stream", io);
- }
- }
- }
- }
- //loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props
- //这个props是register的一个入参.
- protected void loadSettings(LocatableProperties props, final Settings settings) {
- // We are calling the impl methods to get around the single instance of Settings that is expected
- for (Iterator i = settings.listImpl(); i.hasNext(); ) {
- String name = (String) i.next();
- props.setProperty(name, settings.getImpl(name), settings.getLocationImpl(name));
- }
- }
//PropertiesSettings构造方法 //读取org/apache/struts2/default.properties的配置信息,如果项目中需要覆盖,可以在classpath里的struts.properties里覆写 public PropertiesSettings(String name) { URL settingsUrl = ClassLoaderUtils.getResource(name + ".properties", getClass()); if (settingsUrl == null) { LOG.debug(name + ".properties missing"); settings = new LocatableProperties(); return; } settings = new LocatableProperties(new LocationImpl(null, settingsUrl.toString())); // Load settings InputStream in = null; try { in = settingsUrl.openStream(); settings.load(in); } catch (IOException e) { throw new StrutsException("Could not load " + name + ".properties:" + e, e); } finally { if(in != null) { try { in.close(); } catch(IOException io) { LOG.warn("Unable to close input stream", io); } } } } //loadSettings主要是将progerty的value和Locale从上面PropertiesSettings中取得并存放到LocatableProperties props //这个props是register的一个入参. protected void loadSettings(LocatableProperties props, final Settings settings) { // We are calling the impl methods to get around the single instance of Settings that is expected for (Iterator i = settings.listImpl(); i.hasNext(); ) { String name = (String) i.next(); props.setProperty(name, settings.getImpl(name), settings.getLocationImpl(name)); } }
再来看第二步:init_TraditionalXmlConfigurations()
- private void init_TraditionalXmlConfigurations() {
- //首先读取web.xml中的config初始参数值
- //如果没有配置就使用默认的DEFAULT_CONFIGURATION_PATHS:"struts-default.xml,struts-plugin.xml,struts.xml",
- //这儿就可以看出为什么默认的配置文件必须取名为这三个名称了
- //如果不想使用默认的名称,直接在web.xml中配置config初始参数即可
- String configPaths = initParams.get("config");
- if (configPaths == null) {
- configPaths = DEFAULT_CONFIGURATION_PATHS;
- }
- String[] files = configPaths.split("\\s*[,]\\s*");
- for (String file : files) {
- if (file.endsWith(".xml")) {
- if ("xwork.xml".equals(file)) {
- //XmlConfigurationProvider负责解析xwork.xml
- configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false));
- } else {
- //其它xml都是由StrutsXmlConfigurationProvider来解析
- configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext));
- }
- } else {
- throw new IllegalArgumentException("Invalid configuration file name");
- }
- }
- }
private void init_TraditionalXmlConfigurations() { //首先读取web.xml中的config初始参数值 //如果没有配置就使用默认的DEFAULT_CONFIGURATION_PATHS:"struts-default.xml,struts-plugin.xml,struts.xml", //这儿就可以看出为什么默认的配置文件必须取名为这三个名称了 //如果不想使用默认的名称,直接在web.xml中配置config初始参数即可 String configPaths = initParams.get("config"); if (configPaths == null) { configPaths = DEFAULT_CONFIGURATION_PATHS; } String[] files = configPaths.split("\\s*[,]\\s*"); for (String file : files) { if (file.endsWith(".xml")) { if ("xwork.xml".equals(file)) { //XmlConfigurationProvider负责解析xwork.xml configurationManager.addConfigurationProvider(new XmlConfigurationProvider(file, false)); } else { //其它xml都是由StrutsXmlConfigurationProvider来解析 configurationManager.addConfigurationProvider(new StrutsXmlConfigurationProvider(file, false, servletContext)); } } else { throw new IllegalArgumentException("Invalid configuration file name"); } } }
对于其它配置文件只用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对象中。
- protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {
- PackageConfig.Builder newPackage = buildPackageContext(packageElement);
- if (newPackage.isNeedsRefresh()) {
- return newPackage.build();
- }
- // add result types (and default result) to this package
- addResultTypes(newPackage, packageElement);
- // load the interceptors and interceptor stacks for this package
- loadInterceptors(newPackage, packageElement);
- // load the default interceptor reference for this package
- loadDefaultInterceptorRef(newPackage, packageElement);
- // load the default class ref for this package
- loadDefaultClassRef(newPackage, packageElement);
- // load the global result list for this package
- loadGlobalResults(newPackage, packageElement);
- // load the global exception handler list for this package
- loadGobalExceptionMappings(newPackage, packageElement);
- // get actions
- NodeList actionList = packageElement.getElementsByTagName("action");
- for (int i = 0; i < actionList.getLength(); i++) {
- Element actionElement = (Element) actionList.item(i);
- addAction(actionElement, newPackage);
- }
- // load the default action reference for this package
- loadDefaultActionRef(newPackage, packageElement);
- PackageConfig cfg = newPackage.build();
- configuration.addPackageConfig(cfg.getName(), cfg);
- return cfg;
- }
- loadConfigurationFiles解析读取xml中的内容
- private List<Document> loadConfigurationFiles(String fileName, Element includeElement) {
- ...
- //通过DomHelper调用SAX进行解析xml
- doc = DomHelper.parse(in, dtdMappings);
- ...
- Element rootElement = doc.getDocumentElement();
- NodeList children = rootElement.getChildNodes();
- int childSize = children.getLength();
- for (int i = 0; i < childSize; i++) {
- Node childNode = children.item(i);
- if (childNode instanceof Element) {
- Element child = (Element) childNode;
- final String nodeName = child.getNodeName();
- if ("include".equals(nodeName)) {
- String includeFileName = child.getAttribute("file");
- //解析每个action配置是,对于include文件可以使用通配符*来进行配置
- //如Struts.xml中可配置成<include file="actions_*.xml"/>
- if (includeFileName.indexOf('*') != -1) {
- ClassPathFinder wildcardFinder = new ClassPathFinder();
- wildcardFinder.setPattern(includeFileName);
- Vector<String> wildcardMatches = wildcardFinder.findMatches();
- for (String match : wildcardMatches) {
- //递归Load子file中的<include/>
- docs.addAll(loadConfigurationFiles(match, child));
- }
- } else {
- docs.addAll(loadConfigurationFiles(includeFileName, child));
- }
- }
- }
- }
- docs.add(doc);
- loadedFileUrls.add(url.toString());
- ...
- return docs;
- }
protected PackageConfig addPackage(Element packageElement) throws ConfigurationException { PackageConfig.Builder newPackage = buildPackageContext(packageElement); if (newPackage.isNeedsRefresh()) { return newPackage.build(); } // add result types (and default result) to this package addResultTypes(newPackage, packageElement); // load the interceptors and interceptor stacks for this package loadInterceptors(newPackage, packageElement); // load the default interceptor reference for this package loadDefaultInterceptorRef(newPackage, packageElement); // load the default class ref for this package loadDefaultClassRef(newPackage, packageElement); // load the global result list for this package loadGlobalResults(newPackage, packageElement); // load the global exception handler list for this package loadGobalExceptionMappings(newPackage, packageElement); // get actions NodeList actionList = packageElement.getElementsByTagName("action"); for (int i = 0; i < actionList.getLength(); i++) { Element actionElement = (Element) actionList.item(i); addAction(actionElement, newPackage); } // load the default action reference for this package loadDefaultActionRef(newPackage, packageElement); PackageConfig cfg = newPackage.build(); configuration.addPackageConfig(cfg.getName(), cfg); return cfg; } //loadConfigurationFiles解析读取xml中的内容 private List<Document> loadConfigurationFiles(String fileName, Element includeElement) { ... //通过DomHelper调用SAX进行解析xml doc = DomHelper.parse(in, dtdMappings); ... Element rootElement = doc.getDocumentElement(); NodeList children = rootElement.getChildNodes(); int childSize = children.getLength(); for (int i = 0; i < childSize; i++) { Node childNode = children.item(i); if (childNode instanceof Element) { Element child = (Element) childNode; final String nodeName = child.getNodeName(); if ("include".equals(nodeName)) { String includeFileName = child.getAttribute("file"); //解析每个action配置是,对于include文件可以使用通配符*来进行配置 //如Struts.xml中可配置成<include file="actions_*.xml"/> if (includeFileName.indexOf('*') != -1) { ClassPathFinder wildcardFinder = new ClassPathFinder(); wildcardFinder.setPattern(includeFileName); Vector<String> wildcardMatches = wildcardFinder.findMatches(); for (String match : wildcardMatches) { //递归Load子file中的<include/> docs.addAll(loadConfigurationFiles(match, child)); } } else { docs.addAll(loadConfigurationFiles(includeFileName, child)); } } } } docs.add(doc); loadedFileUrls.add(url.toString()); ... return docs; }
发表评论
-
Struts2--ActionContext及CleanUP Filter
2010-10-26 16:41 16261. ActionContext ActionCont ... -
Struts2--Dispatcher&ConfigurationProvider续
2010-10-26 16:36 1183接下来第三步:init_LegacyStrutsPrope ... -
Struts2 --FilterDispatcher核心控制器
2010-10-26 16:34 1749Dispatcher已经在之前讲过,这就好办了。Filte ... -
Struts2 -- ActionProxy&ActionInvocation
2010-10-26 16:11 1223下面开始讲一下主菜ActionProxy了.在这之前最好先去了 ... -
Struts2 --拦截器&工作流程概述
2010-10-24 01:00 2065记得一次面试当面试 ...
相关推荐
<bean type="org.apache.struts2.dispatcher.mapper.ActionMapper" name="myDefaultActionMapper" class="com.struts2.MyDefaultActionMapper" /> <constant name="struts.mapper.class" value=...
8. **请求处理(Request Handling)**:`org.apache.struts2.dispatcher.ng.filter`包中的`StrutsPrepareAndExecuteFilter`是Struts2与Servlet容器交互的关键,它负责准备请求并执行Action。 9. **类型转换(Type ...
plexus-sec-dispatcher-1.3.jar
3. 解压找到位置 org/apache/struts2/dispatcher/multipart:然后,我们需要解压源码包,找到 org/apache/struts2/dispatcher/multipart 目录。 4. 复制文件 JakartaMultiPartRequest.java、...
Struts2是一个基于MVC(Model-View-Controller)设计模式的Java web应用程序框架,它在Java社区中广泛使用,特别是在开发企业级应用时。"struts2-blank"项目是一个基础的Struts2示例代码,可以帮助初学者快速理解和...
4. **结果类型**:Struts 2支持多种结果类型,如dispatcher(默认的JSP渲染),stream(处理文件下载),redirect(重定向URL)等,这些结果类型在Action配置中定义。 5. **标签库**:Struts 2提供了一系列的标签库...
2. **Filter Dispatcher**:Struts2的核心是Filter Dispatcher,它是一个Servlet过滤器,负责拦截所有到达应用的HTTP请求。过滤器会根据配置决定是否将请求转发给Struts2框架处理,从而实现请求的分发。 3. **...
505) at org.apache.struts2.dispatcher.FilterDispatcher.doFilter(FilterDispatcher.java:395) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org....
org.apache.struts2.dispatcher.filter.StrutsPrepareAndExecuteFilter </filter-class> <filter-mapping> <!-- 拦截所有的url --> <filter-name>struts2</filter-name> <url-pattern>/*</url-...
1. **struts2-core.jar** - 包含Struts2框架的核心组件,如ActionContext、ActionProxy、Dispatcher等。 2. **struts2-convention-plugin.jar** - 提供了约定优于配置的特性,允许根据类名和方法名自动映射Action。 ...
<filter-class>org.apache.struts2.dispatcher.FilterDispatcher</filter-class> <init-param> <param-name>actionPackages</param-name> <param-value>com.action</param-value> </init-param> <filter-...
此外,Struts2还支持多种结果类型(Results),如dispatcher(默认的JSP渲染)、stream(用于文件下载)等。配置文件通常位于`struts.xml`或`struts-default.xml`中,定义了Action、结果类型、拦截器栈等。 总的来...
再者,Struts2的Result类型允许开发者定义不同类型的响应,如dispatcher(重定向或转发到一个JSP页面)、stream(处理文件下载)和freemarker(使用FreeMarker模板引擎)。2.3版本进一步增强了对这些Result类型的...
Struts2布局(Struts2-layout)是Apache Struts2框架的一个扩展,它提供了一种在Web应用中统一页面布局的方法。Struts2是Java Web开发中的一个流行MVC(模型-视图-控制器)框架,它简化了业务逻辑与表现层的分离,而...
2. **Dispatcher Servlet**: Struts2的核心控制器,负责接收HTTP请求,根据配置文件选择合适的Action执行,并将响应返回给客户端。 3. **Interceptor**: 拦截器是Struts2的一个重要特性,它允许在Action执行前后...
2. 配置web.xml:在Servlet容器的配置文件中,设置过滤器(`org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter`)以启用Struts2。 3. 创建Action类:继承自Struts2的Action接口或...
Struts2是一个强大的Java EE(Enterprise Edition)框架,主要用于构建基于MVC(Model-View-Controller)模式的Web应用程序。它的核心是Action类,通过它实现了业务逻辑与表现层的分离,增强了应用的可维护性和扩展...
Struts2-057 EXP 是一个针对Apache Struts2框架的严重远程代码执行(RCE)漏洞,其CVE编号为CVE-2018-11776。这个漏洞影响了Struts2的多个版本,使得攻击者能够通过精心构造的HTTP请求在服务器端执行任意代码,从而...
7. **结果类型**:Struts2支持多种结果类型,如dispatcher(用于转发到JSP页面)、stream(用于文件下载)等。 8. **异常处理**:通过全局异常映射,Struts2可以统一处理应用程序中的异常,提供一致的错误页面。 9...
1. **Action与Dispatcher**:在Struts2中,Action类是业务逻辑处理的主要载体。用户请求首先会被Struts2的前端控制器(DispatcherServlet)捕获,然后根据配置文件(struts.xml)中的映射信息,将请求分发到相应的...