IoC
)如何在Spring
中工作。假设我有一个名为
UserServiceImpl
的服务类,它实现了UserService
接口。这应该如何进行 @Autowired
?而在我的
Controllers
中,我应该如何实例化此服务的instance
?我只需要执行以下操作吗?
UserService userService = new UserServiceImpl();
IoC
)如何在Spring
中工作。UserServiceImpl
的服务类,它实现了UserService
接口。这应该如何进行 @Autowired
?Controllers
中,我应该如何实例化此服务的instance
?UserService userService = new UserServiceImpl();
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
等注释。UserServiceImpl
还应被定义为bean,可以使用<bean id=".." class="..">
或使用@Service
注释。既然它是UserService
的唯一实现者,它将被注入。@Autowired
注释之外,Spring还可以使用可通过XML配置的自动装配。在这种情况下,所有具有与现有bean匹配的名称或类型的字段都自动注入一个bean。实际上,这是自动装配的最初想法 - 在没有任何配置的情况下注入具有依赖关系的字段。也可以使用其他注释,如@Inject
、@Resource
。这取决于您想要使用注解路线还是bean XML定义路线。
假设您将bean定义在applicationContext.xml
中:
<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
}
当Spring看到@Autowired
时,它会在applicationContext
中寻找与属性匹配的类,并自动注入它。如果您有多个UserService
bean,则必须明确指定应使用哪一个。UserService service = new UserServiceImpl();
除非您自己设置,否则它不会拾取@Autowired
。
applicationContext.xml
中定义bean id
有什么用?我们必须使用UserService
类型定义userService
变量。那么为什么要在xml
文件中进行条目设置呢? - viper@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()
。 - Dmitry Minkovsky@Autowired
在内部是如何工作的?class EnglishGreeting {
private Greeting greeting;
//setter and getter
}
class Greeting {
private String message;
//setter and getter
}
如果不使用@Autowired
注释,.xml
文件将看起来很相似:
<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
}
.如果没有使用@Autowired
,那么.xml文件看起来会很相似:
<bean id="englishGreeting" class="com.bean.EnglishGreeting"></bean>
<bean id="greeting" class="com.bean.Greeting">
<property name="message" value="Hello World"/>
</bean>
如果仍有疑问,请查看以下实时演示
UserServiceImpl
上加上注解即可:@Service("userService")
Spring容器会负责管理这个类的生命周期,因为它被注册为服务。
然后在您的控制器中,您可以使用自动装配(实例化)来调用并使用其功能:
@Autowired
UserService userService;
Spring依赖注入帮助您从类中消除耦合。不要像这样创建对象:
UserService userService = new UserServiceImpl();
@Autowired
private UserService userService;
ServiceConfiguration
文件中创建您的服务的bean。之后,您需要将该 ServiceConfiguration
类导入到您的 WebApplicationConfiguration
类中,以便您可以像这样自动装配该bean到您的控制器中:public class AccController {
@Autowired
private UserService userService;
}
使用 @Autowired
,您可以有三种方法创建实例。
1. 通过在属性上标注 @Autowired
此注解可直接用于属性上,因此无需使用 getter 和 setter:
@Component("userService")
public class UserService {
public String getName() {
return "service name";
}
}
@Component
public class UserController {
@Autowired
UserService userService
}
UserController
时寻找并注入 userService
。
@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;
}
}
@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";
}
}
输出:示例测试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";
}
}
输出:示例测试 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。
<context:annotation-config/>
以启用 @Autowired
注解。这将注册 AutowiredAnnotationBeanPostProcessor
,它会处理注解的处理。public class YourController{
@Autowired
private UserService userService;
}
我从帖子Spring @autowired注解中发现了这个。