在我们项目开发中,可以将代码分为三层:
- Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
- Service:业务逻辑层。处理具体的业务逻辑。
- Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
基于三层架构的程序执行流程:
- 前端发起的请求,由Controller层接收(Controller响应数据给前端)
- Controller层调用Service层来进行逻辑处理(Service层处理完后,把处理结果返回给Controller层)
- Serivce层调用Dao层(逻辑处理过程中需要用到的一些数据要从Dao层获取)
- Dao层操作文件中的数据(Dao拿到的数据会返回给Service层)
控制翻转
控制翻转:inversion of control,IOC,对象创建的控制权由程序自身转移到外部容器。传统来将,我们要创建一个对象,就是在程序中new自己new一个对象,而现在要一个对象的话去容器找。
在之前的入门案例中,要把某个对象交给IOC容器管理,需要在类上添加一个注解:@Component
而Spring框架为了更好的标识web应用程序开发当中,bean对象到底归属于哪一层,又提供了@Component的衍生注解:
- @Controller (标注在控制层类上)
- @Service (标注在业务层类上)
- @Repository (标注在数据访问层类上)
- Controller层:
@RestController //@RestController = @Controller + @ResponseBody
public class EmpController {
@Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量
private EmpService empService ;
@RequestMapping("/listEmp")
public Result list(){
//1. 调用service, 获取数据
List<Emp> empList = empService.listEmp();
//3. 响应数据
return Result.success(empList);
}
}
- Service层:
@Service
public class EmpServiceA implements EmpService {
@Autowired //运行时,从IOC容器中获取该类型对象,赋值给该变量
private EmpDao empDao ;
@Override
public List<Emp> listEmp() {
//1. 调用dao, 获取数据
List<Emp> empList = empDao.listEmp();
//2. 对数据进行转换处理 - gender, job
empList.stream().forEach(emp -> {
//处理 gender 1: 男, 2: 女
String gender = emp.getGender();
if("1".equals(gender)){
emp.setGender("男");
}else if("2".equals(gender)){
emp.setGender("女");
}
//处理job - 1: 讲师, 2: 班主任 , 3: 就业指导
String job = emp.getJob();
if("1".equals(job)){
emp.setJob("讲师");
}else if("2".equals(job)){
emp.setJob("班主任");
}else if("3".equals(job)){
emp.setJob("就业指导");
}
});
return empList;
}
}
Dao层:
@Repository
public class EmpDaoA implements EmpDao {
@Override
public List<Emp> listEmp() {
//1. 加载并解析emp.xml
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
System.out.println(file);
List<Emp> empList = XmlParserUtils.parse(file, Emp.class);
return empList;
}
}
要把某个对象交给IOC容器管理,需要在对应的类上加上如下注解之一:
注解 | 说明 | 位置 |
---|---|---|
@Controller | @Component的衍生注解 | 标注在控制器类上 |
@Service | @Component的衍生注解 | 标注在业务类上 |
@Repository | @Component的衍生注解 | 标注在数据访问类上(由于与mybatis整合,用的少) |
@Component | 声明bean的基础注解 | 不属于以上三类时,用此注解 |
依赖注入
依赖注入:dependency injection,DI,容器为应用程序提供运行时所依赖的资源,成为依赖注入(autowired注释)前面我们提到IOC控制反转,就是将对象的控制权交给Spring的IOC容器,由IOC容器创建及管理对象。IOC容器创建的对象称为bean对象。
在入门程序案例中,使用了@Autowired这个注解,完成了依赖注入的操作。
@Autowired注解,默认是按照类型进行自动装配的(去IOC容器中找某个类型的对象,然后完成注入操作)。
拿入门程序举例:在EmpController运行的时候,就要到IOC容器当中去查找EmpService这个类型的对象,而我们的IOC容器中刚好有一个EmpService这个类型的对象,所以就找到了这个类型的对象完成注入操作。如果在IOC容器中,实现了多个相同类型的bean对象,会出现程序运行会报错。
如何解决上述问题呢?Spring提供了以下几种解决方案:
- @Primary
- @Qualifier
- @Resource
使用@Primary注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现。
使用@Qualifier注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称。当需要创建多个相同类型的 bean 并希望仅使用属性装配其中一个 bean 时,可以使用 @Qualifier 注解和 @Autowired 指定应该装配哪个 bean 来消除歧义。 @Qualifier注解不能单独使用,必须配合@Autowired使用。
@Autowired
@Qualifier("userDaoA")
private UserDao userDao;
使用@Resource注解:Resource是j2ee的注解,默认按 byName模式自动注入。@Resource有两个中重要的属性:name和type。name属性指定bean的名字,type属性则指定bean的类型。因此使用name属性,则按byName模式的自动注入策略,如果使用type属性,则按 byType模式自动注入策略。倘若既不指定name也不指定type属性,Spring容器将通过反射技术默认按byName模式注入。
@Resource(name = "deptMapperA")
private DeptMapper deptMapper;
@Autowird 与 @Resource的区别?
@Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
@Autowired 默认是按照类型注入,而@Resource是按照名称注入