春季自动装配是如何工作的?

我有点困惑的控制反转 (IoC)如何在Spring中工作。

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

这是怎样的@Autowired?

在我的Controllers中,我如何instantiateinstance这个服务?

我能做下面的事情吗?

UserService userService = new UserServiceImpl();
406403 次浏览

首先,也是最重要的一点——所有Spring bean都是受管理的——它们“生活”在一个容器中,称为“应用程序上下文”。

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

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

在应用程序上下文中,什么是“生活”?这意味着上下文实例化对象,而不是您。例如——你从来没有使用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也可以使用。

这取决于您是想要注释路由还是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,除非您自己设置它。

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

你只需要用注释注释你的服务类UserServiceImpl:

@Service("userService")

Spring容器将在该类注册为服务时负责其生命周期。

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

@Autowired
UserService userService;

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

如果仍有疑问,请通过下面的现场演示

@Autowired内部如何工作?< / >

控制反转的整个概念意味着您可以从手动实例化对象和提供所有必要的依赖项的苦差事中解脱出来。 当你用合适的注释(例如@Service)注释类时,Spring会自动为你实例化对象。如果您不熟悉注释,也可以使用XML文件代替。然而,当您不想加载整个spring上下文时,在单元测试中手动实例化类(使用new关键字)并不是一个坏主意
Spring依赖注入帮助你从类中移除耦合。 而不是像这样创建对象:

UserService userService = new UserServiceImpl();

你将在引入DI之后使用它:

@Autowired
private UserService userService;

为了实现这一点,您需要在ServiceConfiguration文件中创建服务的bean。之后,你需要导入ServiceConfiguration类到你的WebApplicationConfiguration类,这样你就可以像这样将bean自动装配到你的控制器中:

public class AccController {


@Autowired
private UserService userService;
}
你可以在这里找到一个基于POC的java配置 # EYZ0。< / p >

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

然后,您可以使用字段注入方法自动装配您的服务。

public class YourController{


@Autowired
private UserService userService;


}

我从Spring @autowired注释的帖子中找到了这个

有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被创建时,setter方法会被userService的实例调用:

public class UserController {


private UserService userService;


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

3.构造函数上的@Autowired

@Autowired注释也可以用于构造函数。在下面的例子中,当注释用于构造函数时,userService的实例在创建UserController时被注入到构造函数中作为参数:

public class UserController {


private UserService userService;


@Autowired
public UserController(UserService userService) {
this.userService= userService;
}
}
简单地说,自动连接,自动连接,现在的问题是谁做这个和哪种连接。 答案是:容器做这个,次要类型的连接是支持的,原语需要手动完成

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

答:我们将其定义为byType,byName,构造函数。

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

答:是的,它通过一个注释@Autowired来实现。

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

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

标准方法:

@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";
}
}

输出:# EYZ0

这是一个很好的紧密耦合类的例子,糟糕的设计示例,并且在测试时会出现问题(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";
}
}

输出:# EYZ0

现在写测试就很简单了:

@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或field。