Spring框架中用到的设计模式

发布于:2025-09-13 ⋅ 阅读:(15) ⋅ 点赞:(0)

Spring 框架作为 Java 领域广泛应用的企业级开发框架,巧妙运用了多种设计模式来提升代码的可维护性、可扩展性与灵活性。下面将为大家详细介绍 Spring 中常用的几种设计模式,并结合具体案例进行说明。

工厂模式

  • 原理:工厂模式是一种创建型设计模式,它将对象的创建和使用分离。通过一个工厂类来负责创建对象,这样可以根据不同的条件创建不同类型的对象,提高代码的可维护性和可扩展性。
  • 在 Spring 中的应用:Spring 通过BeanFactoryApplicationContext来创建对象。BeanFactory是 Spring IoC 容器的最基本接口,它负责管理和创建 Bean。ApplicationContextBeanFactory的子接口,提供了更多企业级功能,比如国际化、事件发布等 。在 Spring 配置文件(XML 或注解配置)中定义 Bean 的信息,Spring 容器在启动时会根据这些配置信息,使用工厂模式创建并管理 Bean。例如,在 XML 配置中定义<bean id="userService" class="com.example.service.UserService"/>,Spring 容器会根据这个配置创建UserService的实例。

案例

XML 配置方式:在 applicationContext.xml 中定义一个 UserService 的 Bean。

<bean id="userService" class="com.example.service.UserService"/>

然后在代码中获取该 Bean:

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        com.example.service.UserService userService = context.getBean("userService", com.example.service.UserService.class);
        userService.doSomething();
    }
}

注解配置方式:在 UserService 类上添加 @Service 注解标识它是一个服务 Bean,Spring 会自动扫描并创建实例。

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void doSomething() {
        System.out.println("UserService is doing something.");
    }
}

接着在配置类上添加 @ComponentScan 注解来开启扫描,再通过依赖注入使用该 Bean。

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.ComponentScan;

@SpringBootApplication
@ComponentScan(basePackages = "com.example")
public class Application implements CommandLineRunner {
    private final UserService userService;

    @Autowired
    public Application(UserService userService) {
        this.userService = userService;
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        userService.doSomething();
    }
}

单例模式

  • 原理:单例模式是一种创建型设计模式,确保一个类只有一个实例,并提供一个全局访问点来访问这个实例。这样可以节省系统资源,并且在需要全局统一状态或共享资源时非常有用。
  • 在 Spring 中的应用:在 Spring 中,Bean 的默认作用域是单例(singleton)。这意味着在整个 Spring 容器的生命周期内,对于同一个 Bean 定义,只会创建一个实例。例如,配置一个UserService Bean,无论在多少个地方注入UserService,获取到的都是同一个实例。可以通过@Scope("singleton")注解(或者在 XML 配置中指定scope="singleton" )显式指定 Bean 的作用域为单例,不过默认就是单例,所以通常可以省略。

案例

import org.springframework.stereotype.Service;

@Service
public class CounterService {
    private int count = 0;

    public int increment() {
        return ++count;
    }
}
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class Application implements CommandLineRunner {
    private final CounterService counterService1;
    private final CounterService counterService2;

    @Autowired
    public Application(CounterService counterService1, CounterService counterService2) {
        this.counterService1 = counterService1;
        this.counterService2 = counterService2;
    }

    public static void main(String[] args) {
        SpringApplication.run(Application.class, args);
    }

    @Override
    public void run(String... args) throws Exception {
        System.out.println("Counter value from service1: " + counterService1.increment());
        System.out.println("Counter value from service2: " + counterService2.increment());
        // 输出结果中两个counterService的count值是连续递增的,说明它们是同一个实例
    }
}

策略模式

  • 原理:策略模式是一种行为型设计模式,它定义了一系列算法,将每个算法都封装成一个独立的类,使得它们可以相互替换。这样可以让算法的变化独立于使用算法的客户端,提高代码的灵活性和可维护性。
  • 在 Spring 中的应用:Spring 中的Resource接口及其实现类体现了策略模式。Resource接口用于访问各种资源,比如文件系统资源、类路径资源、网络资源等。不同的实现类(如ClassPathResourceFileSystemResourceUrlResource 等)针对不同类型的资源,实现了不同的资源获取策略。例如,当需要读取类路径下的一个配置文件时,可以使用ClassPathResource,而如果要读取文件系统中的文件,则可以使用FileSystemResource

案例

import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.EncodedResource;
import org.springframework.util.FileCopyUtils;

import java.io.IOException;
import java.io.InputStreamReader;

public class ResourceExample {
    public static void main(String[] args) throws IOException {
        // 获取类路径下的资源
        Resource classPathResource = new ClassPathResource("config.properties");
        EncodedResource encodedClassPathResource = new EncodedResource(classPathResource, "UTF-8");
        String contentClassPath = FileCopyUtils.copyToString(new InputStreamReader(encodedClassPathResource.getResource().getInputStream()));
        System.out.println("ClassPath Resource Content: " + contentClassPath);

        // 获取文件系统中的资源
        Resource fileSystemResource = new FileSystemResource("C:/test.txt");
        EncodedResource encodedFileSystemResource = new EncodedResource(fileSystemResource, "UTF-8");
        String contentFileSystem = FileCopyUtils.copyToString(new InputStreamReader(encodedFileSystemResource.getResource().getInputStream()));
        System.out.println("FileSystem Resource Content: " + contentFileSystem);
    }
}

代理模式

  • 原理:代理模式是一种结构型设计模式,为其他对象提供一种代理以控制对这个对象的访问。代理对象可以在客户端和目标对象之间起到中介作用,在不改变目标对象的情况下,增加一些额外的功能,比如日志记录、权限控制、事务管理等。
  • 在 Spring 中的应用:Spring 的 AOP(面向切面编程)实现依赖于动态代理。Spring 提供了两种动态代理方式:JDK 的反射机制和 CGLIB 库。当目标对象实现了接口时,Spring 默认使用 JDK 动态代理来创建代理对象;当目标对象没有实现接口时,Spring 会使用 CGLIB 库来创建代理对象。通过 AOP,我们可以将一些通用的横切逻辑(如日志记录、事务管理)从业务逻辑中分离出来,以提高代码的可维护性和可复用性。例如,通过定义一个切面类,使用@Before@After等注解来指定在目标方法执行前后要执行的逻辑。

案例

定义一个业务接口和实现类

public interface UserService {
    void addUser();
}
public class UserServiceImpl implements UserService {
    @Override
    public void addUser() {
        System.out.println("Adding user...");
    }
}

定义切面类

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class UserServiceAspect {
    @Around("execution(* com.example.service.UserService.addUser(..))")
    public Object aroundAddUser(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("Before adding user");
        Object result = joinPoint.proceed();
        System.out.println("After adding user");
        return result;
    }
}

配置类开启 AOP 扫描

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackages = "com.example")
@EnableAspectJAutoProxy
public class ApplicationConfig {
}

测试类

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Main {
    public static void main(String[] args) {
        ApplicationContext context = new AnnotationConfigApplicationContext(ApplicationConfig.class);
        UserService userService = context.getBean(UserService.class);
        userService.addUser();
    }
}

模板方法模式

  • 原理:模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,将一些步骤延迟到子类中实现。这样可以使得子类在不改变算法结构的情况下,重新定义算法中的某些步骤,提高代码的复用性。
  • 在 Spring 中的应用:Spring 提供了JdbcTemplateRedisTemplate等模板对象。以JdbcTemplate为例,它封装了 JDBC 操作的通用步骤,如获取数据库连接、创建 SQL 语句、执行 SQL、处理结果集等。开发人员只需要关注具体的 SQL 语句和业务逻辑,而不需要重复编写繁琐的 JDBC 操作代码。JdbcTemplate中定义了一些抽象方法和钩子方法,子类可以根据需要重写这些方法来定制特定的操作。

案例

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.stereotype.Service;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;

@Service
public class UserService {
    private final JdbcTemplate jdbcTemplate;

    @Autowired
    public UserService(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }

    public List<User> getUsers() {
        String sql = "SELECT id, name, age FROM users";
        return jdbcTemplate.query(sql, new RowMapper<User>() {
            @Override
            public User mapRow(ResultSet rs, int rowNum) throws SQLException {
                User user = new User();
                user.setId(rs.getInt("id"));
                user.setName(rs.getString("name"));
                user.setAge(rs.getInt("age"));
                return user;
            }
        });
    }
}

class User {
    private int id;
    private String name;
    private int age;

    // getters and setters
    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

适配器模式

  • 原理:适配器模式是一种结构型设计模式,它将一个类的接口转换成客户希望的另一个接口。使得原本由于接口不兼容而不能一起工作的那些类可以一起工作。
  • 在 Spring 中的应用
    • Spring AOP:在 Spring AOP 中,增强或通知(Advice)使用到了适配器模式。不同类型的通知(如前置通知BeforeAdvice、后置通知AfterAdvice等)需要适配到Advisor接口,以便在目标方法执行的不同阶段执行相应的通知逻辑。
    • Spring MVC:Spring MVC 中,使用适配器模式来适配ControllerDispatcherServlet作为前端控制器,需要调用不同类型的Controller(如基于注解的@Controller、实现Controller接口的类等)。通过适配器,DispatcherServlet可以统一调用不同类型的Controller,而不需要为每种类型的Controller编写不同的调用逻辑。

案例(Spring MVC 中适配器模式示例)

定义一个简单的 Controller 接口和实现类

public interface Controller {
    String handleRequest();
}
public class HelloController implements Controller {
    @Override
    public String handleRequest() {
        return "Hello, Spring MVC!";
    }
}

定义适配器类

import org.springframework.web.servlet.HandlerAdapter;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class CustomHandlerAdapter implements HandlerAdapter {
    @Override
    public boolean supports(Object handler) {
        return handler instanceof Controller;
    }

    @Override
    public ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Controller controller = (Controller) handler;
        String result = controller.handleRequest();
        return new ModelAndView().addObject("message", result);
    }

    @Override
    public long getLastModified(HttpServletRequest request) {
        return 0;
    }
}

配置 Spring MVC

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.handler.SimpleUrlHandlerMapping;
import org.springframework.web.servlet.view.InternalResourceViewResolver;

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

@Configuration
@EnableWebMvc
@ComponentScan(basePackages = "com.example")
public class WebConfig {
    @Bean
    public SimpleUrlHandlerMapping simpleUrlHandlerMapping() {
        Map<String, Object> urlMap = new HashMap<>();
        urlMap.put("/hello", new HelloController());
        SimpleUrlHandlerMapping mapping = new SimpleUrlHandlerMapping();
        mapping.setUrlMap(urlMap);
        return mapping;
    }

    @Bean
    public HandlerAdapter customHandlerAdapter() {
        return new CustomHandlerAdapter();
    }

    @Bean
    public ViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        return resolver;
    }
}

这样,DispatcherServlet就能通过CustomHandlerAdapter适配并调用HelloController的方法。

综上所述,Spring 框架通过合理运用工厂模式、单例模式、策略模式、代理模式、模板方法模式和适配器模式等,让代码结构更加清晰,也更便于开发者进行扩展和维护,为企业级应用开发提供了坚实的基础和高效的开发方式。


网站公告

今日签到

点亮在社区的每一天
去签到