ChatGPT解决这个技术问题 Extra ChatGPT

自动装配在 Spring 中是如何工作的?

我对 inversion of control (IoC) 在 Spring 中的工作方式有些困惑。

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

这会是什么@Autowired

在我的 Controllers 中,我将如何instantiate 获得这项服务的instance

我会做以下事情吗?

UserService userService = new UserServiceImpl();

M
MegaMatt

首先,也是最重要的——所有 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 中,您应该启用 以便扫描类以查找 @Controller、@Service 等注释。

Spring-MVC 应用程序的入口点是 DispatcherServlet,但它对您隐藏,因此应用程序上下文的直接交互和引导发生在幕后。

UserServiceImpl 也应该定义为 bean - 使用 或使用 @Service 注释。由于它将是 UserService 的唯一实现者,因此将被注入。

除了 @Autowired 注解之外,Spring 还可以使用 XML 可配置的自动装配。在这种情况下,所有名称或类型与现有 bean 匹配的字段都会自动注入 bean。事实上,这就是自动装配的最初想法——让字段注入依赖项而无需任何配置。也可以使用其他注解,如@Inject、@Resource。


是的,UserServiceImpl注解了Service,UserService就是接口
默认范围是单例,因此您将只有一个 bean 实例,该实例被注入多个位置。如果您将范围明确定义为“原型”,则将存在多个实例,可能是惰性的(取决于配置)
非常感谢您的帖子,它真的为我清除了一切。关于“由于它将是唯一的实现者或用户服务,它将被注入。” - 如果有多个实现用户服务的类怎么办? Spring 如何知道它应该使用哪个实现?
如果有一个被指定为“主要”,它会使用它。否则会抛出异常
不,userService 只创建一次,它在单例范围内
K
Kulasangar

取决于您是想要注释路由还是 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


那么在 applicationContext.xml 中定义 bean id 有什么用。我们必须用 UserService 类型定义 userService 变量。那么为什么要在 xml 文件中输入。
@viper 他正在谈论连接它我相信
H
Hearen

@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(););
    }
}

这不会编译并且通常是不正确的。 @Autowired 并不意味着“您可以使用类 A 中的 B 类中的所有函数(方法)和变量”。它所做的是将 A 的实例带入 B 的实例中,因此您可以从 B 执行 a.getId()
@dimadima因此,如果他执行 System.out.println("Value of id form A class" + a.getId()); ,而不是像他实际所做的那样,那将更正确。请回复,因为这对我来说很直观,并且根据我目前的理解水平正在解释自动装配。
在 spring 2.5 docs.spring.io/spring-framework/docs/2.5.x/api/org/… 中引入了自动装配注释
为了更好地理解我是新手,@autowired 会使用默认构造函数实例化 A 类吗?如果没有,如果我们使用自动装配,如何在 bean 或服务中实例化值。我猜如果它调用默认构造函数,为什么首先使用自动装配,只需执行 A a = new A()。请说清楚?
@Sameer 通过自动装配依赖项,您可以在单元测试以及控制器、服务和 Dao 类中保存大量样板代码,因为字段的实例化会自动随之而来。无需调用构造函数。
I
Ihor Patsian

@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 ?


I
Ihor Patsian

您只需要使用注解来注解您的服务类 UserServiceImpl

@Service("userService")

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

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

@Autowired
UserService userService;

I
Ihor Patsian

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

UserService userService = new UserServiceImpl();

在介绍 DI 后,您将使用它:

@Autowired
private UserService userService;

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

public class AccController {

    @Autowired
    private UserService userService;
} 

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


t
timwaagh

您可以通过 3 种方法使用 @Autowired 创建实例。

<强> 1。 @Autowired 属性

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

    @Component("userService")
    public class UserService {

        public String getName() {
            return "service name";
        }
    }

    @Component
    public class UserController {

        @Autowired
        UserService userService

    }

在上面的示例中,Spring 在创建 UserController 时查找并注入 userService

<强> 2。 @Autowired 在二传手上

@Autowired 注释可用于 setter 方法。在下面的示例中,当在 setter 方法上使用注解时,会在创建 UserController 时使用 userService 的实例调用 setter 方法:

public class UserController {

    private UserService userService;

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

<强> 3。 @Autowired 关于构造函数

@Autowired 注释也可用于构造函数。在下面的示例中,当在构造函数上使用注解时,会在创建 UserController 时将 userService 的实例作为参数注入构造函数:

public class UserController {

    private UserService userService;

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

P
Pratik Gaurav

简而言之,自动布线,自动布线链接,现在来了谁做这个以及哪种布线的问题。答案是:容器会这样做,并且支持次要类型的布线,原语需要手动完成。

问题:容器如何知道什么类型的接线?

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

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

答案:是的,通过一个注释@Autowired 就可以了。

问题:但是系统怎么知道,我需要选择这种辅助数据?

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


M
Michu93

标准方式:

@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 注释,但它也可以在 setter 或字段上使用。


为什么要为主类创建构造函数?而不是自动装配声明?
k
k13i

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


I
Ihor Patsian

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

然后您可以使用字段注入方法自动连接您的服务。

public class YourController{

 @Autowired
 private UserService userService; 

}

我从帖子 Spring @autowired annotation 中找到了这个