1 三层架构:
单一职责原则->
- controller:控制层,接收前端发送的请求,对请求进行处理,并相应数据。
- service:业务逻辑层,处理具体的业务逻辑。
- dao:数据访问层(Data Access Object)(持久层),负责数据访问操作,增删改查
目的:复用性强、便于维护、利于拓展
面向接口的思想。
示例:以上篇EmpController.java为例,将其拆封到三层架构:
1.1.DAO:
创建接口:EmpDao.java:
public interface EmpDao {
//获取员工列表数据
public List<Emp> listEmp();
}
实现接口的一种类:EmpDaoA.java:
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
//1.加载解析xml
String file =this.getClass().getClassLoader().getResource("static/emp.xml").getFile();//此处参数为"emp.xml"就不正常运行(有时候)
System.out.println(file);
List<Emp> empList= XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
1.2 Service:
创建接口:EmpService.java
public interface EmpService {
public List<Emp> listEmp();
}
实现类:EmpServiceA.java
public class EmpServiceA implements EmpService{
private EmpDao empDao=new EmpDaoA();
@Override
public List<Emp> listEmp() {
//1.调用DAO获取数据对象
List<Emp>empList= empDao.listEmp();
//2.对数据进行转换
empList.stream().forEach(emp -> {
String gender= emp.getGender();
if("1".equals(gender))
emp.setGender("男");
else
emp.setGender("女");
});
empList.stream().forEach(emp->{
String job= emp.getJob();
if("1".equals(job))
emp.setJob("讲师");
else if("2".equals(job))
emp.setJob("班主任");
else
emp.setJob("就业指导");
});
return empList;
}
}
1.3 Controller:
@RestController
public class EmpController {
private EmpService empService= new EmpServiceA();
@RequestMapping("/listEmp")
public Result list(){
//controller调用service获取数据
List<Emp> empList=empService.listEmp();
//响应
return Result.success(empList);
}
}
2 分层解耦:
- 内聚:软件中各个功能模块内部的功能联系。
- 耦合:衡量软件中各个层/模块之间的依赖、关联的程度。
- 应该做到 高内聚低耦合,最好解除耦合
在上例中:controller层 通过private EmpService empService= new EmpServiceA(); 与service层耦合。 service层通过 “ private EmpDao empDao=new EmpDaoA();”而与DAO层耦合。
为了解耦,引入容器:将对象的创建、配置和生命周期管理从应用代码中分离出来,实现应用程序不同组件之间的解耦。
Spring的核心:
- 控制反转:IOC。对象的创建控制权由程序自身转移到外部(容器)。
- 依赖注入:DI。容器为应用程序提供运行时,所依赖的资源。
- Bean对象:IOC容器中创建、管理的对象。
3 IOC&DI入门:
将上例解耦:
1.IOC: 将 service层、Dao层接口的实现类,交由IOC容器管理:@Component 对应实现类
2.DI: 为controller及service注入运行时依赖的对象:@Autowired 对应成员变量
如果要用一个接口的其他实现,就在要用的实现上注解,不用的注释掉。
如果同时有多个,需要使用@Primary 或 @Qualifier 选定,否则不能启动服务。
@RestController
public class EmpController {
@Autowired//运行时,IOC容器将会提供该类型的bean对象,赋值于该变量
private EmpService empService= new EmpServiceA();
@RequestMapping("/listEmp")
public Result list(){
//controller调用service获取数据
List<Emp> empList=empService.listEmp();
//响应
return Result.success(empList);
}
}
@Component//将当前类交由IOC容器管理,成为容器中的bean
public class EmpServiceA implements EmpService{
@Autowired//运行时,IOC容器将会提供该类型的bean对象,赋值于该变量
private EmpDao empDao;
@Override
public List<Emp> listEmp() {
//1.调用DAO获取数据对象
List<Emp>empList= empDao.listEmp();
//2.对数据进行转换
empList.stream().forEach(emp -> {
String gender= emp.getGender();
if("1".equals(gender))
emp.setGender("男");
else
emp.setGender("女");
});
empList.stream().forEach(emp->{
String job= emp.getJob();
if("1".equals(job))
emp.setJob("讲师");
else if("2".equals(job))
emp.setJob("班主任");
else
emp.setJob("就业指导");
});
return empList;
}
}
@Component//将当前类交由IOC容器管理,成为容器中的bean
public class EmpDaoA implements EmpDao {
@Override//运行时,IOC容器将会提供该类型的bean对象,赋值于该变量
public List<Emp> listEmp() {
//1.加载解析xml
String file =this.getClass().getClassLoader().getResource("static/emp.xml").getFile();//此处参数为"emp.xml"就不正常运行
//System.out.println(file);
List<Emp> empList= XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
3.1 IOC:
Bean的声明:
要把某个对象交给IOC容器管理,需要在对应的类上加一下注释:
注解 | 说明 | 位置 |
---|---|---|
@Component | 声明bean的基础注解 | 不属于以下三类时,用此注解 |
@Controller | @Component的衍生注解 | 标注在控制器类上 |
@Service | @Component的衍生注解 | 标注在业务类上 |
@Repository | @Component的衍生注解 | 标注在数据访问类上(由于与mybatis整合,用的少) |
- 声明bean的时候,可以通过value属性指定bean的名字,如果没有指定,默认为类名首字母小写。
- 使用以上四个注解都可以声明Bean,但在springboot中,声明控制器controllerbean只能用@Controller
Bean组件扫描:
- 申明的bean注解,想要生效,还需要被组件扫描注解@ComponentScan扫描,
- @ComponentScan注解没有显示配置,实际上包含在了启动类声明注解@SpringBootApplication中,默认扫描范围为启动类所在包及其子包
3.2 DI 依赖注入:
- 依赖注入的注解
- @Autowired:默认按照类型自动装配。
- 如果同类型的bean存在多个:
- @Primary
- @Autowired + @Qualifier(“bean的名称”)
- @Resource(name=”bean的名称”)
- @Resource 与 @Autowired 区别
- @Autowired 是Spring框架提供的注解,而@Resource 是JDK提供的注解。
- @Autowired 默认是按照类型注入,而@Resource 默认是按照名称注入。