自动装配如何在Spring工作?

时间:2010-06-30 21:26:06

标签: java spring spring-mvc ioc-container autowired

我对IoCSpring)在UserServiceImpl中的工作方式感到有些困惑。

假设我有一个名为UserService的服务类,它实现了@Autowired接口。

这将是Controllers

在我的instantiate中,我如何instance UserService userService = new UserServiceImpl(); 这项服务?

我会这样做吗?

{{1}}

11 个答案:

答案 0 :(得分:648)

首先,也是最重要的 - 所有Spring bean都是托管的 - 它们“活”在容器内,称为“应用程序上下文”。

其次,每个应用程序都有一个指向该上下文的入口点。 Web应用程序有一个Servlet,JSF使用el-resolver等。此外,还有一个应用程序上下文被引导的地方和所有bean - 自动连接。在Web应用程序中,这可以是一个启动监听器。

通过将一个bean的实例放入另一个bean的实例中的所需字段中来实现自动装配。这两个类都应该是bean,即它们应该被定义为存在于应用程序上下文中。

应用程序上下文中的“生活”是什么?这意味着 context 实例化对象,而不是你。即 - 你永远不会让new UserServiceImpl() - 容器找到每个注入点并在那里设置一个实例。

在您的控制器中,您只需拥有以下内容:

@Controller // Defines that this class is a spring bean
@RequestMapping("/users")
public class SomeController {

    // Tells the application context to inject an instance of UserService here
    @Autowired
    private UserService userService;

    @RequestMapping("/login")
    public void login(@RequestParam("username") String username,
           @RequestParam("password") String password) {

        // The UserServiceImpl is already injected and you can use it
        userService.login(username, password);

    }
}

一些注意事项:

  • applicationContext.xml中,您应该启用<context:component-scan>,以便针对@Controller@Service等注释扫描课程。
  • Spring-MVC应用程序的入口点是DispatcherServlet,但它对您是隐藏的,因此应用程序上下文的直接交互和引导发生在场景后面。
  • UserServiceImpl也应该定义为bean - 使用<bean id=".." class="..">或使用@Service注释。由于它将是UserService的唯一实现者,因此将被注入。
  • @Autowired注释外,Spring可以使用XML可配置的自动装配。在这种情况下,所有具有与现有bean匹配的名称或类型的字段都会自动获取注入的bean。实际上,这是自动装配的最初想法 - 在没有任何配置的情况下为字段注入依赖关系。也可以使用其他注释,例如@Inject@Resource

答案 1 :(得分:61)

取决于您是使用注释路由还是bean XML定义路由。

假设您已在applicationContext.xml中定义了bean:

<beans ...>

    <bean id="userService" class="com.foo.UserServiceImpl"/>

    <bean id="fooController" class="com.foo.FooController"/>

</beans>

应用程序启动时会发生自动装配。因此,在fooController中,为了论证而想要使用UserServiceImpl类,您需要注释如下:

public class FooController {

    // You could also annotate the setUserService method instead of this
    @Autowired
    private UserService userService;

    // rest of class goes here
}

当它看到@Autowired时,Spring将查找与applicationContext中的属性匹配的类,并自动注入它。如果您有多个UserService bean,那么您必须确定它应该使用哪个。

如果您执行以下操作:

UserService service = new UserServiceImpl();

除非你自己设置,否则它不会接受@Autowired。

答案 2 :(得分:17)

@Autowired是Spring 2.5中引入的注释,它仅用于注入。

例如:

class A {

    private int id;

    // With setter and getter method
}

class B {

    private String name;

    @Autowired // Here we are injecting instance of Class A into class B so that you can use 'a' for accessing A's instance variables and methods.
    A a;

    // With setter and getter method

    public void showDetail() {
        System.out.println("Value of id form A class" + a.getId(););
    }
}

答案 3 :(得分:9)

@Autowired如何在内部工作?

前 -

class EnglishGreeting {
   private Greeting greeting;
   //setter and getter
}

class Greeting {
   private String message;
   //setter and getter
}

.xml文件如果不使用@Autowired

,它看起来很相似
<bean id="englishGreeting" class="com.bean.EnglishGreeting">
   <property name="greeting" ref="greeting"/>
</bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

如果您使用的是@Autowired,那么

class EnglishGreeting {
   @Autowired //so automatically based on the name it will identify the bean and inject.
   private Greeting greeting;
   //setter and getter
}

.xml文件如果不使用@Autowired

,它看起来很相似
<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>

<bean id="greeting" class="com.bean.Greeting">
   <property name="message" value="Hello World"/>
</bean>

如果仍有疑问,请参阅下面的现场演示

How does @Autowired work internally ?

答案 4 :(得分:4)

您只需要使用注释

注释您的服务类UserServiceImpl
@Service("userService")

Spring容器将在注册为服务时处理此类的生命周期。

然后在您的控制器中,您可以自动连接(实例化)它并使用其功能。

@Autowired
UserService userService;

答案 5 :(得分:1)

Spring依赖注入可以帮助您从类中删除耦合。 而不是像这样创建对象

UserService userService = new UserServiceImpl();

您将在介绍DI

后使用此功能
@Autowired
private UserService userService;

为实现此目的,您需要在ServiceConfiguration文件中创建服务的bean。之后,您需要将该ServiceConfiguration类导入WebApplicationConfiguration类,以便您可以将此自动装配到Controller中。

public class AccController {

    @Autowired
    private UserService userService;
} 

您可以在此处找到基于Java配置的POC example

答案 6 :(得分:1)

标准方式:

@RestController
public class Main {
    UserService userService;

    public Main(){
        userService = new UserServiceImpl();
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

用户服务界面:

public interface UserService {
    String print(String text);
}

UserServiceImpl类:

public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

输出:Example test UserServiceImpl

那是紧密耦合类的一个很好的例子,糟糕的设计例子,并且测试存在问题(PowerMockito也很糟糕)。

现在让我们看一下SpringBoot依赖注入,这是松耦合的好例子:

接口保持不变,

主类:

@RestController
public class Main {
    UserService userService;

    @Autowired
    public Main(UserService userService){
        this.userService = userService;
    }

    @GetMapping("/")
    public String index(){
        return userService.print("Example test");
    }
}

ServiceUserImpl类:

@Component
public class UserServiceImpl implements UserService {
    @Override
    public String print(String text) {
        return text + " UserServiceImpl";
    }
}

输出:Example test UserServiceImpl

现在很容易编写测试:

@RunWith(MockitoJUnitRunner.class)
public class MainTest {
    @Mock
    UserService userService;

    @Test
    public void indexTest() {
        when(userService.print("Example test")).thenReturn("Example test UserServiceImpl");

        String result = new Main(userService).index();

        assertEquals(result, "Example test UserServiceImpl");
    }
}

我在构造函数上显示了@Autowired批注,但它也可以在设置器或字段中使用。

答案 7 :(得分:0)

控制反转的整个概念意味着您无需手工操作实例化对象并提供所有必需的依赖项。 当您使用适当的注释(例如PointInWCS = projectionMatrix.inv() * PointInCCS; )注释类时,Spring将自动为您实例化对象。如果您不熟悉注释,也可以使用XML文件。但是,当您不想加载整个弹簧上下文时,在单元测试中手动实例化类(使用@Service关键字)并不是一个坏主意。

答案 8 :(得分:0)

请记住,您必须通过在弹簧配置文件中添加元素<context:annotation-config/>来启用@Autowired注释。这将注册AutowiredAnnotationBeanPostProcessor,它负责处理注释。

然后您可以使用Field Injection方法自动装配您的服务。

public class YourController{

 @Autowired
 private UserService userService; 

}

我是从帖子Spring @autowired annotation

中找到的

答案 9 :(得分:0)

可以使用3种方法使用@Autowired创建实例

使用@Autowired 启用注释注入后,可以在属性,设置器和构造函数上使用自动装配。

3.1。 @自动连线到属性

注释可以直接在属性上使用,因此无需使用getter和setter:

@Component 公共类控制器{

@Autowired
UserService userService

}

在上面的示例中,Spring在创建FooService时查找并注入fooFormatter。

3.2。 @Autowired在二传手 @Autowired批注可用于setter方法。在下面的示例中,在setter方法上使用注释时,创建FooService时,将使用FooFormatter的实例调用setter方法:

公共类控制器{

private UserService userService;

@Autowired
public void setUserService(UserService userService) {
        this.userService = userService;
}

}

3.3。 @Autowired在构造函数上 @Autowired批注也可以在构造函数上使用。在下面的示例中,当在构造函数上使用注释时,创建FooService时会将FooFormatter的实例作为构造函数的参数注入:

公共类控制器{

private UserDTO Userdto;

@Autowired
public UserService(UserDTO userDTO) {
    this.userDTO = userDTO;
}

}

希望它会对您有所帮助。

答案 10 :(得分:0)

简单来说,自动布线是指自动链接链接,现在出现的问题是谁来进行布线以及哪种布线。 答案是:容器可以做到这一点,并且支持辅助类型的接线,基元需要手动完成。

问题:容器如何知道哪种类型的接线?

答案:我们将其定义为byType,byName,constructor。

问题:我们有没有办法定义自动装配的类型?

答案:是的,只需做一个注释即可@Autowired。

问题:但是系统如何知道,我需要选择这种辅助数据类型?

答案:您将在您的spring.xml文件中或通过对类使用sterotype注释来提供数据,以便容器自己可以为您创建对象。