程序员社区

14. Spring 分层架构

Spring 分层架构

  MVC 设计模式:将程序按照不同的业务功能分成不同的层,多层组件构建起来项目的整体,能做到明确分工且模块之间的低耦合度。

  将 Web 应用程序分为 3 层:Controller 层、Service 层、DAO 层,这三层之间的关系是:Controller层调用Service 层,Service 层调用DAO 层,并且 Service 层和 DAO 层设计为接口,这是一个典型的 MVC 模式后台代码分层结构。

14. Spring 分层架构插图
  在实际项目开发中,经常会通过 IOC 容器来架构程序的分层,实现有两种方式:基于 XML 配置文件基于注解的方式

1. 基于 XML 配置方式

1、创建 Student 实体类

package com.trainingl.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;

import java.util.List;
public class Student {
    private Integer id;
    private String name;
    private Double score;

    public Student(){

    }

    public Student(Integer id, String name, Double score) {
        this.id = id;
        this.name = name;
        this.score = score;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Double getScore() {
        return score;
    }

    public void setScore(Double score) {
        this.score = score;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", score=" + score +
                '}';
    }
}

2、创建 StudentController 类

package com.trainingl.controller;

import com.trainingl.entity.Student;
import com.trainingl.service.StudentService;

public class StudentController {
    private StudentService studentService;

    public Student getUserById(int id){
        return studentService.getStuById(id);
    }
}

3、创建 StudentService 接口以及实现类 StudentServiceImpl

package com.trainingl.service;

import com.trainingl.entity.Student;

public interface StudentService {
    public Student getStuById(Integer id);
}
package com.trainingl.service;

import com.trainingl.dao.StudentDAO;
import com.trainingl.entity.Student;

public class StudentServiceImpl implements StudentService{
    private StudentDAO studentDAO;

    public Student getStuById(Integer id) {
        return studentDAO.getStuById(id);
    }
}

4、创建 StudentDAO 接口以及实现类 StudentDAOImpl

package com.trainingl.dao;

import com.trainingl.entity.Student;

public interface StudentDAO {
    public Student getStuById(Integer id);
}
package com.trainingl.dao;

import com.trainingl.entity.Student;

import java.util.HashMap;
import java.util.Map;

public class StudentDAOImpl implements StudentDAO {

    private static Map<Integer,Student> students;

    static {
        students = new HashMap<Integer, Student>();
        students.put(1,new Student(1,"张三",85.5));
        students.put(2,new Student(2,"李四",90.0));
        students.put(3,new Student(3,"王五",95.0));
    }

    public Student getStuById(Integer id) {
        return students.get(id);
    }
}

5、在 spring.xml 配置 studentController、studentService、studentDAO,并完成依赖注入

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	   http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
    <!--配置StudentController-->
    <bean id="studentController" class="com.trainingl.controller.StudentController">
        <property name="studentService" ref="studentService"></property>
    </bean>
    <!--配置StudentService-->
    <bean id="studentService" class="com.trainingl.service.StudentServiceImpl">
        <property name="studentDAO" ref="studentDAO"></property>
    </bean>
    <!--配置StudentDAO-->
    <bean id="studentDAO" class="com.trainingl.dao.StudentDAOImpl">
    </bean>

</beans>

6、在测试类中获取 studentController 对象,调用方法获取 student 对象

package com.trainingl.test;

import com.trainingl.Annotation.StudentConfiguration;
import com.trainingl.controller.StudentController;
import com.trainingl.entity.Student;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        //1.加载spring容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.获取对象
        StudentController stuController = (StudentController)applicationContext.getBean("studentController");
        System.out.println(stuController.getUserById(1));
    }
}

在这里插入图片描述


2. 基于注解的方式

第一步:将 StudentController、StudentService、StudentDAO 类扫描到 IOC 容器里;

第二步:在类中设置注解完成依赖注入;

1、修改 spring.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
	   http://www.springframework.org/schema/context
	   http://www.springframework.org/schema/context/spring-context-4.3.xsd
">
    <!--将指定包下的类扫描到IOC容器中-->
    <context:component-scan base-package="com.trainingl"></context:component-scan>

</beans>

base-package="com.trainingl" 表示将 com.trainingl 包下所有子包下的类全部扫描到 IOC 容器中,一步即可将所有参与项目的类完成扫描注入。

2、修改 StudentController,添加注解

//@Component
@Controller
public class StudentController {

    @Autowired
    private StudentService studentService;
    
    public Student getUserById(int id){
        return studentService.getStuById(id);
    }
}

对比之前的代码,有两处改动:

  1. 在类名处添加 @Controller 注解,其实添加 @Component 也是完全一样的,因为 @Controller 是 @Component 的子类,但是通常为了程序的可读性,开发过程中都添加的是 @Controller,表示作为该类的一个控制器;
  2. studentService 属性处添加 @Autowired 注解,表示 IOC 容器自动完成装载,默认是以 byType 的方式

3、修改 StudentServiceImpl

//@Component
@Service
public class StudentServiceImpl implements StudentService{
    @Autowired
    private StudentDAO studentDAO;

    public Student getStuById(Integer id) {
        return studentDAO.getStuById(id);
    }
}

注:在类名处添加 @Service 注解,表示该类是业务层。

4、修改 StudentDAOImpl

//@Component
@Repository
public class StudentDAOImpl implements StudentDAO {

    private static Map<Integer,Student> students;

    //模拟初始化数据库
    static {
        students = new HashMap<Integer, Student>();
        students.put(1,new Student(1,"张三",85.5));
        students.put(2,new Student(2,"李四",90.0));
        students.put(3,new Student(3,"王五",95.0));
    }

    public Student getStuById(Integer id) {
        return students.get(id);
    }
}

注:在类名处添加 @Repository 注解,表示该类是数据接口层。

5、运行测试代码

public class Main {
    public static void main(String[] args) {
        //1.加载spring容器
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");
        //2.获取对象
        StudentController stuController = (StudentController)applicationContext.getBean("studentController");
        System.out.println(stuController.getUserById(1));
    }
}

控制台的打印结果和上面相同:
在这里插入图片描述

通过代码可以看出,使用注解的方式可以简化代码,所以实际开发中,推荐使用基于注解的方式来架构分层。

在上面的测试程序中,我们分别给 StudentController、StudentService、StudentDAO 添加了 @Controller@Service@Repository 注解,分别表示控制器、业务层和数据接口层,并且这三个注解与 @Component 没有区别,开发时可以使用任意一个注解,但是为了具有明确的语义性和可读性,我们在开发时,在哪个层用到哪个注解。

前面也提到过类中属性自动装载,默认是通过 byType 的方式,还可以使用 byName 的方式,使用 byName 的方式需要结合 @Qualifier 注解一起使用。

注意:我们在类中添加注解时,其实设置了默认的 id,即类名首字母小写之后的值就是 id 的默认值

@Service
public class StudentServiceImpl implements StudentService

此时,IOC容器中默认赋值,StudentService 构建 bean 的 id=studentService,与 StudentController 中的属性名正好一致,所以可以完成自动装载。

当然,也可以手动赋值,只需要在类名处将 @Service 修改成 @Service("myStudentService"),这时 IOC 容器构建 bean 时的 id = "myStudentService"。所以在自动装载的对象前,也要设置 @Qualifier("myStudentService"),做到严格一致,否则就会报错。

@Controller
public class StudentController {

    @Autowired
    @Qualifier("myStudentController")
    private StudentService studentService;

    public Student getUserById(int id){
        return studentService.getStuById(id);
    }
}
@Service("myStudentController")
public class StudentServiceImpl implements StudentService{
    @Autowired
    private StudentDAO studentDAO;

    public Student getStuById(Integer id) {
        return studentDAO.getStuById(id);
    }
}

因此,@Qualifier() 中的值必须与 @Service() 中的值一致,才能完成自动装载。

赞(0) 打赏
未经允许不得转载:IDEA激活码 » 14. Spring 分层架构

一个分享Java & Python知识的社区