1、具体的环境为
MyEclipse 8.5以及自带的tomcat
spring3.0.5
struts2.3.15.1
mybatis3.0.5
2、想弄明白的一些问题
tomcat集成spring,那么spring是如何启动的?
spring是如何读取配置文件的?
spring是如何处理依赖关系的?
应该说所有的bean都是spring实例化的,那么Action的实例是如何产生的?
3、spring是如何启动的?
了解了tomcat的启动过程(容器engine-host-context-wrapper一级一级启动,并且通过事件如ContextConfig等来读取各自应用的web.xml来初始化context),
读了web.xml中的配置,spring也是通过事件来启动的,配置如下:
<listener> <listener-class> org.springframework.web.util.Log4jConfigListener </listener-class> </listener> <listener> <listener-class> org.springframework.web.context.ContextLoaderListener </listener-class> </listener>
注意的是,如果配置了Log4jConfigListener,则Log4jConfigListener的配置要先于ContextLoaderListener的配置(spring3.0.5源码注释得知)。
4、spring启动后做了哪些事情?
通过debug3.0.5的源码,spring解析所有的配置文件,配置文件路径可以如下配置:
<context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath*:applicationContext*.xml</param-value> </context-param>
然后,spring可以得到该应用共有多少个bean(如现在的项目,大概是200+个)
这里,spring还会解析所有的*Sql.xml文件,得到所有的statement mapper
.
.
.
5、Action的实例是如何产生的?也是spring进行管理的吗?
首先Action的实例化不是由spring管理的,因为默认spring产生的实例都是单例的,而Action为了避免多线程产生的不一致,是多例的。
Action的作用是通过Filter机制来实现的:
<filter> <filter-name>struts2</filter-name> <filter-class> org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter </filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
这样所有的请求都会经过这个filter,而如果url是以.action(可在struts.properties中配置)结尾的,则会根据struts*.xml文件中的映射关系new出一个Action
进行处理。
5.1、
首先web application启动时,在初始化spring后,会调用org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.init(FilterConfig filterConfig) throws ServletException方法,在Dispatcher.java的init方法中会读取解析struts*xml配置文件:
/** * Load configurations, including both XML and zero-configuration strategies, * and update optional settings, including whether to reload configurations and resource files. */ public void init() { if (configurationManager == null) { configurationManager = createConfigurationManager(BeanSelectionProvider.DEFAULT_BEAN_NAME); } try { init_FileManager(); init_DefaultProperties(); // [1] init_TraditionalXmlConfigurations(); // [2] init_LegacyStrutsProperties(); // [3] init_CustomConfigurationProviders(); // [5] init_FilterInitParameters() ; // [6] init_AliasStandardObjects() ; // [7] Container container = init_PreloadConfiguration(); container.inject(this); init_CheckWebLogicWorkaround(container); if (!dispatcherListeners.isEmpty()) { for (DispatcherListener l : dispatcherListeners) { l.dispatcherInitialized(this); } } } catch (Exception ex) { if (LOG.isErrorEnabled()) LOG.error("Dispatcher initialization failed", ex); throw new StrutsException(ex); } }
然后通过*Provider的register方法来读取各种配置文件(struts默认的以及自己配置的)
如DefaultPropertiesProvider、XmlConfigrationProvider...
注意:和spring有一点不同,struts的ConfigurationManager只会解析struts.xml这个文件(可以配置指定特定名称),如果我们建立了另外的xml配置文件,
如struts-wms.xml,则需要在struts.xml中如下配置,
<include file="struts-wms.xml"></include>
配置文件的包含关系可以多层级的。
5.2、
在每次请求到来的时候,会调用void org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter.doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException这个方法,
//首先,判断这个请求url是不是在struts2处理的排除范围内,如果是,则继续调用其他filter进行处理 if (excludedPatterns != null && prepare.isUrlExcluded(request, excludedPatterns)) { chain.doFilter(request, response); } else { request = prepare.wrapRequest(request); //根据请求url得到对应的action mapping ActionMapping mapping = prepare.findActionMapping(request, response, true); //如果action mapping为空,则调用其他的filter进行处理 if (mapping == null) { boolean handled = execute.executeStaticResourceRequest(request, response); if (!handled) { chain.doFilter(request, response); } } else { //否则调用action mapping对应的Action进行处理 execute.executeAction(request, response, mapping); } }
一点猜想:
在调用完所有的filter之后,如果是由对应Action处理,则由Action处理完成后,通过向response中设值,交由tomcat处理后返回客户端;
如果不是,如图片/js等静态资源,应该是有Tomcat分派的处理线程调用默认的DefaultServlet返回相应资源。
结论是,不论是不是由Action处理,还是tomcat内部直接处理,只要通过封装了request和response,最后就一定可以通过tomcat的处理返回结果到客户端。。
6、Action中使用到的*Service可以通过@Autowired自动注入,这是通过什么样的机制??
ActionContext会new出对应的Action,那么Action中的字段如*Service是通过什么样的机制注入的?猜想是通过某个Interceptor。
但是,通过在*.java文件中搜索"Autowired.class",结果为0,意识到*Service的注入可能不是通过Interceptor。
在通过debug查看StrutsActionProxy中的DefaultActionInvocation字段中的*Action示例,发现*Service都是实例化过后的。
现在重点是弄明白StrutsActionProxy是如何实例化的?
通过这个类Object com.opensymphony.xwork2.spring.SpringObjectFactory.buildBean(String beanName, Map<String, Object> extraContext, boolean injectInternal) throws Exception
来实例化Action并注入*Service的,其中会得到spring的BeanFactory的实现进而得到所有的由spring管理的*Service。。