使用@Inject和@Named注释进行Spring自动装配

时间:2020-01-09 10:44:30  来源:igfitidea点击:

在使用@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注释注入的依赖项