Spring IoC容器

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring IoC容器相关的知识,希望对你有一定的参考价值。

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();
 }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"  
 xmlns:context="http://www.springframework.org/schema/context"  
 xmlns:p="http://www.springframework.org/schema/p"  
 xmlns:mvc="http://www.springframework.org/schema/mvc"  
 xmlns:aop="http://www.springframework.org/schema/aop"  
 xmlns:tx="http://www.springframework.org/schema/tx"  
 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
 xsi:schemaLocation="http://www.springframework.org/schema/beans  
      http://www.springframework.org/schema/beans/spring-beans-4.0.xsd  
      http://www.springframework.org/schema/context  
      http://www.springframework.org/schema/context/spring-context.xsd  
      http://www.springframework.org/schema/mvc  
      http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
      http://www.springframework.org/schema/aop  
      http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
      http://www.springframework.org/schema/tx 
      http://www.springframework.org/schema/tx/spring-tx-4.0.xsd">
      <!-- 注解扫描包 -->
      <context:component-scan base-package="org.worm.biz"/>
      
      <!-- 避免IE执行AJAX时,返回JSON出现下载文件 -->
      <bean id="mappingJacksonHttpMessageConverter" class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
       <property name="supportedMediaTypes">
        <list>
         <value>text/html;charset=UTF-8</value>
        </list>
       </property>
      </bean>
      <!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->
      <bean class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
       <property name="messageConverters">
        <list>
         <ref bean="mappingJacksonHttpMessageConverter"/>
        </list>
       </property>
      </bean>
       <!-- 定义跳转的文件的前后缀 ,视图模式配置-->  
     <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">  
         <!-- 这里的配置我的理解是自动给后面action的方法return的字符串加上前缀和后缀,变成一个 可用的url地址 -->  
<!--          <property name="prefix" value="/WEB-INF/jsp/" />   -->
<!--          <property name="suffix" value=".jsp" />   -->
     </bean>  
      
      <!-- 访问静态资源 -->
<!--       <mvc:resources location="/images/" mapping="/images/**"/> -->
<!--       <mvc:resources location="/css/" mapping="/css/**"/> -->
<!--       <mvc:resources location="/js/" mapping="/js/**"/> -->
      
       
      <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
    <property name="defaultEncoding" value="utf-8" />
    <!-- 设置文件上传的最大尺寸 -->
       <property name="maxUploadSize" value="10485760000" />
       <property name="maxInMemorySize" value="40960" />
 </bean>
 
 <bean id="car" class="org.worm.biz.Car" 
  p:brand = "红旗CA72"
  p:color = "黑色"
  p:maxSpeed = "200"/>
</beans>

运行结果:

技术分享

通过注解配置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 
*  
*/ 
@Configuration
public 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进行注解。

5、总结

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

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

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




本文出自 “阿酷博客源” 博客,请务必保留此出处http://aku28907.blog.51cto.com/5668513/1793626

以上是关于Spring IoC容器的主要内容,如果未能解决你的问题,请参考以下文章

Spring系列之IOC容器

深入理解Spring的IOC容器

关于Spring——IoC

关于Spring——IoC

Spring IOC源代码具体解释之容器初始化

Spring IOC容器