一:spring概要 简单来说,Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架。
◆
控制反转——Spring通过一种称作控制反转(IoC)的技术促进了松耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。
◆
面向切面——Spring提供了
面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。
◆
容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置
原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。
◆
框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。
所有Spring的这些特征使你能够编写更干净、更可管理、并且更易于测试的代码。它们也为Spring中的各种模块提供了基础支持。
二:spring的整个生命周期 首先说一下spring的整个初始化过程,web应用中创建spring容器有两种方式: 第一种:在web.xml里直接配置spring容器,servletcontextlistener
第二种:通过load-on-startup servlet实现。
主要就说一下第一种方式:
spring提供了ServletContextListener的实现类ContextLoaderListener,该类作为listener使用,在创建时自动查找WEB-INF目录下的applicationContext.xml,该文件是默认查找的,如果只有一个就不需要配置初始化xml参数,如果需要配置,设置contextConfigLocation为application的xml文件即可。可以好好阅读一下ContextLoaderListener的源代码,就可以很清楚的知道spring的整个加载过程。
spring容器的初始化代码如下:
/** * Initialize the root web application context.
*/
public void contextInitialized(ServletContextEvent event) {
this.contextLoader = createContextLoader();
if (this.contextLoader == null) {
this.contextLoader = this;
}
this.contextLoader.initWebApplicationContext(event.getServletContext());//contextLoader初始化web应用容器
}
继续分析initWebApplicationContext做了什么事情:
/**
* Initialize Spring's web application context for the given servlet context,
* according to the "{@link #CONTEXT_CLASS_PARAM contextClass}" and
* "{@link #CONFIG_LOCATION_PARAM contextConfigLocation}" context-params.
* @param servletContext current servlet context
* @return the new WebApplicationContext
* @see #CONTEXT_CLASS_PARAM
* @see #CONFIG_LOCATION_PARAM
*/
public WebApplicationContext initWebApplicationContext(ServletContext servletContext) {
//首先创建一个spring的父容器,类似根节点root容器,而且只能是一个,如果已经创建,抛出对应的异常
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!");
}
Log logger = LogFactory.getLog(ContextLoader.class);
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);//创建通过web.xml配置的父容器
具体里面的代码是怎么实现的,就不在这里进行详解了
// 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);
//把spring初始好的容器加载到servletcontext内,相当于servletcontext包含webapplicationcontext
ClassLoader ccl = Thread.currentThread().getContextClassLoader();
if (ccl == ContextLoader.class.getClassLoader()) {
currentContext = this.context;
}
else if (ccl != null) {
currentContextPerThread.put(ccl, 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;
}
}
看到这里基本已经清楚了整个spring容器的加载过程,如果还想了解更加深入,请查看我红色标注的方法体。
其次再说一下spring的IOC和AOP使用的场景,由于原理大家都很清楚了,那就说一下它们使用到的地方:
IOC使用的场景:
管理bean的依赖关系,目前主流的电子商务网站基本都采用spring管理业务层代码的依赖关系,包括:淘宝,支付宝,阿里巴巴,百度等公司。