Spring学习之一:Ioc容器加单学习+applicationcontext

最近工作比较轻松,自主学习的时间很多,对于前段时间在网上学习,没有方向没有目的 感到遗憾不已,总是觉得要学习新的技术,却忘记了之前学习的东西都还没有巩固.还好,现在醒悟不算太晚.要学习的东西真的很多.而现在,终于想开始学习Spring了

Ioc容器学习+applicationcontext

Ioc控制反转,也叫依赖注入.先讲下控制反转的意思,控制是指容器控制程序的关系,而不是传统的用代码来控制程序.反转,即这种代码控制程序转移为容器控制程序.

依赖注入:组件之间的依赖关系由容器在运行期间完成,由容器动态的管理组件之间的依赖关系.

传统的方式:需要一个对象就自己 New()一个对象来使用.而现在直接从容器中获取就ok了.

 

Spring的Ioc容器,其实可以理解我BeanFactory,通过BeanFactory来实例化,配置和管理对象.BeanFactory是一个接口,常见的实现有XmlBeanFactory(使用Xml定义容器中的bean),AbstractBeanFactory,DefaultListableBeanFactory.

另外Resource接口用来抽象bean定义数据,XmlBeanDefinitionReader用于对xml定义bean的文件的解析。

看一下BeanFactory的源码:

publicinterfaceBeanFactory{

//这里是对FactoryBean的转义定义,因为如果使用bean的名字检索FactoryBean得到的对象是工厂生成的对象,

//如果需要得到工厂本身,需要转义

StringFACTORY_BEAN_PREFIX="&";

//这里根据bean的名字,在IOC容器中得到bean实例,这个IOC容器就是一个大的抽象工厂。

ObjectgetBean(Stringname)throwsBeansException;

//这里根据bean的名字和Class类型来得到bean实例,和上面的方法不同在于它会抛出异常:如果根据名字取得的bean实例的Class类型和需要的不同的话。

ObjectgetBean(Stringname,ClassrequiredType)throwsBeansException;

//这里提供对bean的检索,看看是否在IOC容器有这个名字的bean

booleancontainsBean(Stringname);

//这里根据bean名字得到bean实例,并同时判断这个bean是不是单件

booleanisSingleton(Stringname)throwsNoSuchBeanDefinitionException;

//这里对得到bean实例的Class类型

ClassgetType(Stringname)throwsNoSuchBeanDefinitionException;

//这里得到bean的别名,如果根据别名检索,那么其原名也会被检索出来

String[]getAliases(Stringname);

}

接下来简单的给大家看一下Ioc容器的创建过程:

 1.创建IOC配置文件的抽象资源

2.创建一个BeanFactory

3.把读取配置信息的BeanDefinitionReader,这里是XmlBeanDefinitionReader配置给BeanFactory

4.从定义好的资源位置读入配置信息,具体的解析过程由XmlBeanDefinitionReader来完成,这样完成整个载入bean定义的过程。我们的IoC容器就建立起来了。在BeanFactory的源代码中我们可以看到.

如下代码:

ClassPathResourceres=newClassPathResource("beans.xml");

DefaultListableBeanFactoryfactory=newDefaultListableBeanFactory();

XmlBeanDefinitionReaderreader=newXmlBeanDefinitionReader(factory);

reader.loadBeanDefinitions(res);

applicationcontext

先说几个applicationcontext的几个特点,

1,applicationcontext(Spring的上下文)是在beanfactory的基础上扩展而来的,除了具备BeanFactory的全部能力,还具有其他的新的功能。

2,applicationcontext扩展了MessageSource

3,applicationcontext支持ResourceLoader和Resource,可以从不同的地方访问bean资源

4,applicationcontext允许上下文嵌套,通过保持父上下文来维持一个上下文体系,这个体系在我们的web容器分析中可以看到.

BeanFactory和 ApplicationContext在不同的使用层面上代表了Spring提供Ioc容器服务.

由于applicationcontext比BeanFactory更加好用,用的更多的当然就是它了。

ApplicationContext提供Ioc容器的主要接口,在其体系中有许多的抽象子类。例如常见的:AbstractApplicationContext,FileSystemXmlApplicationContext,ClassPathXmlApplicationContext.

接下来重点说一下web开发中获取Spring的AplicationContext的三种方式:

首先要看一下源码,了解一下ApplicationContext的存储.

web.xml中的配置:

<listener>

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

</listener>

配置了监听器ContextLoaderListener,追踪一下ContextLoaderListener

publicclassContextLoaderListenerimplementsServletContextListener{

privateContextLoadercontextLoader;

/**

*Initializetherootwebapplicationcontext.

*/

publicvoidcontextInitialized(ServletContextEventevent){

this.contextLoader=createContextLoader();

this.contextLoader.

initWebApplicationContext(event.getServletContext());

}

再看一下: initWebApplicationContext方法,

publicWebApplicationContextinitWebApplicationContext(ServletContextservletContext)

throwsIllegalStateException,BeansException{

//从ServletContext中查找,是否存在以//WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE为Key的值

if(servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE)!=null){

thrownewIllegalStateException(

"Cannotinitializecontextbecausethereisalreadyarootapplicationcontextpresent-"+

"checkwhetheryouhavemultipleContextLoader*definitionsinyourweb.xml!");

}

try{

//Determineparentforrootwebapplicationcontext,ifany.

ApplicationContextparent=loadParentContext(servletContext);

//itisavailableonServletContextshutdown.

this.context=createWebApplicationContext(servletContext,parent);

//将ApplicationContext放入ServletContext中,其key为//WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE

servletContext.setAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE,this.context);</span></span>

//将ApplicationContext放入ContextLoader的全局静态常量Map中,其中key

//为:Thread.currentThread().getContextClassLoader()即当前线程类加载器

currentContextPerThread.put(Thread.currentThread().getContextClassLoader(),this.context);

returnthis.context;

}

上面的代码表明,ContextLoaderListener实现了ServeletContextListenet,在ServletContext初始化的时候,会进行Spring的初始化。同时Spring初始化之后,将ApplicationContext存到在了两个地方,意味着我们有两种方式可以获取ApplicationContext。

第一种:

注意:WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE=WebApplicationContext.class.getName()+".ROOT";

即为"org.springframework.web.context.WebApplicationContext.ROOT"

那就可以这样获得ApplicationContext:

request.getSession().getServletContext().getAttribute("org.springframework.web.context.WebApplicationContext.ROOT"),其实Spring已经给了我们接口,

使用spring的工具类来获取:

ApplicationContextac1=WebApplicationContextUtils.getRequiredWebApplicationContext(ServletContextsc);

ApplicationContextac2=WebApplicationContextUtils.getWebApplicationContext(ServletContextsc);

ac1.getBean("beanId");

ac2.getBean("beanId");

说明:

这种方式适合于采用Spring框架的B/S系统,通过ServletContext对象获取ApplicationContext对象,然后在通过它获取需要的类实例。

其中servletContextsc可以具体换成servlet.getServletContext()或者this.getServletContext()或者request.getSession().getServletContext();另外,由于spring是注入的对象放在ServletContext中的,所以可以直接在ServletContext取出WebApplicationContext对象:WebApplicationContextwebApplicationContext=(WebApplicationContext)servletContext.getAttribute(WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE);

第二种方法:

前面说到Spring初始化的时候,将ApplicationContext还存了一份到ContextLoader的Map里面,然而这个Map是私有的,我们直接拿不到的呢。

当然spring也提供了方法的:

<spanstyle="color:#000000;">publicstatic</span>WebApplicationContextgetCurrentWebApplicationContext(){

return(WebApplicationContext)currentContextPerThread.get(Thread.currentThread().getContextClassLoader());

}

第三种方式:

借用ApplicationContextAware,ApplicationContext的帮助类能够自动装载ApplicationContext,只要你将某个类实现这个接口,并将这个实现类在Spring配置文件中进行配置,Spring会自动帮你进行注

入ApplicationContext.ApplicationContextAware的代码结构如下:

publicinterfaceApplicationContextAware{

voidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException;

}

关于spring中的ApplicationContext可在另外一篇博客中看。

相关推荐