Spring是一个基于Java的企业级应用程序开发框架,它使用了多种设计模式来实现其各种特性和功能。本文将介绍一些在Spring中使用的常见设计模式以及相应的代码示例和说明。

单例模式

单例模式是Spring中最常用的设计模式之一。在ApplicationContext中,Bean默认为单例模式。当我们创建一个Bean时,默认情况下它就是单例的。这意味着当Bean被请求时,Spring会返回相同的实例。下面是一个示例代码:

public class MyBean {
// ...
} @Configuration
public class AppConfig { @Bean
public MyBean myBean() {
return new MyBean();
} }

在上面的代码中,myBean()方法返回了MyBean类的实例,这个实例将作为单例对象存在于ApplicationContext中。

在Spring AOP中,切面默认为单例模式。这意味着切面对象只会创建一次,并与所有目标对象共享。下面的代码演示了如何在Spring AOP中配置一个单例切面:

@Aspect
@Component
public class LoggingAspect { @Before("execution(* com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
// ...
} }

这里,LoggingAspect类用@Aspect注解进行了标注,它包含了@Before通知,该通知将在com.example.service包中的所有方法执行前执行。由于LoggingAspect是一个@Component,所以它将被Spring自动扫描并创建一个单例实例。

在Spring MVC中,控制器(Controller)也通常是单例的。下面是一个简单的控制器类示例:

@Controller
public class UserController {
@Autowired
private UserService userService; @GetMapping("/users/{id}")
public ResponseEntity<User> getUserById(@PathVariable Long id) {
User user = userService.getUserById(id);
return ResponseEntity.ok(user);
} }

工厂模式

在Spring框架中工厂模式是一种常用的模式之一。下面我将介绍Spring中使用工厂模式的几个具体示例:

BeanFactory

Spring 的核心容器是BeanFactory和其子接口ApplicationContext。其中,BeanFactory使用了工厂模式来创建和管理bean实例。它包含了创建、配置和管理 bean 的所有功能,如下所示:

public interface BeanFactory {
Object getBean(String name) throws BeansException; <T> T getBean(String name, Class<T> requiredType) throws BeansException; boolean containsBean(String name);
}

上述代码中,BeanFactory接口定义了一个getBean()方法,通过传入bean的名称或类型,返回相应的bean实例。这里的getBean()方法就是工厂方法。

FactoryBean

FactoryBean 是 Spring 中另一个使用工厂模式的类。它用于创建复杂的 bean,这些 bean 可以有自己的生命周期、作用域和依赖项等。

public interface FactoryBean<T> {

    T getObject() throws Exception;

    Class<?> getObjectType();

    boolean isSingleton();
}

述代码中,FactoryBean 定义了一个getObject()方法,用于创建并返回一个特定类型的bean。该方法会在应用程序需要访问bean时被调用。

MessageSource

Spring 的国际化支持是基于MessageSource接口实现的。MessageSource为应用程序提供了访问消息资源的方法,如下所示:

public interface MessageSource {
String getMessage(String code, Object[] args, String defaultMessage, Locale locale);
}

上述代码中,getMessage()方法使用工厂模式创建和管理消息资源。它接收消息代码、参数、默认消息和语言环境等参数,并返回相应的消息字符串。

代理模式

在Spring AOP中,代理模式被广泛应用。Spring使用JDK动态代理和CGLIB代理来创建切面。下面是一个简单的使用注解方式配置切面的示例:

@Aspect
@Component
public class LoggingAspect { @Before("execution(public * com.example.service.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
// ...
} }

在上面的代码中,LoggingAspect类使用了@Aspect和@Component注解进行标注,表明它是一个切面,并会被Spring自动扫描并创建代理对象。在@Before通知中,执行方法调用前进行日志记录。

在Spring事务管理中,代理模式也被广泛使用。Spring使用动态代理技术来实现声明式事务管理。下面是一个使用@Transactional注解来声明事务的示例:

@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserRepository userRepository; @Override
@Transactional
public User createUser(User user) {
return userRepository.save(user);
} }

在上面的代码中,createUser()方法使用@Transactional注解标记,Spring将在该方法调用之前创建一个代理对象。当然,这只是一个简单的示例,实际上,在复杂的应用程序中,Spring可以再通过多种方式来声明式事务。

对于Spring MVC中的控制器类,我们也可以使用代理模式来增强其功能,例如在控制器方法之前和之后添加日志记录。下面是一个基于注解方式实现AOP拦截器的示例:

@Aspect
@Component
public class LoggingInterceptor { @Before("execution(* com.example.controller.*.*(..))")
public void logBefore(JoinPoint joinPoint) {
// ...
} @AfterReturning(value = "execution(* com.example.controller.*.*(..))", returning = "result")
public void logAfterReturning(JoinPoint joinPoint, Object result) {
// ...
} }

在上面的代码中,LoggingInterceptor类使用了@Aspect和@Component注解进行标注,表明它是一个切面,并且会被Spring自动扫描并创建代理对象。在@Before通知中,执行方法调用前进行日志记录,在@AfterReturning通知中,执行方法调用后进行日志记录。

观察者模式

Spring中的事件机制也是基于观察者模式实现的。在Spring中,所有的Bean都可以作为事件源发布事件,其他的Bean则可以通过注册监听器来响应这些事件。

ApplicationEventPublisher

ApplicationEventPublisher是Spring 框架中使用观察者模式的一个类。它负责发布事件并通知已注册的监听器。以下是ApplicationEventPublisher的代码示例:

public interface ApplicationEventPublisher {
void publishEvent(ApplicationEvent event);
}

上述代码中,publishEvent()方法用于发布一个事件,并通知已注册的所有监听器。具体的监听器实现可以通过实现ApplicationListener接口来完成。

ApplicationContext 

ApplicationContext是Spring的核心接口之一。它扩展了BeanFactory接口,并在其基础上添加了更多的功能,例如事件发布和提供环境信息等。以下是 ApplicationContext使用观察者模式的代码示例:

public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver { void publishEvent(ApplicationEvent event); String[] getBeanNamesForType(ResolvableType type); <T> Map<String, T> getBeansOfType(Class<T> type) throws BeansException;
}

上述代码中,publishEvent()方法也用于发布事件,并通知已注册的所有监听器。与 ApplicationEventPublisher不同的是,ApplicationContext继承了多个接口,这使得它可以处理各种类型的事件。

BeanPostProcessor 

BeanPostProcessor是Spring框架中一个可插入的回调接口,用于在bean实例化和配置的过程中提供扩展点。以下是BeanPostProcessor使用观察者模式的代码示例:

public interface BeanPostProcessor {
Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;
Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

postProcessBeforeInitialization()和postProcessAfterInitialization()方法分别在bean实例化和初始化之前/之后被调用。可以将这些方法视为钩子函数,可以在其中添加自定义逻辑以修改或扩展bean的默认行为。

责任链模式 

责任链模式是一种行为型设计模式,它允许你将请求沿着处理链传递,直到其中一个处理程序处理该请求。

HandlerInterceptor 

HandlerInterceptor是Spring MVC中使用责任链模式的一个类。它提供了多个方法,例如 preHandle()、postHandle()和afterCompletion()等,可以在请求处理过程中拦截并修改请求和响应。以下是HandlerInterceptor的代码示例:

public interface HandlerInterceptor {

    boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;

    void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable ModelAndView modelAndView) throws Exception; void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
@Nullable Exception ex) throws Exception;
}

上述代码中,HandlerInterceptor提供了三个方法,分别在请求处理前、处理后、以及完成后调用。通过实现这些方法,在请求处理过程中可以执行自定义逻辑,例如验证用户身份、记录日志等。

AbstractRequestLoggingFilter

AbstractRequestLoggingFilter是Spring中使用责任链模式的另一个类。它提供了预先和后续处理请求和响应的方法,可以进行访问日志记录。

以下是 AbstractRequestLoggingFilter的代码示例:

public abstract class AbstractRequestLoggingFilter extends OncePerRequestFilter {

    protected void beforeRequest(HttpServletRequest request, String message) {}

    protected void afterRequest(HttpServletRequest request, String message) {}
}

上述代码中,AbstractRequestLoggingFilter的beforeRequest()和afterRequest()方法分别在请求处理前和处理后调用。通过实现这些方法,可以记录访问日志,包括请求的地址、参数等信息。

HandlerExceptionResolver

HandlerExceptionResolver是Spring MVC中使用责任链模式的另一个类。它提供了多个方法,例如resolveException()和shouldHandle()等,可以处理异常并决定是否继续执行下一个处理器。以下是HandlerExceptionResolver的代码示例:

public interface HandlerExceptionResolver {

    @Nullable
ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, @Nullable Object handler,
Exception ex); boolean shouldHandle(HttpServletRequest request, @Nullable Exception ex);
}

上述代码中,HandlerExceptionResolver的resolveException()方法用于处理异常并返回ModelAndView对象,该对象可以包含自定义的错误页面或其他错误信息。而 shouldHandle()方法则用于判断是否应该由当前处理器处理异常,如果返回false,则会继续执行下一个处理器。

模板方法模式 

模板方法模式是一种行为型设计模式,它定义了一个算法的骨架,并允许子类实现算法中的某些步骤。在Spring框架中,JdbcTemplate和HibernateTemplate就是使用了模板方法模式的例子。

JdbcTemplate 

JdbcTemplate是Spring中使用模板方法模式的一个类。它提供了多个方法,例如 update()、query()等,可以执行SQL语句并返回结果。以下是JdbcTemplate的代码示例:

public class JdbcTemplate {

    public <T> T execute(ConnectionCallback<T> action) throws DataAccessException {
// ...
} // ... public int update(String sql, Object... args) throws DataAccessException {
// ...
} public <T> List<T> query(String sql, Object[] args, RowMapper<T> rowMapper) throws DataAccessException {
// ...
} // ...
}

上述代码中,JdbcTemplate 提供了execute()、update()和query()等方法,它们都使用了模板方法模式。其中,execute()方法是一个模板方法,它接受一个 ConnectionCallback对象并执行其中的doInConnection()方法,该方法由子类实现。而 update()和 query()方法也是模板方法,它们都调用了execute()方法,并传入不同的参数。

HibernateTemplate 

HibernateTemplate是Spring中使用模板方法模式的另一个类。它提供了多个方法,例如 save()、delete()等,可以操作Hibernate实体并返回结果。以下是HibernateTemplate 的代码示例:

public class HibernateTemplate extends HibernateAccessor {

    public Object execute(HibernateCallback<?> action) throws DataAccessException {
// ...
} // ... public void save(Object entity) throws DataAccessException {
// ...
} public void delete(Object entity) throws DataAccessException {
// ...
} // ...
}

上述代码中,HibernateTemplate提供了 execute()、save()和 delete()等方法,它们也都使用了模板方法模式。其中,execute()方法是一个模板方法,它接受一个 HibernateCallback对象并执行其中的doInHibernate()方法,该方法由子类实现。而 save()和delete()方法也是模板方法,它们都调用了execute()方法,并传入不同的参数。

策略模式

在Spring框架中,策略模式被广泛应用于各种场景,例如事务管理、缓存管理等。以下是 Spring中使用策略模式的几个具体示例:

事务管理 

Spring提供了多种事务管理方式,其中之一就是基于策略模式实现的。该模式下,开发人员需要将不同的事务属性(如传播行为、隔离级别等)封装到TransactionDefinition 接口的实现类中,并将其作为参数传递给PlatformTransactionManager的方法。以下是一个示例代码:

public class TransactionalTest {

    private PlatformTransactionManager transactionManager;

    public void setTransactionManager(PlatformTransactionManager transactionManager) {
this.transactionManager = transactionManager;
} public void doTransactional() {
DefaultTransactionDefinition definition = new DefaultTransactionDefinition();
definition.setPropagationBehavior(TransactionDefinition.PROPAGATION_REQUIRED);
definition.setIsolationLevel(TransactionDefinition.ISOLATION_READ_COMMITTED); TransactionStatus status = transactionManager.getTransaction(definition); try {
// 执行事务操作
transactionManager.commit(status);
} catch (Exception e) {
transactionManager.rollback(status);
}
}
}

上述代码中,TransactionalTest类使用了策略模式来管理事务。它将 DefaultTransactionDefinition对象作为参数传递给PlatformTransactionManager的方法,并在try-catch块中执行事务操作。

缓存管理

Spring 提供了多种缓存管理方式,其中之一就是基于策略模式实现的。该模式下,开发人员需要将不同的缓存属性(如缓存类型、缓存超时时间等)封装到CacheManager和Cache 接口的实现类中,并将其作为参数传递给CacheResolver和Cache的方法。以下是一个示例代码:

public class CacheTest {

    private CacheResolver cacheResolver;

    public void setCacheResolver(CacheResolver cacheResolver) {
this.cacheResolver = cacheResolver;
} public void doCached() {
Cache cache = cacheResolver.resolveCache("myCache"); Object value = cache.get("myKey");
if (value == null) {
// 从数据库或其他存储介质中获取数据
value = "myValue"; cache.put("myKey", value);
}
}
}

上述代码中,CacheTest类使用了策略模式来管理缓存。它将CacheResolver对象作为参数传递给resolveCache()方法,并根据缓存的键值对判断是否需要从缓存中获取数据。

往期面试题:

Java面试题:如果你这样做,你会后悔的,两次启动同一个线程~~~

Java面试题:@PostConstruct、init-method和afterPropertiesSet执行顺序?

Java面试题:SimpleDateFormat是线程安全的吗?使用时应该注意什么?

Java面试题:细数ThreadLocal大坑,内存泄露本可避免

Java面试题:请谈谈对ThreadLocal的理解?

Java面试题:为什么HashMap不建议使用对象作为Key?

Java面试题:你知道Spring的IOC吗?那么,它为什么这么重要呢?

Java面试题:线程池内“闹情绪”的线程,怎么办?

Java面试题:Spring Bean线程安全?别担心,只要你不写并发代码就好了!

Java面试题:Spring框架除了IOC和AOP,还有哪些好玩的设计模式?的更多相关文章

  1. Spring框架之IoC和AOP

    Spring框架简介: 2003年2月,Spring框架正式成为一个开源项目,并发布于SourceForge中.致力于Java EE应用的各种解决方案,而并不是仅仅专注于某一层的方案,是企业应用开发的 ...

  2. spring框架DI(IOC)和AOP 原理及方案

    http://www.blogjava.net/killme2008/archive/2007/04/20/112160.html http://www.oschina.net/code/snippe ...

  3. java面试题-spring篇

    这次是关于spring的面试题,和上次一样依旧挑了几个具有代表性的. 一.  谈谈你对 Spring 的理解 Spring 是一个开源框架,为简化企业级应用开发而生.Spring 可以是使简单的 Ja ...

  4. java面试题-常用框架

    Spring Spring 是什么 一个开发框架,一个容器,主要由面向切面AOP 和依赖注入DI两个方面,外加一些工具 AOP和IOC AOP 面向切面 AOP是一种编程思想,主要是逻辑分离, 使业务 ...

  5. Spring框架(3)---IOC装配Bean(注解方式)

    IOC装配Bean(注解方式) 上面一遍文章讲了通过xml来装配Bean,那么这篇来讲注解方式来讲装配Bean对象 注解方式需要在原先的基础上重新配置环境: (1)Component标签举例 1:导入 ...

  6. Spring框架中IoC(控制反转)的原理(转)

    原文链接:Spring框架中IoC(控制反转)的原理 一.IoC的基础知识以及原理: 1.IoC理论的背景:在采用面向对象方法设计的软件系统中,底层实现都是由N个对象组成的,所有的对象通过彼此的合作, ...

  7. Spring框架的IOC核心功能快速入门

    2. 步骤一:下载Spring框架的开发包 * 官网:http://spring.io/ * 下载地址:http://repo.springsource.org/libs-release-local/ ...

  8. (精简)Spring框架的IoC(替代工厂类实现方法)和AOP(定义规则,约定大于配置)

    Spring的核心框架主要包含两个技术,分别用来处理工厂类,以及事务处理和连接管理的. 两大核心概念 1)  IoC:控制反转,在现在的开发中,如果想建立对象并设置属性,是需要先new对象,再通过se ...

  9. Java 横向技术 Spring框架【笔记】

    Java横向技术 spring框架[笔记] Spring 的两大特性是什么? AOP(Aspect Oriented Programming,面向切面编程)与 IOC(Inverse of Contr ...

  10. Spring框架之IOC(控制反转)

    [TOC] 第一章Spring框架简介 IOC(控制反转)和AOP(面向方面编程)作为Spring框架的两个核心,很好地实现了解耦合.所以,简单来说,Spring是一个轻量级的控制反转(IoC)和面向 ...

随机推荐

  1. #三分,分治,计算几何,prim#JZOJ 3860 地壳运动

    题目 \(q\)组询问查询最小生成树,边权为\(u*k1+v*k2\)(\(k1,k2\)每次询问都不同) \(n\leq 35,m\leq 25000,q\leq 200000\) 分析 纯\(\t ...

  2. #线段树,约数#洛谷 3889 [GDOI2014]吃

    题目 有一个长度为\(n\)的数列,现在有\(m\)组询问每次给出区间\([l,r]\),查询 \[\max_{i,j=1}^n\{gcd(a_i,a_j)[(i<l或i>r)且l\leq ...

  3. C# 做个Splash(启动屏幕)

    现在有好些splash的做法,我的比较简单,而且如果你的素材不错的话,应该可以做出很好的效果,这个教程不依赖任何第三方控件,直接使用vs的就行了,下面这个是预览图: 正文开始: 我们首先新建一个win ...

  4. Spring6

    0x00 环境配置 环境: IDEA >= 2022.1.4 JDK 17 Maven 3.8.6 Spring 6.0.0 JUnit 4.13.2 Log4j2 新建模块 spring001 ...

  5. k8s 深入篇———— pod 实战[六]

    前言 pod 实战一下,主要是一些例子. 正文 例子一 pod 实例的选择: NodeSelector:是一个供用户将 Pod 与 Node 进行绑定的字段 NodeName:一旦 Pod 的这个字段 ...

  6. jenkins 持续集成和交付 —— 邮箱服务器配置(九)

    前言 简介邮箱服务器的配置,让jenkins在构建完成后,能有一个邮箱结果通知到我们,这样就不用每次盯着jenkins 看是否完成了. 正文 1.安装插件 安装下面这个插件. Email Extens ...

  7. 鸿蒙HarmonyOS实战-ArkUI组件(Canvas)

    一.Canvas Canvas组件是一种图形渲染组件,它提供了一个画布(canvas),开发者可以在上面绘制各种图形.文本等.Canvas组件通常用于创建游戏.数据可视化等需要动态绘制图形的应用程序. ...

  8. 《C# in depth》第2章C#2.0中的更改(十五)——字面量

    一.概念 在计算机编程中,Literals(字面量)是指在程序中直接表示数据的一种方式.它们是在代码中出现的固定值,与变量不同,它们没有名称或标识符. Literals 可以用于各种数据类型,包括整数 ...

  9. 云小蜜 Dubbo3.0 实践:从微服务迁移上云到流量治理

    ​简介:阿里云-达摩院-云小蜜对话机器人产品基于深度机器学习技术.自然语言理解技术和对话管理技术,为企业提供多引擎.多渠道.多模态的对话机器人服务.17 年云小蜜对话机器人在公共云开始公测,同期在混合 ...

  10. 服务网格 ASM 年终总结:最终用户如何使用服务网格?

    ​简介:本文不打算回顾 Istio 或是阿里云服务网格 ASM 的变化或趋势,我们来聊一聊阿里云 ASM 服务网格,它的最终用户是如何使用服务网格的. 作者:叶剑宏 背景 阿里云服务网格 ASM 于 ...