Wednesday, October 6, 2010

Spring v3.0.2 Learning Note 7 - Constructor-based dependency injection

基于构造器的注入方式

package com.spring.test.dao;

public class PersonDao {

    public void add() {
        System.out.println("This is add() method in DAO layer.");
    }
}
--------------------------------------------------------------------------
package com.spring.test.manager.impl;

import com.spring.test.dao.PersonDao;
import com.spring.test.manager.IPersonService;

public class PersonManager implements IPersonService {

    private PersonDao personDao;
    private String name;

    public PersonManager() {
    }

    public PersonManager(PersonDao personDao, String name) {
        super();
        this.personDao = personDao;
        this.name = name;
    }

    @Override
    public void save() {
        personDao.add();
        System.out.println("name is " + name);
    }

}

该类的构造函数有2个属性,一个是类PersonDao,一个是String类型的变量。spring关于构造器注入的配置如下:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    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-3.0.xsd">

    <bean id="personDao" class="com.spring.test.dao.PersonDao" />
    <bean id="personService" class="com.spring.test.manager.impl.PersonManager">
        <constructor-arg index="0" type="com.spring.test.dao.PersonDao"
            ref="personDao" />
        <constructor-arg index="1" type="java.lang.String"
            value="name string" />
    </bean>
</beans>
这是关于constructor-arg的设置,其作用就是通过构造器注入依赖的对象或基本数据类型的值。
 index从0开始计数,其顺序要与类中的参数一一对应。

测试类:
package com.spring.test.junit;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
import org.springframework.context.support.AbstractApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.spring.test.manager.IPersonService;

public class PersonServiceTest {

    @BeforeClass
    public static void setUpBeforeClass() throws Exception {
    }

    @AfterClass
    public static void tearDownAfterClass() throws Exception {
    }

    @Test
    public void test() {
        AbstractApplicationContext ctx = new ClassPathXmlApplicationContext(
                "spring.xml");
        IPersonService personService = (IPersonService) ctx
                .getBean("personService");
        personService.save();
    }

}
运行该测试类,可看到正确的注入结果。

基于构造器的注入还是基于Setter方式的注入?
推荐采用Setter的注入方式,以下内容来自spring的参考文档

Constructor-based or setter-based DI?

Since you can mix both, Constructor- and Setter-based DI, it is a good rule of thumb to use constructor arguments for mandatory dependencies and setters for optional dependencies. Note that the use of a @Required annotation on a setter can be used to make setters required dependencies.
The Spring team generally advocates setter injection, because large numbers of constructor arguments can get unwieldy, especially when properties are optional. Setter methods also make objects of that class amenable to reconfiguration or re-injection later. Management through JMX MBeans is a compelling use case.
Some purists favor constructor-based injection. Supplying all object dependencies means that the object is always returned to client (calling) code in a totally initialized state. The disadvantage is that the object becomes less amenable to reconfiguration and re-injection.
Use the DI that makes the most sense for a particular class. Sometimes, when dealing with third-party classes to which you do not have the source, the choice is made for you. A legacy class may not expose any setter methods, and so constructor injection is the only available DI.


No comments:

Post a Comment