控制反转实例

控制反转实例

User

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
package user.model;

public class User {
private String name;
private String content;

public User() {
// default constructor for spring mapping
// Spring中不可以省略空构造方法
}

public User(String name, String content) {
this.name = name;
this.content = content;
}

public String getName() {
return name;
}

public String getContent() {
return content;
}

public void setContent(String content) {
this.content = content;
}

public void setName(String name) {
this.name = name;
}

}

UserDao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package user.model;

import java.util.List;

public interface UserDao {

boolean contains(String key);

User get(String key);

void put(User user);

List<User> getAll();

void delete(String key);
}

UserDaoFactory

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package user.model;

import org.springframework.beans.factory.FactoryBean;
import org.springframework.stereotype.Component;

@Component //Component同时只能标一个,不然会报错
public class UserDaoFactory implements FactoryBean<UserDao> {
// 返回一个UserMockDao对象
@Override
public UserDao getObject() {
System.out.println("使用工厂模式创建一个UserDao的组件");
return new UserMockDao();
}

// 返回一个UserMockDao类型
@Override
public Class<?> getObjectType() {
return UserMockDao.class;
}

// 多个Controller用到UserMockDao时,只需要创建一个,共享
@Override
public boolean isSingleton() {
return true;
}
}

UserMockDao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
package user.model;

import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/*
* DAO - Data Access Object, 用户实现和管理数据访问的对象,比如访问数据库等
*/

//@Component // 告诉Spring这是一个组件,可以用来注入到其他对象里
public class UserMockDao implements UserDao {

// 这可能会用数据库访问,文件访问的逻辑替换

private final HashMap<String, User> users = new HashMap<>();

public UserMockDao() {
// 模拟数据,之后会补充具体数据库的使用
users.put("lzh", new User("lzh","master"));
users.put("pkj", new User("pkj", "electric mouse"));

System.out.println("创建UserMockDao!");
}

// 数据访问接口
@Override
public boolean contains(String key) {
return users.containsKey(key);
}

@Override
public User get(String key) {
return users.get(key);
}

@Override
public void put(User user) {
users.put(user.getName(),user);
}

@Override
public List<User> getAll() {
return new ArrayList<>(users.values());
}

@Override
public void delete(String key) {
users.remove(key);
}
}

Application

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package user;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

// 告诉Spring从这里启动
@SpringBootApplication
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

// 初始化所有的组件,并且根据依赖关系,把每个组件所依赖的其他组件初始化,然后注入!

/*
1.创建UserController --> new UserController(UserDao); --> 需要另外一对象(组件) UserDao
2.先创建UserMockDao --> 创建UserController
*/
}

UserController

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
package user;

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import user.model.User;
import user.model.UserDao;

import java.util.ArrayList;
import java.util.List;

// 告诉Spring这是个Controller
// 资源的控制,资源的接口合集
// Controller本身也是一个Component
@RestController
public class UserController {

// 依赖于UserMockDao,需要注入UserMockDao的实例
// UserDao泛型也可以
private UserDao userDao;

// 使用构造方法进行注入
public UserController(UserDao userDao) {
this.userDao = userDao;
System.out.println("创建UserController!");
}

/**
* 响应 GET /users 这样的请求
* 查询用户列表
* @return 所有用户列表
*/
@GetMapping("/users")
List<User> listUsers() {
return new ArrayList<>(userDao.getAll());
}

/**
* 响应 GET /users/{name}
* 通过User的name查询具体User对象
* @param name
* @return name确定User对象
*/
@GetMapping("/users/{name}")
// 从path中提取出name
ResponseEntity<User> getUser(@PathVariable String name) {
if (userDao.contains(name)) {
return new ResponseEntity<>(userDao.get(name),HttpStatus.OK);
} else {
return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}


/**
* 响应 POST /users 这样的请求
* 添加一个用户到我们用户列表里
* @param user
* @return 返回创建成功的User对象
*/

/*
@PostMapping("/users")
User newUser(@RequestBody User user) {
users.put(user.getName(),user);
return users.get(user.getName());
}
*/

/**
* 响应 POST /users 这样的请求
* 添加一个用户到我们用户列表里
* @param user
* @return 返回创建成功的User对象
*/
@PostMapping("/users")
ResponseEntity<User> newUser(@RequestBody User user) {
userDao.put(user);
// 创建成功后返回User对象,以及自定义的状态值201
return new ResponseEntity<>(userDao.get(user.getName()), HttpStatus.CREATED);
}


/**
* 响应 PUT /users/{name} 这样的请求
* @param name
* @param updatedUser
* @return 修改之后的User对象
*/
@PutMapping("/users/{name}")
ResponseEntity<User> updateUser(@PathVariable String name,@RequestBody User updatedUser) {
if (userDao.contains(name)) {
User user = userDao.get(name);
user.setContent(updatedUser.getContent());
return new ResponseEntity<>(user,HttpStatus.OK);
} else return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}

/**
* 响应 DELETE /users/{name} 这样的请求
* 删除 name 确定的User对象
* @param name
*/
@DeleteMapping("/users/{name}")
ResponseEntity<Void> deleteUser(@PathVariable String name) {
if (userDao.contains(name)) {
userDao.delete(name);
return new ResponseEntity<>(HttpStatus.OK);
} else return new ResponseEntity<>(HttpStatus.NOT_FOUND);
}
}

总结

1.UserDao是User系列操作接口的抽象集合,用于处理User相关数据,通过UserMockDao实现具体方法内容,从而实现控制反转,在Controller中使用时
2.@Component只能标注UserMockDao或者UserDaoFactory(否则创建对象时会出现问题):

  • 标注在UserMockDao时,直接生成UserMockDao实例后注入UserController的构造方法中
  • 标注在UserDaoFactory时,采用工厂模式创建UserMockDao对象,然后注入UserController的构造方法中