Web基础-分层解耦
三层架构
controller:控制层,接收前端发送的请求,对请求进行处理,并响应数据。
service:业务逻辑层,处理具体的业务逻辑。
dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,包括数据的增、删、改、查。
为什么要对代码进行拆分?
遵循单一职责原则,便于复用、后期维护
分层解耦
耦合:衡量软件中各个层/各个模块的依赖关联程度
内聚:软件中各个功能模块内部的功能联系。
软件设计原则:高内聚低耦合
控制反转:Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转。
依赖注入:Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。
Bean对象:IOC容器中创建、管理的对象,称之为Bean。
实现分层解耦的思路是什么?
将项目中的类交给IOC容器管理(IOC,控制反转)
应用程序运行时需要什么对象,直接依赖容器为其提供(DI,依赖注入)
IOC & DI 入门
1.将Dao及Service层的实现类,交给IOC容器管理。
2.为Controller及Service注入运行时所依赖的对象。
@RestController public class UserController { @Autowired private UserService userService; @RequestMapping("/list") public List<User> list(){ //1.调用service,查询用户信息 List<User> userList = userService.list(); //.... }@Component//将UserServiceImpl添加入IOC容器中 public class UserServiceImpl implements UserService { @Autowired private UserDao userDao; @Override public List<User> findAll() { //1.调用dao获取数据 List<String> lines = userDao.FindAll(); //... }@Conponent//将UserDaoImpl添加入IOC容器中 public class UserDaoImpl implements UserDao { @Override public List<String> FindAll(){ //1.加载并读取user.txt文件,获取用户数据 InputStream in = this.getClass().getClassLoader().getResourceAsStream("user.txt"); ArrayList<String> lines = IoUtil.readLines(in, StandardCharsets.UTF_8,new ArrayList<>()); return lines; } }1.如何将一个类交给IOC容器管理?
@Component (注意:是加在实现类上,而非接口上)
2.如何从IOC容器中找到该类型的bean,然后完成依赖注入?
@Autowired
IOC详解
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:
| 注解 | 说明 | 位置 |
| @Component | 声明bean的基础注解 | 不属于以下三类时,用此注解 |
| @Controller | @Component注解 | 标注在控制层类上 |
| @Service | @Component注解 | 标注在业务层类上 |
| @Repository | @Component注解 | 标注在数据访问层类上(由于与mybatis整合,用的少) |
注意:声明bean的时候,可以通过注解的value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
前面声明bean的四大注解,要想生效,还需要被组件扫描注解@ComponentScan扫描。
该注解虽然没有显式配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication中,默认的扫描范围是启动类所在包及其子包。
1.声明bean注解有哪几个?
@Controller
@Service
@Repository
@Component
2.注意事项
在Springboot集成web开发中,声明控制器bean只能用@Controller。
声明bean的注解要想生效,需要被扫描到,启动类默认扫描当前包及其子包。
DI详解
基于@Autowired进行依赖注入的常见方式有如下三种:
1:属性注入
@RestController public class UserController { @Autowired private UserService userService; //... }优点:代码简洁、方便快速开发
缺点:隐藏了类之间的依赖关系、可能破坏类的封装性。
2: 构造函数注入
@RestController public class UserController { @Autowired//(构造器注入,如果当前类只有一个构造器,可以省略@Autowired注解) private UserService userService; public UserController(UserService userService) { this.userService = userService; } }优点:能清晰地看到类的依赖关系、提高了代码的安全性。
缺点:代码繁琐、如果构造参数过多,可能会导致构造函数臃肿。
注意:如果只有一个构造函数,@Autowired注解可以省略。
3:.setter注入
@RestController public class UserController { @Autowired private UserService userService; public void setUserService(UserService userService) { this.userService = userService; } }优点:保持了类的封装性,依赖关系更清晰。
缺点:需要额外编写setter方法,增加了代码量。
@Autowired注解,默认是按照类型进行注入的。
如果存在多个相同类型的bean,将会报出如下错误:
方案一:@Primary
@Primary @Service public class UserServiceImpl implements UserService { @Override public List<User> list(){ //省略... } }方案二:@Qualifier
@RestController public class UserController{ @Autowired @Qualifier(“userServiceImpl") private UsersService userService; }方案三:@Resource
@RestController public class UserController { @Resource(name = "userServiceImpl") private UserService userService; }1.依赖注入的注解
@Autowired:默认按照类型自动装配
如果同类型的bean存在多个:
@Primary
@Autowired + @Qualifier
@Resource
2.@Resource 与 @Autowired区别?
@Autowired是Spring框架提供的注解,而@Resource是JavaEE规范提供的
@Autowired默认是按照类型注入,而@Resource默认是按照名称注入
