微信平台与微网站开发,商丘网站推广公司,公司搜索seo哪家好,绵阳哪里可以做网站的地方首先强调一下struts2的线程程安全#xff0c;在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.
接下来就从Dispatcher开始看起#xff0c;先看其构造函数在Struts2中大量采用ThreadLocal线程局部变量的方法来保证线程的安全,像Dispatcher等都是通过ThreadLocal来保存变量值,使得每个线程都有自己独立的实例变量,互不相干.
接下来就从Dispatcher开始看起先看其构造函数 //创建Dispatcher此类是一个Delegate它是真正完成根据url解析转向读取对应Action的地方 public Dispatcher(ServletContext servletContext, MapString, String initParams) { this.servletContext servletContext; //配置在web.xml中的param参数 this.initParams initParams; } 我们再看在FilterDispatcher创建Dispatcher的: protected Dispatcher createDispatcher(FilterConfig filterConfig) { MapString, String params new HashMapString, String(); for (Enumeration e filterConfig.getInitParameterNames(); e.hasMoreElements();) { String name (String) e.nextElement(); String value filterConfig.getInitParameter(name); params.put(name, value); } return new Dispatcher(filterConfig.getServletContext(), params);
} 分七步载入各种配置属性,都是通过ConfigurationProvider接口进行的,这个接口提供init(),destroy(),register()等方法. 将各种ConfigurationProvider初始化之后将实例添加到ConfigurationManager的List里面. 最后通过循环调用List里的这些destroy(),register()等方法实现对配置文件的属性进行注册和销毁等功能. 下面将分析这七层功夫是怎样一步步练成的. XxxProvider类图: 首先是init_DefaultProperties() 创建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配置文件,默认的struts-default.xml,struts-plugin.xml,struts.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);
} PropertiesSettings类图 //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)); } }
ClassLoaderUtils.getResource( resourceName, callingClass ): 查找指定资源 public static URL getResource(String resourceName, Class callingClass) {URL url null;url Thread.currentThread().getContextClassLoader().getResource(resourceName);if (url null) {url ClassLoaderUtils.class.getClassLoader().getResource(resourceName);}if (url null) {url callingClass.getClassLoader().getResource(resourceName);}return url;}
为什么要按照这个顺序前面的加载为什么可能会失败 LocatableProperties.load( inputStream ): 将文件内容加载到 LocatableProperties 对象内。 public void load(InputStream in) throws IOException {Reader reader new InputStreamReader(in);PropertiesReader pr new PropertiesReader(reader);while (pr.nextProperty()) {String name pr.getPropertyName();String val pr.getPropertyValue();int line pr.getLineNumber();String desc convertCommentsToString(pr.getCommentLines());Location loc new LocationImpl(desc, location.getURI(), line, 0);setProperty(name, val, loc);}} LocatableProperties.setProperty( name, value, location ): 如何实现一个属性名称对应一个属性值而且有对应一个Location
LocatableProperties 内部有一个MapString,Location propLocations;
Properties 类本身又类似一个Map这样通过两个Map 来实现内部存储。 public Object setProperty(String key, String value, Object locationObj) {Object obj super.setProperty(key, value);if (location ! null) {Location loc LocationUtils.getLocation(locationObj);propLocations.put(key, loc);}return obj;}的十大书店
的十大书店
的十大书店 再来看第二步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); } }
} 对于其它配置文件只用StrutsXmlConfigurationProvider此类继承XmlConfigurationProvider而XmlConfigurationProvider又实现ConfigurationProvider接口。 类XmlConfigurationProvider负责配置文件的读取和解析 首先通过init()中的loadDocuments(configFileName);利用DomHelper中的 public static Document parse(InputSource inputSource, MapString, 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 ListDocument 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 fileactions_*.xml/ if (includeFileName.indexOf(*) ! -1) { ClassPathFinder wildcardFinder new ClassPathFinder(); wildcardFinder.setPattern(includeFileName); VectorString 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; }