使用@Inject和@Named注释进行Spring自动装配
在使用@Autowired注释的Spring自动装配中,我们已经看到了容器如何通过使用@Autowired注释对依赖项进行注释来自动解决bean之间的协作(bean依赖项)。或者,我们可以使用@Inject注释在Spring中自动布线。
Spring中的@Inject和@Named注释
Spring 3.0增加了对javax.inject包中包含的JSR-330(Java依赖注入)注释的支持,例如@Inject和@Named。
@Inject用于自动布线,它使我们有机会使用标准注释,而不是像@Autowired这样的Spring特定注释。
如果有多个相同类型的候选者,则@Named注释用于解决冲突。
要使用这些注释,需要javax.inject库,对于Maven的依赖关系如下。
<dependency> <groupId>javax.inject</groupId> <artifactId>javax.inject</artifactId> <version>1</version> </dependency>
使用@Inject注释
我们可以将@Inject注释应用于构造函数。
我们可以将@Inject注释应用于setter方法。
我们可以将@Inject应用于字段。
我们将使用上述所有选项查看@Inject注释的示例。
在setter上使用@Inject注释
使用配置文件进行自动装配时,setter方法上的@Inject注释等效于autowiring =" byType"。
在该示例中,有一个用于下订单的类称为OrderService,可以从商店进行购买。在OrderService类中,必须自动关联商店的依赖关系。
public interface OrderService { public void buyItems(); }
import javax.inject.Inject; import org.springframework.stereotype.Service; @Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on Setter @Inject public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
在类中,使用@Inject注释对setter方法进行自动装配。
public interface IStore { public void doPurchase(); }
import org.springframework.stereotype.Service; @Service public class RetailStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Retail Store"); } }
组态
<?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.service" /> </beans>
由于以与Spring注释相同的方式扫描JSR-330标准注释,因此组件扫描也可以扫描@Inject和@Named注释。
我们可以将以下类与main方法一起使用以读取配置并调用bean方法。
public class App { public static void main( String[] args ){ // create context using configuration ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("appcontext.xml"); OrderService order = context.getBean(OrderServiceImpl.class); order.buyItems(); // close the context context.close(); } }
输出:
17:34:09.769 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'orderServiceImpl' 17:34:09.806 [main] DEBUG org.springframework.beans.factory.support.DefaultListableBeanFactory - Creating shared instance of singleton bean 'retailStore' Doing purchase from Retail Store
在构造函数上使用@Inject注释
使用配置文件自动装配时,bean的构造函数上的@Inject注释等效于autowiring =" constructor"。
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on constructor @Inject public OrderServiceImpl(IStore store){ this.store = store; } public void buyItems() { store.doPurchase(); } }
在字段上使用@Inject注释
使用配置文件进行自动装配时,@ Inject字段上的注释等效于autowiring =" byType"。
@Service public class OrderServiceImpl implements OrderService { // Autowiring on a field @Inject private IStore store; public void buyItems() { store.doPurchase(); } }
@Inject注释与java.util.Optional或者@Nullable
@Inject也可以与java.util.Optional或者@Nullable一起使用。由于@Inject没有必需的属性,因此在某些情况下不能满足依赖关系的情况必须通过使用Optional或者@Nullable来解决,否则在创建bean时会抛出UnsatisfiedDependencyException。
例如,使用@Nullable注解声明被注解的元素在某些情况下可以为null。
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on Setter @Inject public void setStore(@Nullable IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
通过使用@Nullable bean,将完成初始化,但是如果找不到所需的依赖项,则稍后将抛出Null指针专有内容。
使用Optional声明在某些情况下带注释的元素可以为null。
@Service public class OrderServiceImpl implements OrderService { private IStore store; // Autowiring on Setter @Inject public void setStore(Optional<IStore> store) { if(store.isPresent()) this.store = store.get(); } public void buyItems() { store.doPurchase(); } }
使用@Named和@Inject解决冲突
使用@Named注释,可以为应注入的依赖项使用限定名称。
当按类型自动装配时,在这种情况下,Spring容器将无法确定要自动装配哪个bean并抛出NoUniqueBeanDefinitionException。
例如,如果有两个商店的IStore类型为RetailStore和OnlineStore。
@Service public class OnlineStore implements IStore { public void doPurchase() { System.out.println("Doing purchase from Online Store"); } }
然后,我们的示例将失败,因为它无法确定要自动关联的商店。
Exception in thread "main" org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'orderServiceImpl': Unsatisfied dependency expressed through method 'setStore' parameter 0; nested exception is org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.theitroad.springproject.service.IStore' available: expected single matching bean but found 2: onlineStore,retailStore
在这种情况下,可以使用@Named注释来解决冲突,方法是使Bean具有自动装配资格。
@Service public class OrderServiceImpl implements OrderService { private IStore store; @Inject @Named("retailStore") public void setStore(IStore store) { this.store = store; } public void buyItems() { store.doPurchase(); } }
在类中,合格名称用于应使用@Named注释注入的依赖项