对于Spring中的控制反转(IoC)是如何工作的,我有点困惑。
假设我有一个名为UserServiceImpl的服务类,它实现了UserService接口。
@Autowired会怎么做?
在我的控制器中,我如何实例化这个服务的实例?
我能做下面的事情吗?
UserService userService = new UserServiceImpl();
对于Spring中的控制反转(IoC)是如何工作的,我有点困惑。
假设我有一个名为UserServiceImpl的服务类,它实现了UserService接口。
@Autowired会怎么做?
在我的控制器中,我如何实例化这个服务的实例?
我能做下面的事情吗?
UserService userService = new UserServiceImpl();
当前回答
标准方法:
@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";
}
}
输出:示例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";
}
}
输出:示例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或field。
其他回答
@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(););
}
}
控制反转的整个概念意味着您无需手动实例化对象并提供所有必要的依赖项。 当你用适当的注释(例如@Service)注释类时,Spring会自动为你实例化对象。如果您不熟悉注释,也可以使用XML文件代替。然而,当您不想加载整个spring上下文时,在单元测试中手动实例化类(使用new关键字)并不是一个坏主意。
首先,也是最重要的一点——所有Spring bean都是受管理的——它们“生活”在一个容器中,称为“应用程序上下文”。
其次,每个应用程序都有一个到该上下文的入口点。Web应用程序有Servlet, JSF使用el-resolver等等。此外,还有一个地方可以引导应用程序上下文并自动连接所有bean。在web应用程序中,这可以是一个启动监听器。
自动装配是通过将一个bean的实例放入另一个bean的实例中的所需字段来实现的。这两个类都应该是bean,也就是说,它们应该被定义为存在于应用程序上下文中。
在应用程序上下文中,什么是“生活”?这意味着实例化对象的是上下文,而不是您。也就是说——你永远不会创建新的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);
}
}
注意事项:
In your applicationContext.xml you should enable the <context:component-scan> so that classes are scanned for the @Controller, @Service, etc. annotations. The entry point for a Spring-MVC application is the DispatcherServlet, but it is hidden from you, and hence the direct interaction and bootstrapping of the application context happens behind the scene. UserServiceImpl should also be defined as bean - either using <bean id=".." class=".."> or using the @Service annotation. Since it will be the only implementor of UserService, it will be injected. Apart from the @Autowired annotation, Spring can use XML-configurable autowiring. In that case all fields that have a name or type that matches with an existing bean automatically get a bean injected. In fact, that was the initial idea of autowiring - to have fields injected with dependencies without any configuration. Other annotations like @Inject, @Resource can also be used.
Spring依赖注入帮助您从类中移除耦合。 而不是像这样创建对象:
UserService userService = new UserServiceImpl();
你将在引入DI之后使用它:
@Autowired
private UserService userService;
为了实现这一点,您需要在ServiceConfiguration文件中创建服务的bean。之后,你需要导入ServiceConfiguration类到你的WebApplicationConfiguration类,这样你就可以像这样将bean自动装配到你的控制器中:
public class AccController {
@Autowired
private UserService userService;
}
您可以在这里找到一个基于POC的java配置 的例子。
@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内部是如何工作的?