Spring框架广泛使用了设计模式,这些模式提高了框架的灵活性、扩展性和可维护性。以下是Spring框架中一些常用的设计模式:
在Spring框架中,单例模式是一种确保某个类仅有一个实例,并提供一个全局访问点来获取该实例的设计模式。在Spring中,单例模式的应用非常广泛,并且是Bean默认的作用域。以下是对Spring中单例模式的详细介绍:
Spring使用单例模式来管理其Bean的实例化。当在Spring配置文件或者使用注解定义一个Bean时,除非明确指定作用域(scope),否则Spring容器默认会将该Bean定义为单例。
在Spring中,可以通过指定Bean的scope
属性来设置Bean的作用域。常见的作用域有以下几种:
singleton
:单例模式,一个Spring IOC容器中只有一个Bean的实例,这是默认作用域。prototype
:原型模式,每次请求都会创建一个新的Bean实例。request
:对于每一个HTTP请求,都会创建一个Bean实例。session
:每个HTTP Session都会有一个Bean实例。global session
:全局HTTP Session作用域,仅在Portlet上下文中有效。当Spring容器启动时,它将在创建容器的过程中实例化所有的单例Bean。这一过程称为饿汉式加载(eager loading)。这与懒汉式加载(lazy loading)相对,后者只有在第一次请求Bean时才创建实例。
<bean id="myBean" class="com.example.MyClass" scope="singleton"/>
@Component // 或者其他如@Service, @Repository注解,它们都隐式地定义了类为singleton scope
public class MyClass {
}
Spring 提供了丰富的机制来管理单例Bean的生命周期,包括依赖注入、生命周期回调,以及对于懒加载和代理对象的支持。通过这些机制,开发者可以充分利用单例模式而避免其陷阱。
在Spring框架中,工厂模式(Factory Pattern)是一种用于创建对象的设计模式,它不直接使用new运算符实例化对象,而是提供一个接口来创建对象。Spring通过BeanFactory
和ApplicationContext
接口,实现了这种设计模式。以下是对Spring中工厂模式的详细介绍:
在Spring中,工厂模式主要通过XML文件、注解或Java配置类来实现。这些配置定义了如何创建和初始化Bean。
<bean id="exampleBean" class="com.example.ExampleBean"/>
@Component
、@Service
等)标记类,Spring自动扫描并注册这些类的实例为Bean。@Configuration
和@Bean
)来定义Bean。在Spring中,通常不需要直接与BeanFactory
接口交互,因为ApplicationContext
提供了更完善的功能。ApplicationContext
是面向Spring的高级工厂模式实现,支持事件发布、国际化等特性.
虽然工厂模式为管理对象的生命周期和依赖提供了强大的机制,但它也引入了对Spring框架的依赖。此外,过度使用Spring的依赖注入可能会导致配置变得复杂,特别是在大型项目中。
总之,工厂模式在Spring框林中扮演着关键角色,它通过提供一个灵活的对象创建和管理机制,有助于构建松耦合且易于维护的应用程序。
Spring框架中的原型模式(Prototype Pattern)与设计模式中的原型模式有相似之处,但在实现细节上有所不同。设计模式中的原型模式是指使用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。而在Spring框架中,原型模式指的是每次请求都创建一个新的Bean实例的作用域。
在Spring框架中,当一个Bean的作用域被定义为原型时,Spring容器每次在请求该Bean时,都会创建一个新的实例,也就是说,它不会重用同一个实例。与单例模式(Singleton Pattern)相对,单例模式在Spring容器中只创建一次实例,在之后的请求中都会返回这个实例的相同引用。
你可以通过XML配置文件或注解来定义一个原型Bean。
XML配置方式:
<bean id="myPrototypeBean" class="com.example.PrototypeBean" scope="prototype"/>
注解方式:
@Scope("prototype")
@Component
public class PrototypeBean {
// class body
}
原型Bean的生命周期与单例Bean略有不同,Spring容器只负责创建、配置和装配原型Bean,一旦将原型Bean的引用返回给客户端请求,它就不会再管理那个Bean实例的生命周期了。这意味着原型Bean的销毁过程需要开发者自己管理。
原型模式适用于以下情况:
在使用Spring框架时,应根据具体需求选择合适的Bean作用域。对于需要独立状态或多实例的场景,原型作用域可能是一个合适的选择。
在Spring框架中,代理模式是一种常用的设计模式,用于提供一个对象的代理以控制对这个对象的访问。Spring使用代理模式主要用于实现面向切面的编程(Aspect-Oriented Programming, AOP),以及在事务管理、安全性、远程访问等方面的功能。以下是对Spring中使用代理模式的详细介绍:
代理模式涉及两个主要组件:目标对象(被代理的对象)和代理对象。代理对象控制对目标对象的访问,通常在访问目标对象之前或之后执行某些操作。
Spring的AOP是基于代理模式实现的。通过AOP,可以将诸如事务管理、安全检查等跨越多个点的功能模块化到独立的切面中,而不是与业务逻辑混在一起。
before
、after
、around
等。在Spring中,可以通过声明式的方式使用注解(如@Aspect
)或XML配置来定义切面和通知,从而实现代理模式。Spring容器负责创建代理对象并管理它们的生命周期。
Spring的代理模式是其核心特性之一,通过它可以实现多种高级功能,如AOP和事务管理,从而使得业务逻辑的实现更加清晰和简洁。
Spring框架中的模板方法模式是一种行为设计模式,它定义了一个操作中的算法的骨架,将一些步骤延迟到子类中实现。这种模式在Spring框架中被广泛应用,尤其是在那些提供了高级服务的模板类中,例如 JdbcTemplate
、HibernateTemplate
、RestTemplate
等。
在Spring框架中,模板方法模式通常是通过抽象类提供的一种服务,该服务将执行一系列步骤来完成操作。操作中不变的部分在抽象类中实现,变化的部分留给用户通过子类或回调来实现。
Spring提供的一些常见模板类,例如JdbcTemplate
和RestTemplate
,通过提供一系列的模板方法简化了编程模型。下面是对这些模板类的简要介绍:
JdbcTemplate
JdbcTemplate
是Spring提供的简化数据库交互的模板类。用户不必担心资源的创建和释放,也不必处理异常,因为JdbcTemplate
将这些通用的任务抽取成模板方法。
例如,你可以使用JdbcTemplate
执行一个查询并直接返回结果:
List<User> users = jdbcTemplate.query(
"SELECT * FROM users",
(resultSet, rowNum) -> new User(resultSet.getInt("id"), resultSet.getString("name"))
);
RestTemplate
RestTemplate
提供了一个高级的模板方法API,用于客户端HTTP访问。它封装了HTTP连接的创建和释放,以及请求/响应的序列化/反序列化。
String result = restTemplatel.getForObject("http://example.com/resource", String.class);
Spring还提供了其他模板,例如HibernateTemplate
、JmsTemplate
等,都是应用了模板方法模式的实例。
在Spring框架中,模板方法模式为处理具有固定步骤但步骤实现可变的操作提供了一种清晰且可重用的解决方案。
Spring框架中的策略模式是一种行为型设计模式,它定义了一系列算法,并将每个算法封装起来,使它们可以互换使用。策略模式允许客户端选择使用哪个算法,而不必关心算法的具体实现细节。这种模式在Spring中得到了广泛的应用,比如资源访问策略、数据访问策略等。
在Spring框架中,通常会有一个配置类或组件,这个组件中会有一个策略接口的引用,根据配置或运行时的需要,可以将不同的策略实现注入到这个组件中。
以下是几个Spring中使用策略模式的例子:
Spring提供了Resource
接口,它有多种实现,比如ClassPathResource
、FileSystemResource
、UrlResource
等,用于访问不同类型的资源。你可以根据需要选择不同的资源访问策略。
Resource template = new ClassPathResource("data/template.csv");
Spring的数据访问是通过PlatformTransactionManager
接口实现的,不同的数据访问技术(如JDBC, Hibernate, JPA)可以通过不同的PlatformTransactionManager
实现类进行事务管理。
@Bean
public PlatformTransactionManager transactionManager(EntityManagerFactory entityManagerFactory) {
return new JpaTransactionManager(entityManagerFactory);
}
Spring Security使用策略模式来处理认证,通过AuthenticationManager
接口定义认证策略,然后提供多种认证提供者(AuthenticationProvider
)实现,如DaoAuthenticationProvider
、LdapAuthenticationProvider
等。
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(customAuthenticationProvider);
}
在Spring框架中,策略模式让开发者能够编写出更加灵活和可维护的代码。开发者可以根据业务需求变化随时替换算法策略,而无需修改使用这些策略的组件。通过依赖注入(DI),Spring容器可以轻松地在不同的策略实现之间切换,从而实现了高度的可配置性和灵活性。
Spring框架中的观察者模式是一种行为型设计模式,它定义了对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并自动更新。Spring使用事件驱动模型来实现观察者模式,允许应用组件在发生某些事件时,能够接收到通知。
在Spring框架中,观察者模式主要体现在事件发布和事件监听上。Spring提供了ApplicationEvent
类作为所有事件的基类,以及ApplicationListener
接口用于监听这些事件。
Spring的核心容器可以发布各种应用事件。这些事件通常是ApplicationEvent
类的子类实例。ApplicationContext
提供了publishEvent
方法来发布事件。
public class CustomEvent extends ApplicationEvent {
public CustomEvent(Object source) {
super(source);
}
}
ApplicationContext context = ...;
context.publishEvent(new CustomEvent(this));
要监听这些事件,组件需要实现ApplicationListener
接口,并注册为Spring的bean。当事件被发布时,Spring容器会负责调用监听器的onApplicationEvent
方法。
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
// handle event
}
}
Spring提供了@EventListener
注解,使得监听事件变得更加简单。不再需要实现ApplicationListener
接口,只需在方法上添加@EventListener
注解即可。
@Component
public class CustomEventListener {
@EventListener
public void handleCustomEvent(CustomEvent event) {
// handle event
}
}
Spring还允许异步处理事件。通过使用@Async
注解,可以让事件监听器异步地执行,不会阻塞发布事件的过程。
@Async
@EventListener
public void handleCustomEvent(CustomEvent event) {
// handle event asynchronously
}
Spring的事件发布和监听机制是观察者模式的一个经典应用。它允许Spring应用在相互协作的组件之间进行松耦合通信。这种机制在Spring框架中用于各种场合,包括标准的上下文事件(如上下文刷新、上下文关闭)和自定义事件。
Spring框架中广泛使用了适配器模式,这是一种结构型设计模式,它允许将一个类的接口转换成客户期望的另一个接口。适配器模式使得原本接口不兼容的类可以一起工作。在Spring中,适配器模式主要用于确保不同的组件和API能够在Spring的统一框架中一起工作。
在Spring中,适配器模式通常用于集成第三方库、不同的数据源、不同的协议等。Spring利用适配器来确保核心框架可以与这些外部系统无缝协作。
Spring AOP(面向切面编程)使用适配器模式来适配不同的AOP框架。例如,Spring可以通过适配器使用AspectJ的切面,即使这些切面没有遵循Spring AOP的规范。
Advice advice = new AspectJExpressionPointcutAdvisor(adviceConfig);
Spring数据访问框架也使用了适配器模式,它提供了一致的数据访问方式,无论是使用JDBC、JPA、Hibernate还是其他ORM框架。
PlatformTransactionManager tm = new JpaTransactionManager(entityManagerFactory);
在这里,JpaTransactionManager
是一个适配器,它适配了JPA技术到Spring的事务管理器接口PlatformTransactionManager
。
Spring的消息API使用适配器模式来适配不同的消息服务,如JMS和AMQP。
MessageListenerAdapter adapter = new MessageListenerAdapter(messageHandler);
在上面的例子中,MessageListenerAdapter
适配了一个普通的消息处理器到JMS所期望的MessageListener
接口。
Spring MVC中,HandlerAdapter
实现了适配器模式,它允许使用多种不同类型的处理器(controller实现),比如HttpRequestHandler
、SimpleControllerHandlerAdapter
等。
RequestMappingHandlerAdapter adapter = new RequestMappingHandlerAdapter();
在Spring Boot中,适配器模式也非常常见,比如TomcatServletWebServerFactory
是一个适配器,它适配了嵌入式Tomcat服务器到Spring Boot的WebServerFactory
接口。
Spring框架通过适配器模式实现了对多种技术的统一抽象和集成,让开发者可以在不改变现有代码结构的前提下,自由选择最合适的技术和框架,并轻松地集成到Spring应用中。这种模式的使用显著降低了学习曲线,同时增加了应用的可测试性和可维护性。
Spring框架中的装饰器模式是一种结构型设计模式,它允许用户通过将对象包装在装饰器类的对象中来向单个对象添加新的职责,而不改变其接口。这种模式对于增强现有类的功能或为类添加附加功能非常有用,而无需修改原始代码。
在Spring应用中,装饰器模式通常用于在运行时动态地扩展一个对象的行为。由于Spring的核心是依赖注入(DI),因此装饰器可以通过配置(例如XML配置或注解)来应用,而不需要修改原始对象的代码。
在Spring中,装饰器模式常见的一个应用例子是Java I/O流的装饰。虽然这不是Spring特有的,但Spring中的资源抽象(如Resource
接口)经常与I/O流结合使用。
InputStream is = ...; // 原始输入流
BufferedInputStream bis = new BufferedInputStream(is); // 使用装饰器增加缓冲功能
Spring Security使用装饰器模式来增强或修改安全对象的行为,例如为UserDetails
对象添加装饰以增加额外的安全属性。
UserDetails userDetails = ...; // 原始用户详情对象
UserDetails decoratedUserDetails = new CustomUserDetailsDecorator(userDetails); // 增强功能
Spring中的面向切面编程(AOP)可以被视为一种装饰器模式,其中通知(Advice)和切点(Pointcut)用来动态地“装饰”或增强原有Bean的方法。
@Bean
public ProxyFactoryBean myBean() {
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(targetObject);
proxyFactoryBean.addAdvice(new MyAdvice()); // 动态添加增强(装饰)
return proxyFactoryBean;
}
Spring框架中的装饰器模式使开发者能够按照开闭原则(Open-Closed Principle)设计应用,即系统应该对扩展开放,对修改关闭。通过装饰器模式,开发者可以在不改变原有对象行为的前提下,为对象添加新的行为,从而使系统更加灵活和可扩展。
Spring框架中使用了外观模式(Facade Pattern),这是一种结构型设计模式,用于提供一个统一的高层接口来访问子系统中的一群接口,使得子系统更加容易使用。在Spring中,外观模式通常用于简化与复杂框架或库的交互,封装Spring自身的复杂性,或是整合多个服务以提供一个简洁的API。
Spring框架中的外观模式的例子包括但不限于以下几种:
Spring提供了各种模板类,比如JdbcTemplate
、RestTemplate
、HibernateTemplate
等,它们都封装了底层的处理细节,提供了易于使用的高层API。这些模板类实际上充当了外观的角色,简化了底层技术栈的操作。
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
List<User> users = jdbcTemplate.query("SELECT * FROM users", new UserRowMapper());
在Spring MVC中,DispatcherServlet
作为前端控制器,处理所有的HTTP请求并将其分发到相应的处理器。它封装了诸如查找控制器、请求映射、视图解析等复杂的工作流程,为开发者提供了一个简单一致的编程模型。
Spring Security中的SecurityContextHolder
提供了对安全上下文的访问,这个上下文包含了当前认证用户的详细信息。SecurityContextHolder
隐藏了线程绑定等复杂性,提供了一个清晰的API来获取当前用户的认证信息。
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
String username = authentication.getName();
Spring Boot的Starters提供了一种快速开始新Spring项目的方法,它们是预先配置的依赖描述符集合。开发者可以通过添加一个或几个Starters来引入所需的依赖,而不需要关心那些依赖的具体配置和版本管理。
Spring Data提供了Repository的抽象,这允许开发者通过定义接口来直接操作数据源,而不需要编写具体的数据访问代码。Spring Data的Repository作为外观,隐藏了数据访问层的复杂性,并提供了统一的数据访问API。
Spring使用外观模式来提供清晰、简单的编程模型,同时封装了背后复杂的实现细节。这使得开发者可以专注于业务逻辑,而不必深入了解所有底层技术的复杂性。
在Spring框架中,建造者模式(Builder Pattern)是一种创建型设计模式,用于解决复杂对象的构建问题。建造者模式通过将一个复杂对象的构建过程分解为多个简单的步骤,并允许使用相同的构建流程创建不同的表示。这种模式的目的是将对象的构建与其表示分离,以便同一个构建过程可以创建不同的表示。
Spring框架中,建造者模式不是作为其核心模式之一直接体现,但Spring Boot和一些Spring项目中可以找到这个模式的实际应用。
在Spring MVC中,ResponseEntity
是对HTTP响应进行建模的类。ResponseEntity
的构建过程可以通过ResponseEntity
的静态内部类ResponseEntityBuilder
来简化,这个内部类就是一个典型的建造者,允许链式调用方法来设置状态码、响应头和响应体。
ResponseEntity<String> responseEntity = ResponseEntity
.status(HttpStatus.OK)
.header(HttpHeaders.CONTENT_TYPE, MediaType.TEXT_PLAIN_VALUE)
.body("Success");
另一个例子是UriComponentsBuilder
,它用于构建URI的各个部分,比如scheme、host、path等。客户端代码可以使用这个Builder类以链式方式构建复杂的URI。
UriComponents uriComponents = UriComponentsBuilder
.newInstance()
.scheme("http")
.host("www.example.com")
.path("/users/{user}")
.buildAndExpand("john");
在Spring Boot中,ApplicationBuilder
是用于构建SpringApplication
实例的建造者。通过这个建造者,可以灵活地配置SpringApplication
的各种属性,如启动时的环境变量、命令行参数等。
new SpringApplicationBuilder()
.sources(Application.class)
.profiles("prod")
.run(args);
虽然不是Spring框架的一部分,但是在Spring应用中经常使用的Lombok库提供了@Builder
注解,该注解可以自动为类生成一个静态内部的Builder类。这在创建具有多个字段的实体类时显得特别有用。
@Getter
@Builder
public class User {
private final String username;
private final String email;
private final String password;
}
User user = User.builder()
.username("john_doe")
.email("john@example.com")
.password("password")
.build();
Spring框架中建造者模式的使用,尤其是在Spring Boot中,极大地简化了复杂对象的构建过程,使得代码更加清晰、易维护,并提高了代码的可读性。
在Spring框架中,责任链模式(Chain of Responsibility Pattern)是一种行为设计模式,它帮助构建对象之间的链式请求处理流程。在这个模式中,每个处理对象包含对下一个处理对象的引用。请求会沿着这条链传递,直到某个处理对象处理该请求为止。
责任链模式允许多个对象有机会处理请求,从而将请求的发送者和接收者之间的耦合解耦。它增强了给定功能的灵活性和可重用性,因为处理流程可以动态地重新组织或分配给不同的处理者。
在Spring框架中,责任链模式通常用于以下场景:
Spring Security使用一个过滤器链来处理安全相关的任务。每个过滤器执行一个特定的安全功能,并将请求传递给链中的下一个过滤器。这是责任链模式的一个典型应用,它允许开发者添加或去除某些安全功能,或者改变过滤器的顺序,以适应不同的安全需求。
http
.authorizeRequests(authz -> authz
.anyRequest().authenticated()
)
.httpBasic(withDefaults());
在Spring MVC中,拦截器实现了HandlerInterceptor
接口,可以对处理器进行预处理和后处理。拦截器可以建立一个拦截器链,每个拦截器依次调用,直到完成所有的处理,或某个拦截器决定中断执行。
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor());
}
在Spring面向切面编程(AOP)中,增强(Advice)可以看作是责任链模式的一种特殊形式。虽然它们不一定形成一个传统的链条,但每个增强都可以在方法执行的不同点上应用,如前置增强(Before advice)、后置增强(After returning advice)、异常增强(After throwing advice)等,形成了一个逻辑链。
@Aspect
@Component
public class MyAspect {
@Before("execution(* com.example.service.MyService.*(..))")
public void beforeAdvice(JoinPoint joinPoint) {
// ...
}
}
责任链模式也常用于日志记录系统,其中日志请求可以由不同级别的日志记录器处理。例如,一个DEBUG级别的日志记录器可以处理DEBUG信息,但是ERROR信息可以传递给一个更高级别的日志记录器。
总结
Spring中的责任链模式提供了很大的灵活性,使得处理流程可以根据需要进行调整和重构,从而更好地适应应用程序的变化。
在Spring框架中,状态模式(State Pattern)是一种行为设计模式,用于在对象的状态改变时切换对象的行为。状态模式允许一个对象在其内部状态变化时改变它的行为,看起来好像修改了它的类。
虽然Spring框架本身并不直接提供状态模式的实现,但是它的IoC容器和依赖注入特性使得实现状态模式变得容易,且更为灵活。开发者可以在Spring中创建状态对象并通过注入的方式在不同的上下文中切换和管理状态。
在Spring中,可以使用状态模式来管理复杂的业务流程,比如订单处理流程。每个订单状态(如新建、已支付、发货中、已完成、已取消)都可以由具体的状态类来实现,这些状态类会根据订单的当前状态执行相应的业务逻辑。
public interface OrderState {
void handle(OrderContext context);
}
@Component
public class NewOrderState implements OrderState {
@Override
public void handle(OrderContext context) {
// 处理新建订单的逻辑
}
}
@Component
public class PaidOrderState implements OrderState {
@Override
public void handle(OrderContext context) {
// 处理已支付订单的逻辑
}
}
public class OrderContext {
private OrderState state;
public void setState(OrderState state) {
this.state = state;
}
public void next() {
state.handle(this);
}
}
在这个示例中,OrderContext
类代表上下文,持有一个OrderState
接口的引用。各个状态实现了OrderState
接口,并在handle
方法中定义了在该状态下要执行的操作。
Spring State Machine是一个专门为Spring应用构建状态机的项目,它提供了更为丰富的功能来管理复杂状态,并且可以非常方便地被集成到Spring应用中。它支持状态管理、状态迁移事件、条件迁移、分支和合并等高级功能。
@Configuration
@EnableStateMachine
public class StateMachineConfig extends EnumStateMachineConfigurerAdapter<States, Events> {
@Override
public void configure(StateMachineStateConfigurer<States, Events> states) throws Exception {
states
.withStates()
.initial(States.NEW)
.state(States.PAID)
.end(States.COMPLETED);
}
@Override
public void configure(StateMachineTransitionConfigurer<States, Events> transitions) throws Exception {
transitions
.withExternal()
.source(States.NEW).target(States.PAID).event(Events.PAY)
.and()
.withExternal()
.source(States.PAID).target(States.COMPLETED).event(Events.FULFILL);
}
}
public enum States {
NEW, PAID, COMPLETED
}
public enum Events {
PAY, FULFILL
}
通过使用Spring框架的特性来实现状态模式,开发者可以构建出更灵活、更易于维护的状态管理系统,特别是在面临复杂的状态转换和业务流程时。
这些设计模式在Spring框架中的运用提供了一个高度解耦、易于扩展和维护的环境。熟练掌握这些模式可以帮助开发者更好地理解和使用Spring框架。