Spring之IoC

  

      上面的图是Spring的主要模块示意图,IoC属于Spring的Core模块。

       使用Spring中各模块的功能时,首先要在xml中引入模块对应的命令空间。

      

   1.IoC基本概念

      IoC控制翻转,指的是对象的创建及对象生命周期的控制不再由程序本身完成,而是由IoC容器来完成,可以是Spring,也可是EJB。

      由程序区创建对象,例如如下的代码:  

  PersonDao dao = new PersonDaoBean();

      这样dao对象是依赖于代码本身的。IoC是指对象的创建通过Spring中创建,可以基于构造方法或set方法等,将dao的创建交给Spring,代码不再需要去new这样一个对象。

      DI依赖注入,就是在运行期,由外部对象注入到组件中,常常和IoC是一起存在的。

   2.Spring中的bean

      Spring是通过bean来管理对象及实现Ioc的。

  下面的是一个Java Bean的实例: 

public class SpringBeanTest {
    private Action action;
    private String beanName;
    
    public String getBeanName() {
        return beanName;
    }
    public void setBeanName(String name) {
        this.beanName = name;
    }
    public Action getAction() {
        return action;
    }
    public void setAction(Action action) {
        this.action = action;
    }
    
    private void start(){
        System.out.println("get resource for database");
    }
    
    private void destroy(){
        System.out.println("release resource for database");
    }
    
    public void actionTest(){
        System.out.println(action.execute("Kare Smith"));
    }
}

  为了管理这个bean,我们需要在一个xml文件中配置这个bean,以便Spring可以知道这个bean的存在并对它进行控制。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context" 
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
    <bean id = "beanTest" class = "qs.SpringBeanTest" scope="singleton" init-method = "start" destroy-method = "destroy">
        <!-- 指定属性参数 -->
       <property name = "beanName">
          <value>hello</value>
       </property>
        <!-- 注入其他的bean -->
        <property name = "action">
          <ref bean ="upper"/>
       </property>
    </bean>
        
       <bean id = "upper" class = "qs.UpperAction" scope="singleton"/>
</beans>

     上面的JavaBean中还用到了一个类UpperAction,其代码如下: 

public class UpperAction implements Action {
    public String execute(String str) {
        //return (getMessage() + "," + str).toUpperCase() + " in upperAction";
        return str.toUpperCase() + " in upperAction";
    }
}

  下面是对xml中bean的配置参数的解释:

  bean的id属性在整个容器中时唯一的,这个是要注意的。name属性和id属性的不同点是,name属性中可以包含特殊字符,正常情况下还是应该使用id属性。

      bean的作用域;singleton,prototype,还有对应于web的request,session,global session(application)。默认的是singleton,这是需要注意的,处理数据时bean使用默认的singleton是会出问题的。singleton的作用范围是Spring容器,在Spring容器之外是不能保证的。

     

   singleton时Spring容器初始化时会初始bean,检查错误。prototype时getBean时才会去初始化对象。

     lazy-init ="true",大体积且不一定会用到的bean适用,lazy-init尽量不使用。

     bean的init-method方法用于打开,准备好程序所需资源。destroy-method用于资源的释放,需要调用AbstractApplicationContext的close方法。init-method和destroy-method都可以被Spring容器动态地调用。 

  

  下面是对这个bean的测试,看看Spring容器是否能够很好地管理这个bean。

public class SpringBeanTestTest2 {
    private ApplicationContext ctx;
     private SpringBeanTest beanTest;
    @Before
    public void setUp() throws Exception {
        ctx = new ClassPathXmlApplicationContext("bean.xml");
    }

    @After
    public void tearDown() throws Exception {
    }

    @Test
    public void test() {
        beanTest = (SpringBeanTest) ctx.getBean("beanTest");
        beanTest.actionTest();
    }

}

  FileSystemXmlApplicationContext需要指定文件路径,适用性不强。ClassPathXmlApplicationContext会在类路径包括jar包中寻找xml文件,XmlWebApplicationContext用于读取web应用的xml文件并装载。

  更为完善的测试代码应该如下: 

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("/bean.xml")
public class SpringBeanTestTest {

    @Autowired
    @Qualifier("beanTest")
    private SpringBeanTest beanTest;
    @Test
    public void test() {
        beanTest.actionTest();
    }

}

   3.Spring中的注入

   Spring中的注入分为基本类型的注入,如int,String等和对象的注入。基本类型的注入用的是value属性,对象的注入用的是ref属性。

     Spring中的注入可以有三种方式:构造器注入,set方法注入,注解方式注入。

   再看一个java bean的例子:

public class LowerAction {
    
    private String message;
    private List<Integer> testlist;    
    private String [][] arrays;
    private Map<Integer, String> maps;
    private Action action;
    
    public Action getAction() {
        return action;
    }
    public void setAction(Action action) {
        this.action = action;
    }
    public Map<Integer, String> getMaps() {
        return maps;
    }
    public void setMaps(Map<Integer, String> maps) {
        this.maps = maps;
    }
    public String[][] getArrays() {
        return arrays;
    }
    public void setArrays(String[][] arrays) {
        this.arrays = arrays;
    }
    public List<Integer> getTestlist() {
        return testlist;
    }
    public void setTestlist(List<Integer> testlist) {
        this.testlist = testlist;
    }
    public String getMessage() {
        return message;
    }
    //java bean要求有一个无参的构造方法
    public LowerAction(){
    }
    
    public LowerAction(String arg){
        System.out.println(arg);
    }
    
    public void setMessage(String message) {
        this.message = message;
    }

    @Override
    public String execute(String str) {
        return (getMessage() + "," + str).toLowerCase() + ", list is" + getTestlist() + 
                ",arrays:" + arrays[1][1] + ",maps:" + maps.get(new Integer(1)) + "actions:" + action.execute("muu");
    }
}

  在xml中完成注入的例子如下:

  

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xmlns:context="http://www.springframework.org/schema/context" 
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.0.xsd
">
    
    <bean id = "theAction" class = "qs.LowerAction" scope="singleton" >
       <!-- 指定属性参数 -->
       <property name = "message">
          <value>hello</value>
       </property>
        <!-- 注入其他的bean -->
        <property name = "action">
          <ref bean ="upper"/>
       </property>
       <!-- 指定构造器参数 -->
       <constructor-arg index = "0" value ="constructor test"/>
       <!-- 注入集合 -->
       <property name = "testlist">
             <list value-type = "java.lang.Integer">
              <value>1</value>
              <value>2</value>
              <value>3</value>
          </list>
       </property>
        <!-- 注入数组 -->
       <property name = "arrays">
             <array>
                 <array><value>1</value><value>2</value></array>
                 <array><value>3</value><value>4</value></array>
             </array>
       </property>
       <!-- 注入字典 -->
       <property name = "maps">
             <map key-type = "java.lang.Integer" value-type = "java.lang.String">
                 <entry key ="1" value ="2"/>
             </map>
       </property>
     </bean>

</beans>

 4.自动装配及自动检测

  从上面可以看到,通过xml对bean的属性及引用进行装配,如果bean的数量很多,xml文件将会很大,虽然可以将xml文件分成多份,但依然难以维护。自动装配及自动检测就是为了减少xml中的配置信息。

  自动装配autowiring,减少property属性和constructor-arg属性。
  自动检测autodiscovery,让Spring识别哪些类需要被配置为bean,减少了bean属性。

     4.1基于XML的自动装配

  自动装配分为XML和注解2中方式。基于注解的支持以下注解:@Autowired,@Inject,@Resource。

      

       先看基于XML的自动装配,可以有效地减少xml中的property属性和constructor-arg属性。

      

      

  id为kenny的bean使用了byName的自动装配方式,com.spriginaction.springidol.Instrumentalist类中的:

       private Instrument instrument;       

       instrument在使用时会被自动装配为Saxophone。

      

        如果Instrument接口存在多个子类,则byType的自动装配将会失败。

       

  

     4.2基于注解的自动装配

       可以看出基于XML的自动装配还不是很简便,基于注解的自动装配会极大地简化配置工作, 下面是使用注解自动装配的介绍:

       基于注解的支持以下注解:@Autowired,@Inject,@Resource。
  @Autowired(required = "false"),不是必须注入的
       

  @Autowired
  @Autowired @Qualifier("guitar")指定注入bean id为guitar的bean。接口被多个类实现,注入接口时就需要。

       
  @Value注入String和其他基本类型的属性。

       @Autowired默认是按类型装配,@Resource默认是按名称进行装配,名称找不到时再按类型装配。

       @Resource在JDK1.6中已支持,是通用的,@Autowired是Spring自己的注解。

       可以标注在变量上(可以不需要set方法)或者set方法上。

      

       

       

 4.3 自动检测bean

  自动检测bean
  @Component,通用组件  @Component("add") 显示的指明bean的id
  @Controller Spring MVC 的Controller,struts的action
  @Repository  数据仓库,DAO组件
  @Service  业务层,定义为服务

       

       @Component  @Scope("prototype")

       @PostConstruct用于标识bean的init方法

       @PreDestroy用于destroy方法

       自动扫描一般制定一个包,去扫描这个包及子包中的bean。也可以加上过滤器,使得扫描条件更为精确。

      

include-filter将和component-scan的条件取交集,自动扫描Instrument的子类。

      

  include-filter可以和exclude-filter配合使用。

      

posted on 2014-09-27 21:25  lnlvinso  阅读(246)  评论(0编辑  收藏  举报