对于Spring中的控制反转(IoC)是如何工作的,我有点困惑。
假设我有一个名为UserServiceImpl的服务类,它实现了UserService接口。
@Autowired会怎么做?
在我的控制器中,我如何实例化这个服务的实例?
我能做下面的事情吗?
UserService userService = new UserServiceImpl();
对于Spring中的控制反转(IoC)是如何工作的,我有点困惑。
假设我有一个名为UserServiceImpl的服务类,它实现了UserService接口。
@Autowired会怎么做?
在我的控制器中,我如何实例化这个服务的实例?
我能做下面的事情吗?
UserService userService = new UserServiceImpl();
当前回答
控制反转的整个概念意味着您无需手动实例化对象并提供所有必要的依赖项。 当你用适当的注释(例如@Service)注释类时,Spring会自动为你实例化对象。如果您不熟悉注释,也可以使用XML文件代替。然而,当您不想加载整个spring上下文时,在单元测试中手动实例化类(使用new关键字)并不是一个坏主意。
其他回答
你只需要用annotation注释你的服务类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内部是如何工作的?
标准方法:
@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。
有3种方法可以使用@Autowired创建实例。
1. @Autowired on Properties
注释可以直接用于属性,因此不需要getter和setter:
@Component("userService")
public class UserService {
public String getName() {
return "service name";
}
}
@Component
public class UserController {
@Autowired
UserService userService
}
在上面的例子中,当创建UserController时,Spring会查找并注入userService。
2. @自动连接设置
@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;
}
}
这取决于您是想要注释路由还是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。