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

Spring源码-启动过程

2017-07-12 09:46 309 查看

Spring源码分析(一)-Spring环境的初始化

Spring的框架特征

以下摘自知道词条

控制反转——Spring通过一种称作控制反转(IoC)的技术促进了低耦合。当应用了IoC,一个对象依赖的其它对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。你可以认为IoC与JNDI相反——不是对象从容器中查找依赖,而是容器在对象初始化时不等对象请求就主动将依赖传递给它。

面向切面——Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发。应用对象只实现它们应该做的——完成业务逻辑——仅此而已。它们并不负责(甚至是意识)其它的系统级关注点,例如日志或事务支持。

容器——Spring包含并管理应用对象的配置和生命周期,在这个意义上它是一种容器,你可以配置你的每个bean如何被创建——基于一个可配置原型(prototype),你的bean可以创建一个单独的实例或者每次需要时都生成一个新的实例——以及它们是如何相互关联的。然而,Spring不应该被混同于传统的重量级的EJB容器,它们经常是庞大与笨重的,难以使用。

框架——Spring可以将简单的组件配置、组合成为复杂的应用。在Spring中,应用对象被声明式地组合,典型地是在一个XML文件里。Spring也提供了很多基础功能(事务管理、持久化框架集成等等),将应用逻辑的开发留给了你。

MVC——Spring的作用是整合,但不仅仅限于整合,Spring 框架可以被看做是一个企业解决方案级别的框架。客户端发送请求,服务器控制器(由DispatcherServlet实现的)完成请求的转发,控制器调用一个用于映射的类HandlerMapping,该类用于将请求映射到对应的处理器来处理请求。HandlerMapping 将请求映射到对应的处理器Controller(相当于Action)在Spring 当中如果写一些处理器组件,一般实现Controller 接口,在Controller 中就可以调用一些Service 或DAO 来进行数据操作 ModelAndView 用于存放从DAO 中取出的数据,还可以存放响应视图的一些数据。 如果想将处理结果返回给用户,那么在Spring 框架中还提供一个视图组件ViewResolver,该组件根据Controller 返回的标示,找到对应的视图,将响应response 返回给用户。

我们将分章节介绍Spring是如何实现这些功能的。

Spring是如何初始化的

我们知道在WEB项目中集成Spring是需要在web.xml中添加一个监听器

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>


非Web项目:

java
public static void main(String[] args) {

//所有配置文件
args = new String[] {
"classpath:spring/spring-servlet.xml",
"classpath:spring/ApplicationContext.xml",
"classpath:spring/mybatis-config.xml",
};
ApplicationContext actx = new ClassPathXmlApplicationContext(args);
//得到类的实例
UserService userService = (UserService) actx.getBean("userService");
//调用类的方法
userService.deleteUser(2);
}


这里先以非Web项目为准,虽说Spring最长使用场景是在Web项目中,但是非Web项目这种用法更直接,更易跟踪。

看一下这个构造方法,歌词大意是创建一个ClassPathXmlApplicationContext,并从指定的配置文件加载定义,并自动的刷新Context(上下文)

java
/**
* Create a new ClassPathXmlApplicationContext, loading the definitions
* from the given XML file and automatically refreshing the context.
* @param configLocation resource location
* @throws BeansException if context creation failed
*/
public ClassPathXmlApplicationContext(String configLocation) throws BeansException {
this(new String[] {configLocation}, true, null);
}


跟踪下来看看多参构造器

java
/**
* Create a new ClassPathXmlApplicationContext with the given parent,
* loading the definitions from the given XML files.
* @param configLocations array of resource locations
* @param refresh whether to automatically refresh the context,
* loading all bean definitions and creating all singletons.
* Alternatively, call refresh manually after further configuring the context.
* @param parent the parent context
* @throws BeansException if context creation failed
* @see #refresh()
*/
public ClassPathXmlApplicationContext(String[] configLocations, boolean refresh, ApplicationContext parent)
throws BeansException {

super(parent);
setConfigLocations(configLocations);
if (refresh) {
refresh();
}
}


super(ApplicationContext parent)
暂时不管,因为我们通过那个构造器转进来,parent参数是null

setConfigLocations(configLocations);
这个是初始化context中的配置文件路径

refresh()
追进去看下

其实这个方法定义在父类org.springframework.context.support.AbstractApplicationContext 中,从这代码的书写方式上是可以看出Spring一些加载流程的(中文我自己加的,渣英语)

java
@Override
public void refresh() throws BeansException, IllegalStateException {
synchronized (this.startupShutdownMonitor) {
// Prepare this context for refreshing. //为正在进行的刷新准备bean工厂
prepareRefresh();

// Tell the subclass to refresh the internal bean factory. //告诉子类去刷新内部的beanFactory
ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

// Prepare the bean factory for use in this context.
// 在当前上下文中,准备Bean工厂
prepareBeanFactory(beanFactory);

try {
// Allows post-processing of the bean factory in context
// subclasses.
// 在bean被装载后,提供一个修改BeanFactory的入口  ,即允许子类做一些后处理
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.
// 检查是否有监听器bean并注册他们
registerListeners();

// Instantiate all remaining (non-lazy-init) singletons.
// 实例化所有的非懒加载的单例
finishBeanFactoryInitialization(beanFactory);

// Last step: publish corresponding event.
// 最后一步,发布相关事件
finishRefresh();
}

catch (BeansException ex) { //异常处理
if (logger.isWarnEnabled()) {
logger.warn("Exception encountered during context initialization - "
+ "cancelling refresh attempt: " + ex);
}

// Destroy already created singletons to avoid dangling
// resources.
// 销毁一些已经创建的bean
destroyBeans();

// Reset 'active' flag.
// 重置'active'标记
cancelRefresh(ex);

// Propagate exception to caller.
throw ex;
}

finally {
// Reset common introspection caches in Spring's core, since we
// might not ever need metadata for singleton beans anymore...
resetCommonCaches();
}
}
}


从以上代码,大概可知一个Spring上下文启动或刷新的过程

java
/**
* Prepare this context for refreshing, setting its startup date and active
* flag as well as performing any initialization of property sources.
*/
protected void prepareRefresh() {
this.startupDate = System.currentTimeMillis();
this.closed.set(false); //AtomicBoolean 类型
this.active.set(true);  //AtomicBoolean 类型

if (logger.isInfoEnabled()) {
logger.info("Refreshing " + this);
}

// Initialize any placeholder property sources in the context
// environment
initPropertySources();

// Validate that all properties marked as required are resolvable
// see ConfigurablePropertyResolver#setRequiredProperties
getEnvironment().validateRequiredProperties();

// Allow for the collection of early ApplicationEvents,
// to be published once the multicaster is available...
this.earlyApplicationEvents = new LinkedHashSet<ApplicationEvent>();
}


obtainFreshBeanFactory
看方法名是一个刷新Bean工厂的方法,其方法签名为
protected ConfigurableListableBeanFactory obtainFreshBeanFactory()


结合Spring源码注释 “Tell the subclass to refresh the internal bean factory.” ,方法含义为刷新并返回内部BeanFactory工厂

/**
* Tell the subclass to refresh the internal bean factory.
* @return the fresh BeanFactory instance
* @see #refreshBeanFactory()
* @see #getBeanFactory()
*/
protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
refreshBeanFactory(); //静态方法,子类覆写
ConfigurableListableBeanFactory beanFactory = getBeanFactory(); //静态方法子类覆写
if (logger.isDebugEnabled()) {
logger.debug("Bean factory for " + getDisplayName() + ": " + beanFactory);
}
return beanFactory;
}


那么实现该方法的子类是谁呢?,回到ClassPathXmlApplicationContext,看看其UML图



查看refreshBeanFactory的子类覆写情况,如图,明显是
org.springframework.context.support.AbstractRefreshableApplicationContext
这个类



通过代码看看BeanFactory是如何刷新的

/**
* This implementation performs an actual refresh of this context's underlying
* bean factory, shutting down the previous bean factory (if any) and
* initializing a fresh bean factory for the next phase of the context's lifecycle.
*/
@Override
protected final void refreshBeanFactory() throws BeansException {
if (hasBeanFactory()) {//判断是否已经有BeanFactory
destroyBeans();  //销毁单例bean,代码(getBeanFactory().destroySingletons()),具体是如何销毁的由具体的BeanFactory去实现
closeBeanFactory(); //关闭BeanFactory,直接设置实例变量(this.beanFactory)的引用为null
}
try {
DefaultListableBeanFactory beanFactory = createBeanFactory(); //创建一个新的BeanFactory
beanFactory.setSerializationId(getId());
customizeBeanFactory(beanFactory); //干了两个事,1:allowBeanDefinitionOverriding(是否允许ID相同的Bean覆盖,不指定时默认为true) 2.allowCircularReferences(是否允许循环引用,不指定时默认为true)
loadBeanDefinitions(beanFactory); //加载Bean的定义(读取配置文件,并向bean工厂中注册Bean)customizeBeanFactory中设置的作用会在读取Bean定义并注册的时候体现
synchronized (this.beanFactoryMonitor) {
this.beanFactory = beanFactory; //将新的Bean工厂注册给当前的Context
}
}
catch (IOException ex) {
throw new ApplicationContextException("I/O error parsing bean definition source for " + getDisplayName(), ex);
}
}


createBeanFactory();方法中创建了一个beanFactory,Factory实现与层级结构暂不分析,只看Spring的启动准备,loadBeanDefinitions(beanFactory);加载并注册Bean,
refreshBeanFactory()
主要干了两个事,先把Context中原来的工厂干掉,在重新创建和初始化一个新的Beanfactory.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: