Spring 控制反转(IoC)容器与依赖注入(DI)

一、相关概念
1.容器:管理对象的生命周期(包括对象创建、对象的调用,对象的销毁)管理器,处理对象与对象之间的关系
2.容器提供的服务
 *对象生命周期的管理
 *对象依赖和配置管理
 *对象池和线程池的管理
3.轻量级与重量级容器
轻量级体现在非侵入(类之间的关系上),不需要依赖容器提供的类
重量级有侵入的,
4.IoC(控制反转)
DI(dependency injection) 依赖注入
什么是依赖注入?注入的目的?
依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在 传统的程序设计过程中,通常由调用者来创建被调用者的实例。但在Spring里,创建被调用者的工作不再由调用者来完成,因此称为控制反转;创建被调用者 实例的工作通常由Spring容器来完成,然后注入调用者,因此也称为依赖注入。
5.依赖注入的三种方式
  *接口注入 往往传递的是接口,而不是具体实现
 * 设值注入 通过setter方法设值,没有具体的业务语义,很简洁
 *构造注入  通过构造函数来创建对象,依赖关系体现在构造函数的参数上,
 依赖关系集中
三、Spring初探
1.Spring环境的搭建

本环境采用的是Spring2.0的环境
 1)jar包的引入
 新建一个User Library 命名为spring(任意命名),引入必须要使用的jar文件,如下:
  *%SPRING_HOME%/dist/spring.jar
  *%SPRING_HOME%/lib/jakarta-commons/commons-logging.jar
  *%SPRING_HOME%/lib/log4j/log4j-1.2.14.jar
 2)拷贝spring配置文件和log4j的配置文件到项目src目录下
  *%SPRING_HOME%/samples/jpestore/war/WEB-INF/applicationContext.xml
  *%SPRING_HOME%/samples/jpestore/war/WEB-INF/log4j.properties
 3)添加applicationContext.xml的标签智能提示
 此处主要是导入XML文件的Schema文件,编辑相关XML文档是出现标签的提示
  *window-->Preferecces--->MyEclipse Enterprise Workbench--->Files and Editors---->XML--->XMLCatalog---->右边Add XML Catalog--->打开了 Add XML Catalog Entry 
   Location 选择 %SPRING_HOME%\dist\resources\spring-beans-2.0.xsd   
   KeyType 选择Schema Location
   Key 在自动生成的串后面加上/spring-beans-2.0.xsd  
  然后完成ok
2.Spring IoC快速入门
 1)相关类和接口
 实体类--->Permission
 IPermissionService接口---PermissionServiceImpl实现,持有一个IPermssionDAO类型的引用permissionDAO方便调用DAO的方法
 IPermissionDAO接口----->PermssionDAOImpl实现
 本实例要使用两种方式的注入对PermssionServiceImpl类中permssionDAO的变量完成赋值.
 2)通过get和set方法设值,注入方式
  *首先要在PermissionServiceImpl建立permissionDAO的get和set方法
  *要保证PermissionServiceImpl有一个无参的构造方法.,默认或者手动创建均可
  *applicationContext的配置
  创建一个bean的实例,便于下面注入引用
  "<bean id="permissionDAO" class="yeah.developers.spring.PermissionDAOImpl"></bean>"
  <bean id="permissionService" class="yeah.developers.spring.PermissionServiceImpl">
   //通过get和set方法设值,注入方式
   <property name="permissionDAO" ref="permissionDAO"></property>
  </bean>
 3)通过带参数的构造器实现,每个参数就是一个依赖,也可以通过静态的工厂方法实现
  *首先要保证PermissionServiceImpl有带参的构造方法,用来初始化要通过注入方式赋值的成员变量
  public PermissionServiceImpl(IPermissionDAO permissionDAO) {
   this.permissionDAO = permissionDAO;
  }
  *applicationContext的配置
  <bean id="permissionDAO" class="yeah.developers.spring.PermissionDAOImpl"></bean>
  <bean id="permissionService" class="yeah.developers.spring.PermissionServiceImpl">
   //构造注入方式,
    <constructor-arg ref="permissionDAO"></constructor-arg>
  </bean>
 4)测试
 //读取配置文件
 BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
 //用用过Spring创建的Bean的实例,调用业务方法
 IPermissionService permissionService = (IPermissionService) beanFactory.getBean("permissionService");
 permissionService.addPermission(new Permission());
 
 如果没有构造方法, 又没有get和set方法,譬如单例的情况Spring可以通过静态的工厂方法实现注入.
 
3.Bean处理和BeanWrapper
 BeanWrapper提供了设置和获取属性值(单个的或者是批量的),获取属性描述信息、查询只读或者可写属性等功能
 BeanWrapper封装了一个bean的行为,诸如设置和获取属性值等
  代码示例:
 Class  c = Class.forName("yeah.developers.spring.Permission");
 BeanWrapper bw = new BeanWrapperImpl(c.newInstance());
 bw.setPropertyValue("name", "abc");
 System.out.println(bw.getPropertyType("name"));
 System.out.println(bw.getPropertyValue("name"));
4.JavaBean普通属性注入
 TestBean包含属性,并生成了其对应的get和set方法
  private int intValue;
  private String stringValue;
  private List listValue;
  private Set  setValue;
  private String[] stringArray;
  private Map mapValue;
 配置文件
  <bean id="testBean" class="yeah.developers.spring.TestBean">
   <property name="intValue">
    <value>1</value>
   </property>
   <property name="stringValue">
    <value>string</value>
   </property>
   <property name="listValue">
    <list>
     <value>list1</value>
     <value>list2</value>
    </list>
   </property>
   <property name="setValue">
    <set>
     <value>365</value>
     <value>jerry</value>
     <value>developers@yeah.net</value>
    </set>
   </property>
   <property name="stringArray">
    <list>
     <value>000</value>
     <value>111</value>
     <value>222</value>
    </list>
   </property>  
   <property name="mapValue">
    <map>
     <entry key="key1" value="value1"></entry>
     <entry key="key2" value="value2"></entry>
    </map>
   </property>
  </bean>
 测试
 BeanFactory beanFactory = new ClassPathXmlApplicationContext(
  "applicationContext.xml");
 TestBean testBean = (TestBean) beanFactory.getBean("testBean");
 System.out.println(testBean.getIntValue());
 System.out.println(testBean.getStringValue());
 System.out.println(testBean.getListValue());
 System.out.println(testBean.getSetValue());
 System.out.println(testBean.getStringValue());
 System.out.println(testBean.getMapValue());
5.注册用户自定义的PropertyEditor
 1)继承ProperyEditorSupport,例如实现一个日期类型的转换器
 public class DateConverter extends PropertyEditorSupport {
  String pattern;
  重写public void setAsText(String text)
  public void setAsText(String text){
   SimpleDateFormat sd = new SimpleDateFormat(pattern);
   Date date = sd.parse(text);
   完成之后调用父类的super.setValue(date)
   super.setValue(date);
  }
  public String getPattern() {
   return pattern;
  }
  public void setPattern(String pattern) {
   this.pattern = pattern;
  }
 }
 2)重写public void setAsText(String text)
 3)完成之后调用父类的super.setValue(date);
 4)注册到Spring IOC容器
  *注册自定义的转换器
  <bean id="dateConverter" class="yeah.developers.spring.DateConverter">
  <property name="pattern" value="yyyy-MM-dd"></property>
  </bean>
  *注册到IoC容器
  <bean id="dateConverter_register"   class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  <property name="customEditors">
  <map>
  <entry key="java.util.Date" value-ref="dateConverter"></entry>
  </map>
  </property>
  </bean>
6.配置Spring已经定义好但是没有注册的转换器(CustomDateEditor)
 由于CustomDateEditor 是构造注入,有构造方法
 CustomDateEditor(DateFormat dateFormat, boolean allowEmpty),需要DateFormate的实例
 构造simpleDateFormate通过构造注入方式赋值给CustomDateEditor的成员变量
 <bean name="simpleDateFormat" class="java.text.SimpleDateFormat">
  <constructor-arg value="yyyy-MM-dd"></constructor-arg>
 </bean>
 *创建CustomDateEditor的Bean的实例
 <bean id="dateConverter"
  class="org.springframework.beans.propertyeditors.CustomDateEditor">
  <constructor-arg ref="simpleDateFormat"></constructor-arg>
  <constructor-arg value="true"></constructor-arg>
 </bean>
 *将创建好的CustomDateEditor实例注册到SrpingIOC容器中
 <bean id="dateConverter_register"
  class="org.springframework.beans.factory.config.CustomEditorConfigurer">
  <property name="customEditors">
   <map>
    <entry key="java.util.Date" value-ref="dateConverter"></entry>
   </map>
  </property>
 </bean>
7.bean的作用域
 通过Spring给创建的bean的实例默认为scope="singleton",即一个单例,我们可以通过<bean>标签上的scope属性,灵活控制对象的作用域.
 在没有Servlet容器的时候,Bean只有如下两种作用域
  singleton(默认) 在每个Spring IoC容器中一个bean定义对应一个对象实例
  prototype 一个bean定义对应多个对象实例
 多线程的情况下应该使用prototype,避免多个线程同时对同一个bean对象执行set操作.
  
8.自动装配(AutoWire)
 Spring IoC容器可以自动装配(autowire)相互协作bean之间的关联关系.autowire的方便之处在减少或者消除属性或构造器参数的设置,这样可以给我们的配置文件减减肥.
 在xml配置文件中,autowire一共有五种类型,可以在<bean/>元素中使用autowire属性指定:
  *no  不使用自动装配。必须通过ref元素指定依赖(ref指定到对应的bean id),这是默认设置。由于显式指定协作者可以使配置更灵活、更清晰,因此对于较大的部署配置,推荐采用该设置.如下:
  创建3个类Bean1,Bean2,Bean3,类Bean1有一个Bean2类型的成员变量bean2,类Bean2 有一个Bean3类型的成员变量bean3,下面两种自动装配的测试均采用这几个测试类,
  <bean >
   <property name="bean2" ref="bean2"></property>
  </bean>
  <bean id="bean2" class="yeah.developers.spring.Bean2">
   <property name="bean3" ref="bean3"></property>
  </bean>
  <bean id="bean3" class="yeah.developers.spring.Bean3">
</bean>
  * byName  根据属性名自动装配。此选项将检查容器并根据名字查找与属性完全一致的bean,并将其与属性自动装配,也就是,类里面的实例变量的名字一定要和applicationContext.xml中的定义bean 的id对应,才能自动装配上.
   如果配置文件的<beans>标签中设置Default-autowire="byName":配置文件就可以写成下面这个样子,由Spring IoC容器自动装配
   <bean id="bean1" class="yeah.developers.spring.Bean1"></bean>
   <bean id="bean2" class="yeah.developers.spring.Bean2"></bean>
   <bean id="bean3" class="yeah.developers.spring.Bean3"></bean>
  必须保证Bean类里面的成员变量必须在配置文件里有id与自己变量名相同的对应类型的Bean.
  * byType  如果容器中存在一个与指定属性类型相同的bean,那么将与该属性自动装配。如果存在多个该类型的bean,那么将会抛出异常,并指出不能使用byType方式进行自动装配
  如果配置文件的<beans>标签中设置Default-autowire="byType":配置文件就可以写成下面这个样子,由SpringIoC容器自动装配
  <bean ></bean>
  <bean id="bean22" class="yeah.developers.spring.Bean2"> </bean>
  <bean id="bean33" class="yeah.developers.spring.Bean3"></bean>
  测试代码:
  BeanFactory beanFactory = new ClassPathXmlApplicationContext("applicationContext.xml");
  Bean1 Bean1 = (Bean1) beanFactory.getBean("bean1");
  Bean2 Bean2 = (Bean2) beanFactory.getBean("bean22");
  这样也能完成自动装配,因为Ioc容器中只存在一个与相应的Bean1,Bean2中属性相同的Bean; 
  这种方式下,类里面的实例变量的名字不一定要和applicationContext.xml 中 定义的bean 的ID对应,只要类型能够匹配就可以装配上
 
9.Bean定义的继承
 如下两个类成年人和未成年人类:
 public class Adolecense {
  private int id;
  private String name;
  private String studentCardId;
  //get和set方法省略
 }
 public class Adult {
  private int id;
  private String name;
  private String cardId;
 }
可以看出两个类有共同的属性id,name,Spring Ioc容器依赖注入支持Bean定义继承,如下:
 父Bean需要在其对应的<bean>标签定义abstract="true"的属性
 <bean id="commonBean" abstract="true">
  <property name="id">
   <value>100</value>
  </property>
  <property name="name">
   <value>felix</value>
  </property>
 </bean>
 子Bean需要在其对应的<bean>标签中定义parent=父Bean的ID属性
 <bean id="adult" class="yeah.developers.spring.Adult"
  parent="commonBean">
  <property name="cardId">
   <value>bj001</value>
  </property>
 </bean>
 <bean id="adolecense" class="yeah.developers.spring.Adolecense"
  parent="commonBean">
  <property name="studentCardId">
   <value>bj_stu_001</value>
  </property>
 </bean>
注意:抽象bean定义可作为子bean定义的模板,不能被Spring Ioc容器实例化,子bean会继承父Bean的所有属性,如果子bean中重新设置了与父Bean中相同的属性,那么会覆盖父Bean的属性..
10.国际化
 ApplicationContext接口扩展了MessageSource接口,因而提供了消息处理的功能(i18n或者国际化)。当ApplicationContext被加载时,它会自动在context中查找已定义为MessageSource类型的bean。此bean的名称须为messageSource。
 MessageSource 提供的常用方法:
 String getMessage(String code, Object[] args, String default, Locale loc):用来从MessageSource获取消息的基本方法。如果在指定的locale中没有找到消息,则使用默认的消息。args中的参数将使用标准类库中的MessageFormat来作消息中替换值。
 读取国际化资源文件示例如下
 BeanFactory beanFactory = new ClassPathXmlApplicationContext(
   "applicationContext.xml");
 MessageSource messageSource = (MessageSource) beanFactory.getBean("messageSource");
 String message= messageSource.getMessage("user.name", null, "Resource can not find !", null);
 配置示例如下:
   <bean id="messageSource"
         class="org.springframework.context.support.ResourceBundleMessageSource">
     <property name="basenames">
       <list>
         <value>yeah.developers.spring.MessageResources</value>
       </list>
     </property>
   </bean>
   //此处配置authCheck为了不用每次都通过读取配置文件每次都拿到BeanFactory,然后再拿到MessageSource对象.
   <bean id="authCheck" class="yeah.developers.spring.AuthCheck">
    <property name="messagesource" ref="messageSource"></property>
   </bean>
 AuthCheck类代码:
 public class AuthCheck { 
  MessageSource messagesource; 
  public void setMessagesource(MessageSource messagesource) {
   this.messagesource = messagesource;
  }
  public void check(){
   String message = messagesource.getMessage("user.name", new Object[]{"jerry"}, "Resource can not find !", null);
   System.out.println(message);
  }
 }

 Spring Ioc容器自动创建的messageSource的实例,通过AuthCheck类中MessageSource类型变量的set方法,注入,为属性赋值
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值