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

Struts2.3.14分析-初始化2--Struts.xml解析

2015-05-06 21:14 316 查看
承接上一篇,在Filter初始化时,在DefautlConfiguration类中调用containerProvider的方法,完成对各个ContainerProvider的解析,我们着重分析对Struts.xml文件的读取和解析。

DefaultConfiguration类

public synchronized List<PackageProvider> reloadContainer(List<ContainerProvider> providers) throws ConfigurationException {
packageContexts.clear();
loadedFileNames.clear();
List<PackageProvider> packageProviders = new ArrayList<PackageProvider>();

ContainerProperties props = new ContainerProperties();
ContainerBuilder builder = new ContainerBuilder();
for (final ContainerProvider containerProvider : providers)
{
containerProvider.init(this);①
containerProvider.register(builder, props);②
}
……

// Then process any package providers from the plugins
Set<String> packageProviderNames = container.getInstanceNames(PackageProvider.class);
if (packageProviderNames != null) {
for (String name : packageProviderNames) {
PackageProvider provider = container.getInstance(PackageProvider.class, name);
provider.init(this);
provider.loadPackages();③
packageProviders.add(provider);
}
}
……
return packageProviders;
}


XmlConfigurationProvider类

private Set<String> loadedFileUrls = new HashSet<String>();
private Configuration configuration;
private Set<String> includedFileNames;
private List<Document> documents;

//①init 方法,读取该Provider对应的xml文件,转换成documents
public void init(Configuration configuration) {
this.configuration = configuration;
this.includedFileNames = configuration.getLoadedFileNames();
//加载xml文件
loadDocuments(configFileName);
}

private void loadDocuments(String configFileName) {
try {
loadedFileUrls.clear();
documents = loadConfigurationFiles(configFileName, null);
} catch (ConfigurationException e) {
throw e;
} catch (Exception e) {
throw new ConfigurationException("Error loading configuration file " + configFileName, e);
}
}

# 将xml文件转换成document,并存放在list中
private List<Document> loadConfigurationFiles(String fileName, Element includeElement) {
List<Document> docs = new ArrayList<Document>();
List<Document> finalDocs = new ArrayList<Document>();
if (!includedFileNames.contains(fileName)) {
if (LOG.isDebugEnabled()) {
LOG.debug("Loading action configurations from: " + fileName);
}
includedFileNames.add(fileName);
Iterator<URL> urls = null;
InputStream is = null;

IOException ioException = null;
try {
# 获取配置文件的路径
urls = getConfigurationUrls(fileName);
} catch (IOException ex) {
ioException = ex;
}

if (urls == null || !urls.hasNext()) {
if (errorIfMissing) {
throw new ConfigurationException("Could not open files of the name " + fileName, ioException);
} else {
if (LOG.isInfoEnabled()) {
LOG.info("Unable to locate configuration files of the name " + fileName + ", skipping");
}
return docs;
}
}

URL url = null;
while (urls.hasNext()) {
try {
url = urls.next();
is = fileManager.loadFile(url);
InputSource in = new InputSource(is);
in.setSystemId(url.toString());
docs.add(DomHelper.parse(in, dtdMappings));
} catch (XWorkException e) {
if (includeElement != null) {
throw new ConfigurationException("Unable to load " + url, e, includeElement);
} else {
throw new ConfigurationException("Unable to load " + url, e);
}
} catch (Exception e) {
throw new ConfigurationException("Caught exception while loading file " + fileName, e, includeElement);
} finally {
if (is != null) {
try {
is.close();
} catch (IOException e) {
LOG.error("Unable to close input stream", e);
}
}
}
}

//sort the documents, according to the "order" attribute
Collections.sort(docs, new Comparator<Document>() {
public int compare(Document doc1, Document doc2) {
return XmlHelper.getLoadOrder(doc1).compareTo(XmlHelper.getLoadOrder(doc2));
}
});

# 解析文件,将xml文件转换成document对象
for (Document doc : docs) {
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();
# 处理include标签,xml文件嵌套
if ("include".equals(nodeName)) {
String includeFileName = child.getAttribute("file");
if (includeFileName.indexOf('*') != -1) {
// handleWildCardIncludes(includeFileName, docs, child);
ClassPathFinder wildcardFinder = new ClassPathFinder();
wildcardFinder.setPattern(includeFileName);
Vector<String> wildcardMatches = wildcardFinder.findMatches();
for (String match : wildcardMatches) {
finalDocs.addAll(loadConfigurationFiles(match, child));
}
} else {
finalDocs.addAll(loadConfigurationFiles(includeFileName, child));
}
}
}
}
finalDocs.add(doc);
loadedFileUrls.add(url.toString());
}
if (LOG.isDebugEnabled()) {
LOG.debug("Loaded action configuration from: " + fileName);
}
}
return finalDocs;
}

protected Iterator<URL> getConfigurationUrls(String fileName) throws IOException {
return ClassLoaderUtil.getResources(fileName, XmlConfigurationProvider.class, false);
}

//②register方法,处理xml文件的beans、constant标签
public void register(ContainerBuilder containerBuilder, LocatableProperties props) throws ConfigurationException {
if (LOG.isInfoEnabled()) {
LOG.info("Parsing configuration file [" + configFileName + "]");
}
Map<String, Node> loadedBeans = new HashMap<String, Node>();
for (Document doc : documents) {
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 ("bean".equals(nodeName)) {
#将bean信息加载到containBuild中,struts自己的IoC
String type = child.getAttribute("type");
String name = child.getAttribute("name");
String impl = child.getAttribute("class");
String onlyStatic = child.getAttribute("static");
String scopeStr = child.getAttribute("scope");
boolean optional = "true".equals(child.getAttribute("optional"));
Scope scope = Scope.SINGLETON;
if ("default".equals(scopeStr)) {
scope = Scope.DEFAULT;
} else if ("request".equals(scopeStr)) {
scope = Scope.REQUEST;
} else if ("session".equals(scopeStr)) {
scope = Scope.SESSION;
} else if ("singleton".equals(scopeStr)) {
scope = Scope.SINGLETON;
} else if ("thread".equals(scopeStr)) {
scope = Scope.THREAD;
}

if (StringUtils.isEmpty(name)) {
name = Container.DEFAULT_NAME;
}

try {
Class cimpl = ClassLoaderUtil.loadClass(impl, getClass());
Class ctype = cimpl;
if (StringUtils.isNotEmpty(type)) {
ctype = ClassLoaderUtil.loadClass(type, getClass());
}
if ("true".equals(onlyStatic)) {
// Force loading of class to detect no class def found exceptions
cimpl.getDeclaredClasses();
containerBuilder.injectStatics(cimpl);
} else {
if (containerBuilder.contains(ctype, name)) {
Location loc = LocationUtils.getLocation(loadedBeans.get(ctype.getName() + name));
if (throwExceptionOnDuplicateBeans) {
throw new ConfigurationException("Bean type " + ctype + " with the name " +
name + " has already been loaded by " + loc, child);
}
}

// Force loading of class to detect no class def found exceptions
cimpl.getDeclaredConstructors();

if (LOG.isDebugEnabled()) {
LOG.debug("Loaded type:" + type + " name:" + name + " impl:" + impl);
}
containerBuilder.factory(ctype, name, new LocatableFactory(name, ctype, cimpl, scope, childNode), scope);
}
loadedBeans.put(ctype.getName() + name, child);
} catch (Throwable ex) {
if (!optional) {
throw new ConfigurationException("Unable to load bean: type:" + type + " class:" + impl, ex, childNode);
} else {
if (LOG.isDebugEnabled()) {
LOG.debug("Unable to load optional class: #0", ex, impl);
}
}
}
} else if ("constant".equals(nodeName)) {
# 将constant信息加载到LocatableProperties
String name = child.getAttribute("name");
String value = child.getAttribute("value");
props.setProperty(name, value, childNode);
} else if (nodeName.equals("unknown-handler-stack")) {
List<UnknownHandlerConfig> unknownHandlerStack = new ArrayList<UnknownHandlerConfig>();
NodeList unknownHandlers = child.getElementsByTagName("unknown-handler-ref");
int unknownHandlersSize = unknownHandlers.getLength();

for (int k = 0; k < unknownHandlersSize; k++) {
Element unknownHandler = (Element) unknownHandlers.item(k);
unknownHandlerStack.add(new UnknownHandlerConfig(unknownHandler.getAttribute("name")));
}

if (!unknownHandlerStack.isEmpty())
configuration.setUnknownHandlerStack(unknownHandlerStack);
}
}
}
}
}

//③loadPackages方法加载Package节点信息
public void loadPackages() throws ConfigurationException {
List<Element> reloads = new ArrayList<Element>();
//检查Package extends是否处在闭环,如A extends B,但B却 extends A
verifyPackageStructure();⑴

for (Document doc : documents) {
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 ("package".equals(nodeName)) {
PackageConfig cfg = addPackage(child);⑵
if (cfg.isNeedsRefresh()) {
reloads.add(child);
}
}
}
}
loadExtraConfiguration(doc);
}

if (reloads.size() > 0) {
reloadRequiredPackages(reloads);
}

for (Document doc : documents) {
loadExtraConfiguration(doc);
}

documents.clear();
declaredPackages.clear();
configuration = null;
}

private void verifyPackageStructure() {
DirectedGraph<String> graph = new DirectedGraph<String>();

for (Document doc : documents) {
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 ("package".equals(nodeName)) {
String packageName = child.getAttribute("name");
declaredPackages.put(packageName, child);
graph.addNode(packageName);

String extendsAttribute = child.getAttribute("extends");
List<String> parents = ConfigurationUtil.buildParentListFromString(extendsAttribute);
//添加顶点和变到图中
for (String parent : parents) {
graph.addNode(parent);
graph.addEdge(packageName, parent);
}
}
}
}
}

CycleDetector<String> detector = new CycleDetector<String>(graph);
//检测图中是否包含回路
if (detector.containsCycle()) {
StringBuilder builder = new StringBuilder("The following packages participate in cycles:");
for (String packageName : detector.getVerticesInCycles()) {
builder.append(" ");
builder.append(packageName);
}
throw new ConfigurationException(builder.toString());
}
}

protected PackageConfig addPackage(Element packageElement) throws ConfigurationException {
PackageConfig.Builder newPackage = buildPackageContext(packageElement);

if (newPackage.isNeedsRefresh()) {
return newPackage.build();
}

if (LOG.isDebugEnabled()) {
LOG.debug("Loaded " + newPackage);
}

// 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);
//处理Package中的Action
addAction(actionElement, newPackage);
}

// load the default action reference for this package
loadDefaultActionRef(newPackage, packageElement);

PackageConfig cfg = newPackage.build();
//将Package信息加入DefaultConfiguration中
configuration.addPackageConfig(cfg.getName(), cfg);
return cfg;
}

protected void addAction(Element actionElement, PackageConfig.Builder packageContext) throws ConfigurationException {
String name = actionElement.getAttribute("name");
String className = actionElement.getAttribute("class");
String methodName = actionElement.getAttribute("method");
Location location = DomHelper.getLocationObject(actionElement);

if (location == null) {
if (LOG.isWarnEnabled()) {
LOG.warn("location null for " + className);
}
}
//methodName should be null if it's not set
methodName = (methodName.trim().length() > 0) ? methodName.trim() : null;

Map<String, ResultConfig> results;
try {
//处理Action下的多个result
results = buildResults(actionElement, packageContext);
} catch (ConfigurationException e) {
throw new ConfigurationException("Error building results for action " + name + " in namespace " + packageContext.getNamespace(), e, actionElement);
}

List<InterceptorMapping> interceptorList = buildInterceptorList(actionElement, packageContext);

List<ExceptionMappingConfig> exceptionMappings = buildExceptionMappings(actionElement, packageContext);

Set<String> allowedMethods = buildAllowedMethods(actionElement, packageContext);

ActionConfig actionConfig = new ActionConfig.Builder(packageContext.getName(), name, className)
.methodName(methodName)
.addResultConfigs(results)
.addInterceptors(interceptorList)
.addExceptionMappings(exceptionMappings)
.addParams(XmlHelper.getParams(actionElement))
.addAllowedMethod(allowedMethods)
.location(location)
.build();
packageContext.addActionConfig(name, actionConfig);
}


StrutsXmlConfigurationProvider类

public void register(ContainerBuilder containerBuilder,
LocatableProperties props) throws ConfigurationException {
if (servletContext != null && !containerBuilder.contains(ServletContext.class)) {
containerBuilder.factory(ServletContext.class, new Factory<ServletContext>() {
public ServletContext create(Context context) throws Exception {
return servletContext;
}
});
}
#调用XmlConfigurationProvider的register方法
super.register(containerBuilder, props);
}


ContainerBuilder类

#容器类,保存配置文件的Beans
public final class ContainerBuilder {
final Map<Key<?>, InternalFactory<?>> factories = new HashMap<Key<?>, InternalFactory<?>>();
final List<InternalFactory<?>> singletonFactories = new ArrayList<InternalFactory<?>>();
final List<Class<?>> staticInjections = new ArrayList<Class<?>>();
boolean created;
boolean allowDuplicates = false;

public ContainerBuilder injectStatics(Class<?>... types) {
staticInjections.addAll(Arrays.asList(types));
return this;
}

private void ensureNotCreated() {
if (created) {
throw new IllegalStateException("Container already created.");
}
}

private void checkKey(Key<?> key) {
if (factories.containsKey(key) && !allowDuplicates) {
throw new DependencyException("Dependency mapping for " + key + " already exists.");
}
}

public <T> ContainerBuilder factory(final Class<T> type, final String name, final Class<? extends T> implementation, final Scope scope) {
InternalFactory<? extends T> factory = new InternalFactory<T>(){
// This factory creates new instances of the given implementation.
// We have to lazy load the constructor because the Container
// hasn't been created yet.
volatile ContainerImpl.ConstructorInjector<? extends T> constructor;
@SuppressWarnings("unchecked")
public T create(InternalContext context) {
if (constructor == null) {
this.constructor = context.getContainerImpl().getConstructor(implementation);
}
return (T) constructor.construct(context, type);
}

@Override
public String toString() {
return new LinkedHashMap<String, Object>() {{
put("type", type);
put("name", name);
put("implementation", implementation);
put("scope", scope);
}}.toString();
}
};
return factory(Key.newInstance(type, name), factory, scope);
}

private <T> ContainerBuilder factory(final Key<T> key,
InternalFactory<? extends T> factory, Scope scope) {
ensureNotCreated();
checkKey(key);
final InternalFactory<? extends T> scopedFactory =
scope.scopeFactory(key.getType(), key.getName(), factory);
factories.put(key, scopedFactory);
if (scope == Scope.SINGLETON) {
singletonFactories.add(new InternalFactory<T>() {
public T create(InternalContext context) {
try {
context.setExternalContext(ExternalContext.newInstance(
null, key, context.getContainerImpl()));
return scopedFactory.create(context);
} finally {
context.setExternalContext(null);
}
}
});
}
return this;
}


这样,在调用完init和register方法后,将struts.xml内容转化为Java对象存储起来,方便后面管理。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: