三层架构
上一篇文章的案例出现问题,进行程序设计以及程序开发时,应该满足单一职责原则,一个类或一个方法,就只做一件事情,只管一块功能,但是上一篇文章却是一个类做了三件事情
上一篇文章的处理逻辑,从组成上看可以分为三个部分:
Controller:控制层。接收前端发送的请求,对请求进行处理,并响应数据。
Service:业务逻辑层。处理具体的业务逻辑。
Dao:数据访问层(Data Access Object),也称为持久层。负责数据访问操作,包括数据的增、删、改、查。
具体流程为:
前端发起请求,由Controller层接收(Controller响应数据给前端)
Controller层调用Service层来进行逻辑处理(Service层处理完后,把处理结果返回给Controller层)
Serivce层调用Dao层(逻辑处理过程中需要用到的一些数据要从Dao层获取)
Dao层操作文件中的数据(Dao拿到的原始数据会返回给Service层)
定义业务逻辑层接口
public interface EmpService {
//获取员工列表
public List<Emp> listEmp();
}
定义数据访问层接口
public interface EmpDao {
//获取员工列表数据
public List<Emp> listEmp();
}
private EmpService empService = new
EmpServiceA()
;是具体定义的EmpServiceA()类private EmpDao empDao = new
EmpDaoA()
;是具体定义的EmpDaoA类
分层解耦
高内聚:一个模块中各个元素之间的联系的紧密程度,如果各个元素(语句、程序段)之间的联系程度越高,则内聚性越高,即 "高内聚"
低耦合指的是:软件中各个层、模块之间的依赖关联程序越低越好
软件开发中应该满足高内聚,低耦合
的特点,但是上述分层的做法却是高耦合
的,例如把业务类变为EmpServiceB时,需要修改controller层中的代码
解决办法
引入控制反转与依赖注入
控制反转: Inversion Of Control,简称IOC。对象的创建控制权由程序自身转移到外部(容器),这种思想称为控制反转,IOC容器中创建、管理的对象,称之为:bean
对象
依赖注入: Dependency Injection,简称DI。容器为应用程序提供运行时,所依赖的资源,称之为依赖注入
例:EmpController程序运行时需要EmpService对象,Spring容器就为其提供并注入EmpService对象
实现步骤:
删除Controller层、Service层中new对象的代码
Service层及Dao层的实现类,交给IOC容器管理,使用Spring提供的注解:
@Component
,就可以实现类交给IOC容器管理为Controller及Service注入运行时依赖的对象,使用Spring提供的注解:
@Autowired
,就可以实现程序运行时IOC容器自动注入需要的依赖对象
IOC细节:
类交给IOC容器管理,使用@Component太宽泛,无法确定bean对象到底归属于哪一层,又提供了@Component的衍生注解(无法确定属于哪一类,例如工具类才用Component):
@Controller (标注在控制层类上)
@Service (标注在业务层类上)
@Repository (标注在数据访问层类上)
但是
@RestController
= @Controller + @ResponseBody,所以控制层不用再单独声明@Repository 了在IOC容器中,每一个Bean都有一个属于自己的名字,可以通过注解的
value
属性指定bean的名字。如果没有指定,默认为类名首字母小写。使用四大注解声明的bean,要想生效,还需要被组件扫描注解
@ComponentScan
扫描,@ComponentScan注解虽然没有显式配置,但是实际上已经包含在了引导类声明注解@SpringBootApplication
中,(默认扫描的范围是SpringBoot启动类所在包及其子包),如果定义的类不在SpringBoot启动类所在包及其子包,手动添加@ComponentScan注解,指定要扫描的包
DI细节:
如果在IOC容器中,存在多个相同类型的bean对象,会报错(不知道该注入哪个对象)解决方案:
使用
@Primary
注解:当存在多个相同类型的Bean注入时,加上@Primary注解,来确定默认的实现使用
@Qualifier
注解:指定当前要注入的bean对象。 在@Qualifier的value属性中,指定注入的bean的名称,@Qualifier注解不能单独使用,必须配合@Autowired
使用使用@Resource注解:是按照bean的名称进行注入。通过name属性指定要注入的bean的名称
@Autowird 与 @Resource的区别:
@Autowired 是spring框架提供的注解,而@Resource是JDK提供的注解
@Autowired 默认是按照类型注入,而@Resource是按照名称注入