Spring中的Setter依赖注入
在Spring的依赖注入后,我们已经介绍了依赖注入的概念,在这篇文章中,我们将详细介绍一种依赖注入的类型:Setter在Spring中的依赖注入。
对于另一种类型的依赖注入,构造函数依赖注入在Spring中检查此postConstructor依赖注入
Spring Setter依赖注入
在基于setter的DI中,Spring容器在调用无参数构造函数或者无参数静态工厂方法以实例化bean之后,在bean上调用setter方法。
为了配置基于setter的依赖关系,可以使用XML配置以及注释。我们将看到使用这两种方式进行操作的示例。
Spring Setter依赖注入示例
在该示例中,有一个用于下达订单的类,称为Order,可以从在线商店或者零售商店进行购买。在Order类中,使用setter依赖项注入来注入属性的依赖项。
public interface IStore { public void doPurchase(int items); }
public class OnlineStore implements IStore { public void doPurchase(int items) { System.out.println("Doing online purchase of " + items + " Items"); } }
public class RetailStore implements IStore { public void doPurchase(int items) { System.out.println("Doing purchase of " + items + " Items from a brick and mortar store"); } }
public class Order { private IStore store; private int items; public void setStore(IStore store) { this.store = store; } public void setItems(int items) { this.items = items; } public void buyItems() { store.doPurchase(items); } }
在Order类中,这是两个属性,一个是对Istore类型的引用,另一个是对int的引用。这些属性有setter方法,Spring容器将调用这些方法来设置配置的值。
如果我们使用的是XML配置,那么将按照以下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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Store bean --> <bean id="store" class="com.theitroad.SpringProject.RetailStore" /> <!-- Order bean with dependencies --> <bean id="orderBean" class="com.theitroad.SpringProject.Order"> <property name="store" ref="store" /> <property name="items" value="20" /> </bean> </beans>
为了提供setter依赖项,使用了<property>标签。
- 当依赖关系是另一个bean时,使用" ref"属性。
- 对于任何原始类型或者字符串,都使用"值"属性。
我们可以将以下类与main方法一起使用以读取配置并调用bean方法。
public class App { public static void main( String[] args ){ // create context using configuration ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml"); Order order = (Order) context.getBean("orderBean"); order.buyItems(); // close the context context.close(); } }
如果要使用注释在Spring中配置setter依赖项,则必须对类使用@Service或者@Component注释,以表明它们是Spring托管的组件,并且在完成组件扫描时会自动发现它们。
使用@autowired注释setter方法,以自动注入setter依赖项。
@Service public class OnlineStore implements IStore { public void doPurchase(int items) { System.out.println("Doing online purchase of " + items + " Items"); } }
@Service public class RetailStore implements IStore { public void doPurchase(int items) { System.out.println("Doing purchase of " + items + " Items from a brick and mortar store"); } }
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; @Service public class Order { private IStore store; @Value("20") private int items; @Autowired @Qualifier("onlineStore") public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(items); } }
由于存在两个类型为store的对象,因此已使用@Qualifier注释来告知必须连接哪个bean,否则将出现错误"没有可用的com.theitroad.SpringProject.IStore类型的合格bean"。
自动装配仅适用于引用,因此使用@Value注释提供原始值。
如果要使用XML设置组件扫描以自动发现Bean,则可以使用以下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.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="com.theitroad.SpringProject" /> </beans>
XML配置现在没有任何依赖性,只有<context:component-scan>标记。
基于构造函数或者基于setter的依赖项注入
根据Spring文档,基于构造器的DI优于基于设置器的DI。
"由于可以混合使用基于构造函数的DI和基于setter的DI,因此,将构造函数用于强制性依赖项,将setter方法或者配置方法用于可选性依赖项是一个很好的经验法则。
Spring团队通常提倡构造函数注入,因为它可以使应用程序组件实现为不可变对象,并确保所需的依赖项不为null。此外,注入构造函数的组件总是以完全初始化的状态返回到客户端(调用)代码。
Setter注入主要应仅用于可以在类中分配合理的默认值的可选依赖项。否则,必须在代码使用依赖项的任何地方执行非空检查。"