IOC/DI学习

@Controller

作用:接收请求,处理响应。

@ResponseBody

类型:方法注解、类注解上面均可

作用:将方法的返回值直接响应,如果返回值的类型是实体对象、集合,将会转为JSON格式响应。

@RestController = @Controller + @ResponseBody

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
public Result list(){
//1、加载并解析XML文件
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
//2、逻辑处理,将前端页面的1修改为男,2修改为女......
empList.stream().forEach(emp -> {
String gender = emp.getGender();
if ("1".equals(gender)){
emp.setGender("男");
}else if ("2".equals(gender)){
emp.setGender("女");
}
String job = emp.getJob();
if ("1".equals(job)){
emp.setJob("讲师");
}else if ("2".equals(job)){
emp.setJob("班主任");
}else if ("3".equals(job)){
emp.setJob("就业指导");
}
});
//3、接收请求,响应数据
return Result.success(empList);
}

数据访问 ===> 解析XML文件

逻辑处理 ===> 将前端页面的一些数据进行合理转换

接收请求,响应数据===> retrun

在进行软件设计的时候类或者方法职责尽可能单一。更利于后期的维护。

三层架构

Controller:控制层,接收前端发送过来的请求,对于其进行处理,并响应数据。

1
2
3
4
5
6
7
8
9
@RestController
public class EmpController {
private EmpService empService = new EmpServiceA();
@RequestMapping("/listEmp")
public Result list(){
List<Emp> empList = empService.listEmp();
return Result.success(empList);
}
}

service:业务逻辑层,处理具体的业务逻辑。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class EmpServiceA implements EmpService {
private empDaoA empDao = new empDaoA();
@Override
public List<Emp> listEmp() {
//Service层调用DAO层的对象
List<Emp> empList = empDao.ListEmp();

empList.stream().forEach(emp -> {
String gender = emp.getGender();
if ("1".equals(gender)){
emp.setGender("男");
}else if ("2".equals(gender)){
emp.setGender("女");
}
return empList;
}
}

dao:数据访问层(持久层),负责数据的访问操作,包括数据的增删改查。

1
2
3
4
5
6
7
8
9
public class empDaoA implements empDao {
@Override
public List<Emp> ListEmp() {
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}

前端发起请求之后,首先会到达Controller层(controller接收到请求之后,要去调用Service进行逻辑处理,得先拿到数据,service层要去调用Dao层,dao层再去操作文件当中的数据,将数据拿到之后,再将数据返回给Service,service拿到数据之后,在进行逻辑处理。再将逻辑处理的结果返回给Controller)controller再给前端响应数据。

Dao层访问文件当中的数据、数据库中的数据、抑或是别人给了一个接口获取的数据,实现的方式有很多,可以面向接口编程,增强程序的灵活性。

Service 层也是类似,面向接口编程。

分层解耦

内聚:软件中各个功能模块内部的功能联系。

耦合:衡量各个层/各个模块之间的关联程度的。

假如上述我们要切换上述Service的实现,将EmpServiceA切换为EmpServiceB,此时,Controller 的代码也得进行改动,我们需要将new的对象切换为EmpServiceB,所以,Service层与Contoller 层的代码耦合了。所以在conroller层取消new一个对象。(但是肯定对报错的)

如何解决上述问题呢?

提供一个容器(存储一些对象EmpServiceA、EmpServiceB……),如果我们(例如Controller)需要使用这些对象,只需要在容器当中查找这些对象,再将这些对象赋值给EmpService。

这里会有两个问题。

1、对象如何交给容器管理?

2、容器如何为程序提供所依赖的资源。

控制反转(IOC):对象创建程序的控制权由程序自身转移到外部(容器),这种思想称为控制反转。

依赖注入(DI):容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

Bean对象:IOC容器中创建、管理的对象称之为bean。

需要完成的任务是Controller层与Service层代码的解耦,Service层与Dao层的代码的解耦。

①将Serveice 层以及DAO层的实现类,交给IOC容器管理。 ===> 需要交给IOC进行管理@component

1
@Component //将当前类交给IOC容器管理,成为IOC容器中的bean

②为Controller层以及Service层运行注入的时候,依赖的对象。 ===> 需要加入@Autowired注解

1
@Autowired//运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 -依赖注入

IOC详解

对象创建程序的控制权由程序自身转移到外部(容器),这种思想称为控制反转。

bean的声明:

要将某一个对象交给IOC容器进行管理,需要在对应的类上加上如下注解之一:

注解 说明 位置
@Component 声明bean的基础注解 不属于以下三类的时候,使用此注解。
@Controller @Component的衍生注解 标注在控制器的类上面
@Service @Component的衍生注解 标注在业务类上面
@Repository @Component的衍生注解 标注在数据访问类上(由于与mybatis整合,用的比较少)
  • 在声明bean的时候,我们可以通过value 属性指定bean的名字,如果没有指定,默认为类名首字母小写。
  • 使用以上四个注解都可以声明bean,但是在springboot集成web开发的时候,声明控制器bean只能使用@Controller

这四个注解声明的bean就一定会生效吗?

涉及到一个bean的组件扫描的问题。

  • 前面声明bean的四大注解,要想生效;还需要被组件扫描注解@componentScan扫描。
  • @componentScan注解虽然没有显示配置,但是实际上已经包含在了启动类声明注解@SpringBootApplication之中,默认的扫描范围是启动类所在的包及其子包。

依赖注入DI详解

容器为应用程序提供运行时,所依赖的资源,称之为依赖注入。

@Autowired注解,默认是通过类型进行的,如果存在多个相同类型的bean,会出现报错。

  • 通过以下的方式可以进行解决

@primary 用来设置bean的优先级

@Qualifier @Qualifier(“empServiceA”)

@Resource


IOC/DI学习
http://example.com/2024/07/07/spr2/
作者
nianjx
发布于
2024年7月7日
许可协议