1、IoC概述

    控制反转(Inverse of Control,IoC)是Spring容器的内核,AOP、声明式事务等功能都是在此基础上扩展的。所谓IoC就是通过容器来控制业务对象之间的依赖关系,而不是传统实现中,由代码直接操控。这也就是“控制反转”概念所在:控制权由应用代码中转移到了外部容器,控制权的转移,就是反转。控制权转移带来的好处就是降低了业务对象之间的依赖程度。

    更加形象的说明一下IoC是如何做的。这有点像通过婚介找女朋友,在我和女朋友之间引入了一个第三者:婚姻介绍所。婚介管理了很多男男女女的资料,我可以向婚介提出一个列表,告诉它我想找个什么样的女朋友,比如长得像李嘉欣,身材像林熙雷,唱歌像周杰伦,速度像卡洛斯,技术像齐达内之类的,然后婚介就会按照我们的要求,提供一个mm,我们只需要去和她谈恋爱、结婚就行了。简单明了,如果婚介给我们的人选不符合要求,我们就会抛出异常。整个过程不再由我自己控制,而是有婚介这样一个类似容器的机构来控制。Spring所倡导的开发方式就是如此,所有的类都会在spring容器中登记,告诉spring你是个什么东西,你需要什么东西,然后spring会在系统运行到适当的时候,把你要的东西主动给你,同时也把你交给其他需要你的东西。所有的类的创建、销毁都由 spring来控制,也就是说控制对象生存周期的不再是引用它的对象,而是spring。对于某个具体的对象而言,以前是它控制其他对象,现在是所有对象都被spring控制,所以这叫控制反转。

2、BeanFactory和ApplicationContext

    Spring通过一个配置文件描述了Bean和Bean之间的依赖关系,利用Java语言的反射功能实例化Bean并建立Bean之间的依赖关系。Spring的IoC容器在完成这些底层工作的基础上,还提供了Bean实例化缓存、声明周期管理、Bean实例化代理、事件发布、资源装载等高级服务。

    Bean工厂(BeanFactory)是Spring框架最核心的接口,它提供了高级IoC的配置机制。BeanFactory使管理不同类型的Java对象称为可能,应用上下文(ApplicationContext)建立在BeanFactory基础之上,提供了更多面向应用的功能。BeanFactory是Spring框架的基础设施,面向Spring本身;ApplicationContext面向Spring框架的开发者,几乎所有的应用场合都直接使用ApplicationContext而非底层的BeanFactory。

    ApplicationContext由BeanFactory派生而来,提供了更多面向实际应用的功能。在获取ApplicationContext实例后,就可以像BeanFactory一样调用getBean(beanName)返回Bean了。ApplicationContext的初始化和BeanFactory的初始化有一个重大的区别:BeanFactory在初始化容器时,并未初始化Bean,直到第一次访问某个Bean时才实例化目标Bean;而ApplicationContext在初始化应用上下文时就实例化所有单实例的Bean。因此ApplicationContext的初始化时间会比BeanFactory稍长一些。

    Spring3.0支持基于注解类的配置方式,主要功能来自于Spring的一个名为JavaConfig的子项目,目前JavaConfig已经是Spring核心框架的一部分。一个标注@Configuration注解的POJO即可提供Spring所需的Bean配置信息。

    WebApplicationContext是专门为Web应用准备的,它允许从相对于Web根目录的路径中装载配置文件,完成初始化工作。从WebApplicationContext中可以获得ServletContext的引用,整个Web应用上下文对象将作为属性防止到ServletContext中,以便Web应用环境可以访问spring应用上下文。Spring专门为此提供了一个工具类WebApplicationContextUtils。通过该类的getWebApplicationContext(ServletContext sc)方法,既可以从ServletContext中获取WebApplicationContext实例。

    Spring分别提供了用于启动WebApplicationContext的Servlet和Web容器监听器

  • org.springframework.web.context.ContextLoaderServlet

  • org.springframework,web.context.ContextLoaderListener

两者都实现了启动WebApplicationContext实例的逻辑,用户只要根据Web容器的具体情况选择二者之一,并在web.xml中完成配置就可以了。

    通过实例认识BeanFactory

package org.worm.biz;import org.apache.log4j.Logger;import org.springframework.beans.BeansException;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.BeanFactoryAware;import org.springframework.beans.factory.BeanNameAware;import org.springframework.beans.factory.DisposableBean;import org.springframework.beans.factory.InitializingBean;import org.worm.util.LogUtil;/** * @ClassName: Car * @Description: TODO 认识BeanFactory测试用类* @author Administrator* @date 2016年6月28日 上午10:48:51 *  */ public class Car implements BeanFactoryAware,BeanNameAware,InitializingBean,DisposableBean{ private static final Logger logger = LogUtil.getLogger(Car.class); private String brand; private String color; private int maxSpeed; private String name; private BeanFactory beanFactory; private String beanName;  public Car() {  logger.info("调用Car()构造函数"); } public String getBrand() {  return brand; } public void setBrand(String brand) {  logger.info("调用setBrand()设置属性");  this.brand = brand; } public String getColor() {  return color; } public void setColor(String color) {  this.color = color; } public int getMaxSpeed() {  return maxSpeed; } public void setMaxSpeed(int maxSpeed) {  this.maxSpeed = maxSpeed; } public String getName() {  return name; } public void setName(String name) {  this.name = name; } public BeanFactory getBeanFactory() {  return beanFactory; } public String getBeanName() {  return beanName; } public void destroy() throws Exception {  // TODO Auto-generated method stub  logger.info("调用DispoasbleBean.destroy()."); } public void afterPropertiesSet() throws Exception {  // TODO Auto-generated method stub  logger.info("调用InitializingBean.afterPropertiesSet()"); } public void setBeanName(String name) {  // TODO Auto-generated method stub  logger.info("调用BeanNameAware.setBeanName()");  this.beanName = name; } public void setBeanFactory(BeanFactory beanFactory) throws BeansException {  // TODO Auto-generated method stub  logger.info("调用BeanFactoryAware.setBeanFactory().");  this.beanFactory = beanFactory; } @Override public String toString() {  return "Car [brand=" + brand + ", color=" + color + ", maxSpeed=" + maxSpeed + "]"; } public void introduce(){  logger.info("introduce:"+this.toString()); } public void myInit(){  logger.info("调用myInit()");  this.maxSpeed = 240; } public void myDestory(){  logger.info("调用买也D额story"); }}
package org.worm.biz.springioc;import org.apache.log4j.Logger;import org.springframework.beans.factory.BeanFactory;import org.springframework.beans.factory.xml.XmlBeanFactory;import org.springframework.core.io.Resource;import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import org.springframework.core.io.support.ResourcePatternResolver;import org.worm.biz.Car;import org.worm.util.LogUtil;/** * @ClassName: TestSpringIoC * @Description: TODO 学习了解SpringIoC* @author Administrator* @date 2016年6月28日 上午10:39:27 *  */  public class TestSpringIoC { private static final Logger logger = LogUtil.getLogger(TestSpringIoC.class); /**  * @Title: testBeanFactory  * @Description: TODO 通过实例认识BeanFactory  * @param     设定文件  * @return void    返回类型  * @throws  */  private static void testBeanFactory(){  ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();  Resource res = resolver.getResource("classpath:beans.xml");  BeanFactory bf= new XmlBeanFactory(res);  logger.info("init BeanFactory");  Car car = bf.getBean("car", Car.class);  car.introduce();  System.out.println("car bean is ready for use!"); } public static void main(String[] args) {  // TODO Auto-generated method stub  new TestSpringIoC().testBeanFactory(); }}
      
      
            
      
       
        
         
text/html;charset=UTF-8
        
                   
      
       
        
         
        
                    
       
           
  
                   
                   
    
    
       
       
   

运行结果:

通过注解配置beans.xml的类Beans.java

package org.worm.biz;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;/** * @ClassName: Beans * @Description: TODO 基于注解的配置方式,类似于bens.xml* @author Administrator* @date 2016年6月28日 上午11:40:29 *  */ @Configurationpublic class Beans { @Bean(name = "car") public Car buildCar(){  Car car = new Car();  car.setBrand("红旗CA72_Annotation");  car.setMaxSpeed(200);  car.setColor("黑色_Annotation");  return car; }}

加载ApplicationContext

/**  * @Title: testApplicationContextWithAnnotatioin  * @Description: TODO 实例演示applicationContext * @param     设定文件  * @return void    返回类型  * @throws  */  private static void testApplicationContextWithAnnotatioin(){  ApplicationContext ctx = new AnnotationConfigApplicationContext(Beans.class);  Car car = ctx.getBean("car",Car.class);  car.introduce(); }

3、资源加载

    为了访问不同类型的资源,必须使用相应的Resource实现类,是否可以在不显示使用Resource实现类的情况下,仅通过资源地址的特殊标识就可以加载相应的资源了呢?Spring提供了一个强大的加载资源的机制,不但能够通过“classpath”、"file"等资源地址前缀识别不同的资源类型,还支持Ant风格带通配符的资源地址

地址前缀
示例
对应资源类型
classpath:
classpath:org/aku/worm/biz/beans.xml
从类路径中加载资源,classpath:和classpath:/是等价的,都是相对于类的根路径。资源文件可以在标准的文件系统中,可以在jar或者zip的类包中
file:
file:/org/aku/worm/biz/beans.xml
使用UrlResource从文件系统目录中加载资源,可以采用绝对路径或相对路径
http://
http://www.aku.org/resource/beans.xml
使用UrlResource从Web服务器中装载资源
ftp://
ftp://www.aku.org/resource/beans.xml
使用UrlResource从FTP服务器中加载资源
没有前缀
org/aku/worm/biz/beans.xml
根据ApplicationContext具体实现类采用对应的Resource
classpath*:
classpath*:org/aku/worm/biz/beans.xml 假设多个Jar包或者文件系统类路径中都拥有一个相同的包名(org.aku.worm)。classpath:只会在第一个加载的org.aku.worm包下查找,而classpath*:会扫描所有这个jar包或者类路径下的org.aku.worm类路径。

4、Bean基本配置

   4.1、 在<beans>标签内装载bean,bean的id属性是唯一的,此外id的命名需要满足xml对id的命名规范:必须以字母开始,后面可以是字母、数字、连字符、下划线、句号、冒号等完成结束符,逗号和空格等是非法的。

    4.2、依赖注入

        属性注入,通过setter()方法注入Bean的属性或依赖对象,由于属性注入方式具有可选择性和灵活性高的优点,所以属性注入是最常用的注入方式。

        构造函数注入,它保证一些必要的属性在Bean实例化时就得到设置,并确保了Bean实例在实例化后就可以使用。可按照类型匹配入参、联合使用类型和索引匹配入参和通过自身类型反射匹配入参

    4.3、注入参数详解

        字面值,一般指可用字符串表示的值,这些值可以通过<value>标签元素进行注入。在xml中<![CDTAT[]]>的作用是让XML解析器将标签中的字符串当做普通文本对待,以防止某些字符串对xml格式造成破坏

        引用其他Bean,通过<ref>元素就可以引用其他Bean,建立起依赖关系

        集合类型属性,Spring为集合类型(List、Set、Map和Properties)属性提供了专门的配置元素标签。List属性用<list>。Map属性用<map><entry><key/><value/></entry></map>来配置。Properties可以看成Map类型的特例。<props><prop key></prop></props>。最后集合属性可以通过util命名空间配置集合类型的Bean

    4.4、Bean的作用域

        在Spring中Bean有5个作用域,singleton(在springIoC容器中,仅存在一个Bean实例),prototype(每次从容器中调用Bean时,都相当于执行了一个new XXXBean()),request(每次HTTP请求都会创建一个新的Bean),session(同一个HTTP Session共享一个Bean),globalSession(同一个全局Session共享一个Bean)。

        在Spring中推荐采用配置方式“Scope=<作用域类型>”。

    4.5、基于注解的Bean

        Spring容器成功启动的三大要件分别是:Bean定义信息、Bean实现类以及Spring本身。Spring提供了3个功能分别对于DAO、Service以及Web层的Controller进行注解。

  • @Repository:用于对DAO实现类进行注解

  • @Service:用于对Service进行注解

  • @Controller:用于对Controller进行注解

5、总结

    本文分析了IoC的概念,控制反转其实包含两层意思,“控制”是接口实现类的选择控制权,而“反转”是指这种选择控制权从调用类转移到了外部第三方类或容器中。

    BeanFactory、ApplicationContext和WebApplicationContext是Spring框架的3个最核心的接口,框架中其他大部分都是围绕着他们展开、为他们提供支持和服务。Spring提供了一个强大的加载资源的机制,不仅能够通过classpath、file等资源地址前缀识别不同的资源类型,还支持Ant风格带通配符的资源地址。

    本文还讲解了在Spring配置文件中配置Bean的各种知识。