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

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

@Autowired会怎么做?

在我的控制器中,我如何实例化这个服务的实例?

我能做下面的事情吗?

UserService userService = new UserServiceImpl();

当前回答

有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;
    }
}

其他回答

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

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

有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;
    }
}

标准方法:

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

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

@Service("userService")

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

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

@Autowired
UserService userService;