系统的学习一下spring的东西
第一部分,web项目初始化的时候spring容器的加载情况:
web项目启动的时候首先加载web.xml,初始化servletcontext对象
读取监听器
<listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener>
然后执行ContextLoaderListener 的
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
this.contextLoader.initWebApplicationContext(event.getServletContext());
}
这个方法。
实际上 public class ContextLoaderListener implements ServletContextListener
这个监听器是实现了j2ee的标准规范 ServletContextListener 这个借口
这个几口实际上就是监听项目启动,做一些初始化的工作
Implementations of this interface receive notifications about changes to the servlet context of the web application they are part of. To receive notification events, the implementation class must be configured in the deployment descriptor for the web application.
实现了这个接口的类可以接收通知--关于web应用中的servletcontext的一些变化。接收通知事件。并且必须要在web.xml中进行配置。所以在该接口的方法声明中有一个事件参数 即:(ServletContextEvent event)
------------------------------------下面这个方法是contextLoader 的初始化方法。返回一个WebApplicationContext对象。目前还没有使用。其中最主要的步骤就是createWebApplicationContext()
它主要就是产生一个bean工厂。并且把这个bean 工厂放入servletcontext中
public WebApplicationContext initWebApplicationContext(ServletContext servletContext)
throws IllegalStateException, BeansException {
if (servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE) != null) {
throw new IllegalStateException(
"Cannot initialize context because there is already a root application context present - " +
"check whether you have multiple ContextLoader* definitions in your web.xml!");
}
servletContext.log("Initializing Spring root WebApplicationContext");
if (logger.isInfoEnabled()) {
logger.info("Root WebApplicationContext: initialization started");
}
long startTime = System.currentTimeMillis();
try {
// Determine parent for root web application context, if any.
ApplicationContext parent = loadParentContext(servletContext);
// Store context in local instance variable, to guarantee that
// it is available on ServletContext shutdown.
this.context = createWebApplicationContext(servletContext, parent);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, this.context);
if (logger.isDebugEnabled()) {
logger.debug("Published root WebApplicationContext as ServletContext attribute with name [" +
WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE + "]");
}
if (logger.isInfoEnabled()) {
long elapsedTime = System.currentTimeMillis() - startTime;
logger.info("Root WebApplicationContext: initialization completed in " + elapsedTime + " ms");
}
return this.context;
}
catch (RuntimeException ex) {
logger.error("Context initialization failed", ex);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, ex);
throw ex;
}
catch (Error err) {
logger.error("Context initialization failed", err);
servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE, err);
throw err;
}
}
下面就是创建bean工厂的方法:
protected WebApplicationContext createWebApplicationContext(
ServletContext servletContext, ApplicationContext parent) throws BeansException {
Class contextClass = determineContextClass(servletContext);
if (!ConfigurableWebApplicationContext.class.isAssignableFrom(contextClass)) {
throw new ApplicationContextException("Custom context class [" + contextClass.getName() +
"] is not of type [" + ConfigurableWebApplicationContext.class.getName() + "]");
}
ConfigurableWebApplicationContext wac =
(ConfigurableWebApplicationContext) BeanUtils.instantiateClass(contextClass);
wac.setParent(parent);
wac.setServletContext(servletContext);
String configLocation = servletContext.getInitParameter(CONFIG_LOCATION_PARAM);
if (configLocation != null) {
wac.setConfigLocations(StringUtils.tokenizeToStringArray(configLocation,
ConfigurableWebApplicationContext.CONFIG_LOCATION_DELIMITERS));
}
wac.refresh();
return wac;
}
具体的bean的实际创建是:org.springframework.web.context.support.XmlWebApplicationContext 这个类的实例调用父类AbstractApplicationContext 的refresh方法:如下
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing.
prepareRefresh();
// Tell the subclass to refresh the internal bean factory.
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
// Prepare the bean factory for use in this context.
prepareBeanFactory(beanFactory);
try {
// Allows post-processing of the bean factory in context subclasses.
postProcessBeanFactory(beanFactory);
// Invoke factory processors registered as beans in the context.
invokeBeanFactoryPostProcessors(beanFactory);
// Register bean processors that intercept bean creation.
registerBeanPostProcessors(beanFactory);
// Initialize message source for this context.
initMessageSource();
// Initialize event multicaster for this context.
initApplicationEventMulticaster();
// Initialize other special beans in specific context subclasses.
onRefresh();
// Check for listener beans and register them.
registerListeners();
// Instantiate all remaining (non-lazy-init) singletons.
beanFactory.preInstantiateSingletons();
// Last step: publish corresponding event.
finishRefresh();
}
catch (BeansException ex) {
// Destroy already created singletons to avoid dangling resources.
beanFactory.destroySingletons();
// Reset 'active' flag.
cancelRefresh(ex);
// Propagate exception to caller.
throw ex;
}
}
}
--------------------------------------------------------------------------------------------------
第二部分 spring的task管理
主要是使用ScheduledTimerTask 这个类
1.创建一个继承自TimerTask 的自定义类,重写run方法。并在spring容器中声明:
<bean id="updateBufferDataService" class="com.temp.company.service.task.UpdateBufferDataService" />
2.在spring 的容器中声明一个bean
<bean id="updateBufferDataTask" class="org.springframework.scheduling.timer.ScheduledTimerTask"> <property name="delay"> <value>0</value> </property> <property name="period"> <value>600000</value> </property> <property name="timerTask"> <ref local="updateBufferDataService" /> </property> </bean>
id可以随便取,但是class 一定是ScheduledTimerTask这个class。中间的属性配置,是该类的直接变量的注入。
变量timerTask 配置成我们声明的哪个bean
3.声明一下TimerFactoryBean 这个类,这个相当于产生task的工厂 id随意
<bean id="updateBufferDataTimerFactory" class="org.springframework.scheduling.timer.TimerFactoryBean"> <property name="scheduledTimerTasks"> <list> <ref local="updateBufferDataTask" /> </list> </property> </bean>
其中:有一个数组的成员变量叫 scheduledTimerTasks ,把需要加载的task 放入list标签中即可
-------------------------------------------------------------------------------------------------------------------------
第三部分:spring使用hessian通过http远程调用服务
Hessian提供一种基于HTTP的二进制远程协议
1.应用程序提供服务器端:
Hessian使用一个特定的Servlet通过HTTP进行通讯。使用Spring在Web MVC中就常用的 DispatcherServlet
原理,可以很容易的配置这样一个Servlet来暴露你的服务。首先我们要在你的应用里创建一个新的Servlet(下面来自web.xml
文件):
<servlet> <servlet-name>remoting</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>remoting</servlet-name> <url-pattern>/remoting/*</url-pattern> </servlet-mapping>
这样你将需要在'WEB-INF'
目录中创建一个名为'remoting-servlet.xml'
(在你的servlet名称后) 的Spring容器配置上下文。在新创建的 remoting-servlet.xml
应用上下文里,我们将创建一个HessianServiceExporter
来暴露你的服务:
<bean id="accountService" class="example.AccountServiceImpl">
<!-- any additional properties, maybe a DAO? -->
</bean>
<bean name="/AccountService" class="org.springframework.remoting.caucho.HessianServiceExporter">
<property name="service" ref="accountService"/>
<property name="serviceInterface" value="example.AccountService"/>
</bean>
这样服务端就搭建好了。
2.下面是客户端的配置:
使用HessianProxyFactoryBean
,我们可以在客户端连接服务
<bean class="example.SimpleObject"> <property name="accountService" ref="accountService"/> </bean> <bean id="accountService" class="org.springframework.remoting.caucho.HessianProxyFactoryBean"> <property name="serviceUrl" value="http://remotehost:8080/remoting/AccountService"/> <property name="serviceInterface" value="example.AccountService"/> </bean>