控制反转实例
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的构造方法中