百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术文章 > 正文

一文读懂Spring框架中的设计模式

ccwgpt 2024-11-19 02:33 29 浏览 0 评论

Spring框架是用于构建企业级应用程序的流行Java框架。它提供了广泛的特性和功能,能够开发高性能、可扩展和可维护的应用程序。在本文中,我们将探讨 Spring 框架中一些最常用的设计模式,并了解它们在实践中的使用方式。

单例模式

在Spring中,默认创建单例对象。这意味着每个 Spring 上下文仅创建特定 bean 的一个实例。这是通过使用单例 bean 范围来实现的。在 Spring 中使用单例范围定义一个 bean 时,Spring 将仅创建该 bean 的一个实例并缓存它。对该 bean 的任何后续请求都将返回缓存的实例。

要在 Spring 中定义单例 bean,可以在类上使用@Component注解或构造函数注解之一(@Service@Repository等)。例如,以下是如何使用@Component注解定义单例 bean:

@Component
public class MySingletonBean {
    // implementation here
}

当Spring容器初始化时,会创建一个MySingletonBean实例并缓存它。对 MySingletonBean 的任何后续请求都将返回缓存的实例。需要注意的是,虽然单例 bean 在每个 Spring 上下文中仅创建一次,但如果该 bean 未设计为线程安全的,则它们仍然可能被多个线程修改状态。因此,通过适当的同步或完全避免可变状态来确保单例 bean 是线程安全的非常重要。

工厂模式

工厂模式是Spring中另一种常用的设计模式。它提供了一个用于在超类中创建对象的接口,但允许子类更改将创建的对象的类型。在Spring中, 工厂模式用于根据应用程序的当前状态动态创建 Bean 实例。Spring 提供了工厂模式的两个主要实现:BeanFactoryApplicationContext

BeanFactory是访问Spring容器的核心接口,负责创建和管理bean对象。BeanFactory 使用许多不同的策略来创建和管理 bean,包括 单例 和原型 设计模式。

接下来举一个例子说明,假设有一个 UserService 接口和一个实现该接口的 UserServiceImpl 类。我们想要创建一个 UserService 对象并在我们的应用程序中使用它。我们可以在 Spring 配置文件中将 UserServiceImpl 定义为 bean,如下所示:

@Configuration
public class AppConfig {
    @Bean
    public UserService userService() {
        return new UserServiceImpl();
    }
}

现在,当我们想要在应用程序中使用 UserService 对象时,我们可以使用 BeanFactory 从 Spring 容器中获取它:

public class UserController {
    private BeanFactory beanFactory;

    public void setBeanFactory(BeanFactory beanFactory) {
        this.beanFactory = beanFactory;
    }

    public void doSomething() {
        UserService userService = (UserService) beanFactory.getBean("userService");
        // use userService object here
    }
}

在上面的示例中,我们有一个 UserController 类,该类通过其 setter 方法注入了一个 BeanFactory 实例。UserController 类的 doSomething() 方法使用 BeanFactory 从 Spring 容器获取 UserService 对象,然后在应用程序中使用它。

注意,当我们调用BeanFactory的getBean()方法获取UserService对象时,Spring使用Factory模式来创建UserService对象。Spring 创建 UserServiceImpl 类的一个新实例,并使用它可能具有的任何依赖项对其进行初始化。

ApplicationContext接口通过提供附加功能(例如对国际化资源加载事件传播的支持)来扩展 BeanFactory 的功能。ApplicationContext 接口通常用在 Web 应用程序中,它提供附加功能,例如对 Web 范围的支持以及从 ServletContext 获取对象的能力。

下面是我们如何使用ApplicationContext在 Spring 应用程序中创建和管理 bean 对象的示例:

public class UserServlet extends HttpServlet {
    private ApplicationContext applicationContext;

    public void init() throws ServletException {
        applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        UserService userService = (UserService) applicationContext.getBean("userService");
        // use userService object here
    }
}

在上面的示例中,我们创建了一个 UserServlet 类,并在 init() 方法中初始化 ApplicationContext。UserServlet 类的 doGet() 方法使用 ApplicationContext 从 Spring 容器获取 UserService 对象,然后在应用程序中使用它。

模板方法模式

在Spring框架中,模板方法模式被广泛用于各种模板类的实现。这些模板类提供算法或过程的骨架实现,并允许用户根据需要覆盖算法或过程的特定部分。

Spring 中模板方法模式最著名的示例之一是JdbcTemplate类,它提供了一组用于处理关系数据库的便捷方法。

JdbcTemplate 类提供了一个名为execute() 的模板方法,该方法接受一个回调对象,该对象定义要执行的SQL 语句以及要传递给该语句的参数。JdbcTemplate 类负责打开和关闭数据库连接、执行语句以及处理可能发生的任何异常。下面是我们如何使用 JdbcTemplate 类执行简单 SQL 查询的示例:

public class UserDaoImpl implements UserDao {
    private JdbcTemplate jdbcTemplate;

    public void setDataSource(DataSource dataSource) {
        jdbcTemplate = new JdbcTemplate(dataSource);
    }

    public User getUserById(int userId) {
        return jdbcTemplate.queryForObject("SELECT * FROM users WHERE id = ?", new Object[]{userId}, new UserRowMapper());
    }
}

在上面的示例中,我们有一个 UserDaoImpl 类,它使用 JdbcTemplate 执行通过 ID 查询用户的SQL 。JdbcTemplate 的execute() 方法由queryForObject() 方法在内部调用,该方法将回调对象(UserRowMapper 类的实例)传递给execute() 方法。UserRowMapper 类负责将 SQL 查询的结果映射到 User 对象。

请注意,JdbcTemplate 类的execute() 方法使用模板方法模式来提供数据库访问过程的骨架实现,同时允许用户通过提供回调对象来自定义该方法的行为。

Spring 中模板方法模式的另一个示例是AbstractController类,它提供了用于处理 HTTP 请求的控制器类的骨架实现。

AbstractController 类定义了一个名为handleRequestInternal() 的模板方法,Spring 框架调用该方法来处理HTTP 请求。handleRequestInternal() 方法负责处理请求,并返回一个 ModelAndView 对象,其中包含要渲染的视图以及渲染视图时要使用的模型数据。下面是我们如何使用 AbstractController 类处理 HTTP 请求的示例:

public class UserController extends AbstractController {
    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {
        int userId = Integer.parseInt(request.getParameter("userId"));
        User user = userService.getUserById(userId);

        ModelAndView modelAndView = new ModelAndView("userView");
        modelAndView.addObject("user", user);

        return modelAndView;
    }
}

在上面的示例中,我们有一个 UserController 类,它扩展了 AbstractController 类来处理 HTTP 请求。重写 AbstractController 类的 handleRequestInternal() 方法以提供自定义实现,该实现使用 UserService 对象按 ID查询用户,然后返回包含要在视图中呈现的用户数据的 ModelAndView 对象。

代理模式

在Spring框架中,代理模式被广泛用于各种AOP(面向切面编程)功能的实现。AOP 是一种编程范例,允许将横切关注点与应用程序的核心业务逻辑分离。换句话说,它允许开发人员封装应用程序行为的某些方面,并以模块化和可重用的方式将它们应用到多个类或模块。

Spring 中代理模式最常见的示例之一是使用动态代理为服务层中的方法提供声明式事务管理。下面是我们如何使用动态代理来使用 Spring 事务管理的示例:

@Transactional
public void updateEmployee(Employee employee) {
    employeeDao.update(employee);
}

在上面的示例中,@Transactional注解告诉 Spring 将事务管理应用到 updateEmployee() 方法。当调用该方法时,Spring会创建一个动态代理对象,该对象会拦截该方法调用并执行必要的事务管理操作,例如开始事务、提交事务或在发生异常时回滚事务。

Spring中代理模式的另一个例子是使用JDK动态代理和CGLIB代理来实现依赖注入(DI)机制。当使用接口为 DI 配置 bean 时,Spring 创建一个实现该接口的 JDK 动态代理对象,并将方法调用委托给实际的 bean 对象。示例代码:

public interface EmployeeService {
    void updateEmployee(Employee employee);
}

@Service
public class EmployeeServiceImpl implements EmployeeService {
    @Override
    public void updateEmployee(Employee employee) {
        employeeDao.update(employee);
    }
}

@Controller
public class EmployeeController {
    @Autowired
    private EmployeeService employeeService;

    @PostMapping("/employee")
    public void updateEmployee(@RequestBody Employee employee) {
        employeeService.updateEmployee(employee);
    }
}

在上面的示例中,EmployeeController 类依赖于 EmployeeService 接口,该接口由 EmployeeServiceImpl 类实现。创建控制器时,Spring 创建一个实现 EmployeeService 接口的动态代理对象,并将方法调用委托给实际的 EmployeeServiceImpl 对象。这允许 Spring 在运行时注入服务的实际实现,而不需要控制器知道实现。

当使用类为 DI 配置 bean 时,Spring 将创建一个 CGLIB 代理对象,该对象扩展该类并覆盖执行 DI 操作所需的方法。示例代码:

@Service
public class EmployeeService {
    @Autowired
    private EmployeeDao employeeDao;

    public void updateEmployee(Employee employee) {
        employeeDao.update(employee);
    }
}

在上面的示例中,EmployeeService 类依赖于 EmployeeDao 类,该类是使用 @Autowired 注解注入的。创建服务时,Spring 创建一个 CGLIB 代理对象,该对象扩展 EmployeeService 类并重写 updateEmployee() 方法来执行 DI 操作。

装饰器模式

装饰器模式是一种设计模式,允许静态或动态地将行为添加到单个对象,而不影响同一类中其他对象的行为。它用于在运行时扩展或修改对象的行为而不影响其原始结构。

在 Spring 中,装饰器模式在多个地方使用,以提供附加功能而不改变对象的原始行为。Spring 中装饰器模式最常见的示例之一是使用 HandlerInterceptor接口为 Spring MVC 应用程序中的 HTTP 请求处理提供附加行为。示例代码:

public class LoggingInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // Logging logic here
        return true;
    }
    
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        // Logging logic here
    }
    
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        // Logging logic here
    }
}

在上面的示例中,LoggingInterceptor 类实现了 HandlerInterceptor 接口,该接口提供了三个方法,可用于在控制器处理 HTTP 请求之前和之后拦截 HTTP 请求。这允许开发人员向请求处理拦截器添加额外的行为,而无需更改控制器的原始行为。

Spring 中装饰器模式的另一个示例是使用DelegatingFilterProxy类向 Web 应用程序过滤器添加附加行为。示例代码:

public class LoggingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        // Initialization logic here
    }
    
    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        // Logging logic here
        chain.doFilter(request, response);
    }
    
    @Override
    public void destroy() {
        // Cleanup logic here
    }
}

在上面的示例中,LoggingFilter 类实现了 Filter 接口,该接口用于拦截 Web 应用程序中的 HTTP 请求和响应。过滤器通过记录请求和响应数据向请求处理添加附加行为。

观察者模式

观察者模式是一种设计模式,允许一个对象观察另一个对象的变化并对这些变化做出反应。它用于维护相关对象之间的一致性并减少它们之间的耦合。

在 Spring 中,观察者模式被用在多个地方,以允许对象观察其他对象的变化并做出相应的反应。Spring 中观察者模式最常见的示例之一是使用ApplicationEventPublisher接口将事件发布到注册的侦听器。示例代码:

public class Order {
    private List<OrderItem> items;
    private double totalPrice;
    
    // getters and setters
    
    public void addItem(OrderItem item) {
        items.add(item);
        totalPrice += item.getPrice();
        ApplicationEventPublisher publisher = // get ApplicationEventPublisher instance
        publisher.publishEvent(new OrderItemAddedEvent(this, item));
    }
}

public class OrderItemAddedEvent extends ApplicationEvent {
    private Order order;
    private OrderItem item;
    
    public OrderItemAddedEvent(Order order, OrderItem item) {
        super(order);
        this.order = order;
        this.item = item;
    }
    
    // getters and setters
}

public class OrderProcessor implements ApplicationListener<OrderItemAddedEvent> {
    @Override
    public void onApplicationEvent(OrderItemAddedEvent event) {
        // Process the order item added event here
    }
}

在上面的示例中,Order 类包含 OrderItem 对象的列表和totalPrice 字段。当新的 OrderItem 添加到订单中时,将调用 addItem 方法并更新总价。然后,该方法将 OrderItemAddedEvent 发布到 ApplicationEventPublisher 实例,该实例通知所有注册的事件侦听器。

OrderProcessor 类实现 ApplicationListener 接口,并注册为 OrderItemAddedEvent 事件的侦听器。当事件发布时,将调用 onApplicationEvent 方法,该方法根据需要处理该事件。

Spring 中观察者模式的另一个例子是使用@EventListener注解来处理事件。示例代码:

@Component
public class OrderProcessor {
    @EventListener
    public void handleOrderItemAddedEvent(OrderItemAddedEvent event) {
        // Process the order item added event here
    }
}

在此示例中,OrderProcessor 类使用 @Component 进行注解,这使其成为 Spring bean。该类包含一个使用 @EventListener 注解的方法,表示由该方法处理 OrderItemAddedEvent 事件。

当事件发布时,Spring会自动检测带注解的方法并调用它来处理事件。

命令模式

命令模式是一种行为设计模式,它将特定操作的请求与执行该操作的对象分开。该模式允许将请求存储为对象,这些对象可以作为参数传递给其他对象或存储以供以后使用。

在 Spring 中,命令模式在多个地方使用,以允许对象执行命令并在必要时撤消或重做它们。Spring 中命令模式最常见的示例之一是使用JdbcTemplate类来执行数据库查询。示例代码:

@Autowired
private JdbcTemplate jdbcTemplate;

public void updateOrder(Order order) {
    jdbcTemplate.update("UPDATE orders SET status = ? WHERE id = ?", order.getStatus(), order.getId());
}

在此示例中,JdbcTemplate 类用于执行数据库查询以更新数据库中的 Order 对象。JdbcTemplate 类的 update 方法采用 SQL 查询字符串和要在查询中使用的参数数组。

Spring 中命令模式的另一个示例是使用@RequestMapping注解将 HTTP 请求映射到 Spring 控制器中的方法。示例代码:

@Controller
@RequestMapping("/orders")
public class OrderController {
    @Autowired
    private OrderService orderService;

    @RequestMapping(value = "/{id}", method = RequestMethod.GET)
    public String getOrder(@PathVariable("id") Long id, Model model) {
        Order order = orderService.getOrderById(id);
        model.addAttribute("order", order);
        return "orderDetails";
    }
}

在此示例中,OrderController 类使用 @Controller 和 @RequestMapping 注解进行注解,这些注解指定该类是 Spring 控制器,并且所有对“/orders”的 HTTP 请求都应由该控制器中的方法处理。

getOrder 方法使用 @RequestMapping 注解进行注解,该注解指定通过此方法处理对“/orders/{id}”的 HTTP GET 请求。

责任链模式

责任链是一种行为设计模式,允许一组对象按顺序处理请求或事件。在此模式中,链中的每个对象都有机会处理请求或将其传递给链中的下一个对象。

在Spring中,责任链模式被用在多个地方,以允许多个对象以灵活且可扩展的方式处理请求。Spring 中责任链模式最常见的示例之一是使用拦截器来处理 HTTP 请求。示例代码:

@Configuration
public class AppConfig extends WebMvcConfigurerAdapter {

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoggingInterceptor())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/public/**");
        registry.addInterceptor(new AuthorizationInterceptor())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/api/public/**");
    }

    // Other configuration methods...
}

在此示例中,AppConfig 类扩展了WebMvcConfigurerAdapter类并重写 addInterceptors 方法以注册两个拦截器:LoggingInterceptorAuthorizationInterceptor

拦截器对象可以配置一组路径模式,指定它们应该处理哪些请求。在此示例中,两个拦截器都配置为处理对“/api/”的所有请求,除了那些匹配“/api/public/”的请求。

Spring 中责任链模式的另一个示例是使用AOP向 Spring bean 添加行为。示例代码:

@Aspect
@Component
public class LoggingAspect {

    @Before("execution(* com.example.service.*.*(..))")
    public void logBefore(JoinPoint joinPoint) {
        System.out.println("Before calling method: " + joinPoint.getSignature().getName());
    }

    // Other advice methods...
}

在此示例中,LoggingAspect 类使用 @Aspect 和 @Component 注解进行注解,以指示它是一个为 Spring bean 提供横切行为的方面组件。

该方面提供了在 Spring bean 中的方法之前、之后等的方法。

享元模式

亨元模式是一种结构设计模式,允许在多个上下文中共享具有公共状态的对象,从而减少应用程序的总体内存占用。在 Spring 中,在多个地方使用亨元模式来优化内存使用并提高性能。

Spring 中享元模式最常见的示例之一是对 bean使用单例范围。示例代码:

@Service 
@Scope ( "singleton" ) 
public class MyService { 
    // ...
 }

在此示例中,MyService 类使用@Service 进行注解,该注解告诉Spring 该类是一个Spring bean。此外,@Scope 注解用于指定该 bean 应创建为 Singleton,这意味着将仅创建该 bean 的一个实例,并在需要它的应用程序的所有部分之间共享。

解释器模式

解释器模式是一种设计模式,它定义了一种语言的语法并提供了一个解释器来执行该语法。在解释器模式中,语法是使用一组规则或表达式来定义的,解释器通过解释这些表达式来评估语法。

在Spring框架中,解释器模式用于实现Spring表达式语言(SpEL)。SpEL 是一种功能强大的表达式语言,可用于配置和操作 Spring 应用程序中的 bean。SpEL 表达式在运行时计算,可用于将值注入 bean 属性、调用方法以及对数据执行操作。下面是如何使用 SpEL 将值注入 bean 属性的示例:

@Component
 public class  MyService { 

    @Value ( " #{ systemProperties[ 'myProperty' ] } " ) 
    private String myProperty; 

    // ... 

}

在此示例中,@Value注解用于将myProperty系统属性的值注入到MyService类的myProperty的字段中。SpEL 表达式#{ systemProperties['myProperty'] }在运行时计算并检索系统属性的值myProperty

综上所述,设计模式为Spring框架为提供了强大的支持,包括单例模式、工厂模式、模板方法模式、代理模式、装饰器模式和观察者模式等。通过有效地理解和应用这些模式,开发人员可以构建高质量、可扩展、和可维护的应用程序。

相关推荐

盲盒小程序背后的技术揭秘:如何打造个性化购物体验

在2025年的今天,盲盒小程序作为一种新兴的购物方式,正以其独特的魅力和个性化体验吸引着越来越多的消费者。这种将线上购物与盲盒概念相结合的应用,不仅为消费者带来了未知的惊喜,还通过一系列技术手段实现了...

小程序·云开发已支持单日亿级调用量,接口可用率高达99.99%

2019-10-1914:1210月19日,由腾讯云与微信小程序团队联合举办的“小程序·云开发”技术峰会在北京召开。会上,微信小程序团队相关负责人表示“小程序·云开发”系统架构已经支持每天亿级别的...

程序员副业开启模式:8个GitHub上可以赚钱的小程序

前言开源项目作者:JackonYang今天推荐的这个项目是「list-of-wechat-mini-program-list」,开源微信小程序列表的列表、有赚钱能力的小程序开源代码。这个项目分为两部分...

深度科普:盲盒小程序开发的底层逻辑

在当下的数字化浪潮中,盲盒小程序以其独特的趣味性和互动性,吸引着众多消费者的目光。无论是热衷于收集玩偶的年轻人,还是享受拆盒惊喜的上班族,都对盲盒小程序情有独钟。那么,这种备受欢迎的盲盒小程序,其开发...

微信小程序的制作步骤

SaaS小程序制作平台,作为数字化转型时代下的创新产物,不仅将易用性置于设计的核心位置,让非技术背景的用户也能轻松上手,快速制作出功能丰富、界面精美的小程序,更在性能和稳定性方面投入了大量精力,以确保...

携程开源--小程序构建工具,三分钟搞定

前言今天推荐的这个项目是「wean」,一个小程序构建打包工具。在wean之前,大量小程序工具使用webpack进行打包,各种loader、plugin导致整个开发链路变长。wean旨在解...

校园小程序的搭建以及营收模式校园外卖程序校园跑腿校园圈子系统

校园小程序的架构设计主要包括云端架构和本地架构两部分。云端架构方面,采用Serverless架构可以降低技术门槛,通过阿里云、腾讯云等平台提供的云服务,可以实现弹性扩容和快速部署。例如,使用云数据库、...

盲盒小程序开发揭秘:技术架构与实现原理全解析

在2025年的今天,盲盒小程序作为一种结合了线上购物与趣味性的创新应用,正受到越来越多用户的喜爱。其背后的技术架构与实现原理,对于想要了解或涉足这一领域的人来说,无疑充满了神秘与吸引力。本文将为大家科...

月活百万的小程序架构设计:流量暴增秘籍

从小程序到"大"程序的蜕变之路当你的小程序用户量从几千跃升至百万级别时,原有的架构就像一件不合身的衣服,处处紧绷。这个阶段最常遇到的噩梦就是服务器崩溃、接口超时、数据丢失。想象一下,在...

认知智能如何与产业结合?专家学者共探理论框架与落地实践

当前,以大模型为代表的生成式人工智能等前沿技术加速迭代,如何将认知智能与产业结合,成为摆在各行各业面前的一个问题。论坛现场。主办方供图7月4日,2024世界人工智能大会暨人工智能全球治理高级别会议在...

现代中医理论框架

...

认知行为(CBT)中的ABC情绪理论

情绪ABC理论是由美国心理学家阿尔伯特·艾利斯(AlbertEllis1913-2007)创建的理论,A表示诱发性事件(Activatingevent),B表示个体针对此诱发性事件产生的一些信...

说说卡伦霍妮的理论框架,对你调整性格和人际关系,价值很大

01自在今天我主要想说下霍妮的理论框架。主要说三本书,第一本是《我们时代的神经症人格》,第二本是《我们内心的冲突》,第三本是《神经症与人的成长》。根据我的经验,三本书价值巨大,但并不是每个人都能读进去...

供应链管理-理论框架

一个最佳价值的供应链,应该是一个具有敏捷性、适应性和联盟功能(3A)的供应链,其基本要素包括战略资源、物流管理、关系管理以及信息系统,目标是实现速度、质量、成本、柔性的竞争优势。篇幅有...

微信WeUI设计规范文件下载及使用方法

来人人都是产品经理【起点学院】,BAT实战派产品总监手把手系统带你学产品、学运营。WeUI是一套同微信原生视觉体验一致的基础样式库,由微信官方设计团队为微信Web开发量身设计,可以令用户的使用感知...

取消回复欢迎 发表评论: