前言
😊"spring中用了哪些设计模式?"
面试过的肯定都知道,这个问题算是非常高频的问题了。
从现在起不要再死记硬背🤯,下面我把每个设计的模式的源码贴出来分析,以后大家就不会忘了👌
单例模式
在Spring Boot中,单例模式是默认的Bean作用域,Spring容器会保证每个单例Bean仅有一个实例。以DefaultSingletonBeanRegistry
类为例,它是Spring容器实现单例模式的关键类。
Spring Boot 中的单例模式没有直接采用传统单例模式(如双检锁、静态内部类、枚举)的实现方式,而是基于自身的 Bean 管理机制来实现单例
简化的源码:
java
public class DefaultSingletonBeanRegistry extends SimpleAliasRegistry implements SingletonBeanRegistry {
// 用于存储单例Bean的缓存
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
@Override
public Object getSingleton(String beanName) {
return getSingleton(beanName, true);
}
protected Object getSingleton(String beanName, boolean allowEarlyReference) {
// 从单例缓存中获取Bean
Object singletonObject = this.singletonObjects.get(beanName);
if (singletonObject == null && isSingletonCurrentlyInCreation(beanName)) {
//-------singletonObjects 不是已经是 concurrentHashMap线程安全的吗,为什么还要加锁
synchronized (this.singletonObjects) {
singletonObject = this.earlySingletonObjects.get(beanName);
if (singletonObject == null && allowEarlyReference) {
ObjectFactory<?> singletonFactory = this.singletonFactories.get(beanName);
if (singletonFactory != null) {
singletonObject = singletonFactory.getObject();
this.earlySingletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
}
}
}
}
return singletonObject;
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
// 将单例Bean添加到缓存中
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
}
在上述代码里,singletonObjects
这个Map
用于存储单例Bean实例。getSingleton
方法会先从缓存里查找Bean实例,若不存在则创建;addSingleton
方法会把创建好的单例Bean添加到缓存中。
tips
-
可以看到
singletonObjects
用了ConcurrentHashMap
保证线程安全 -
synchronized (this.singletonObjects)
对singletonObjects
再次加锁,保证get
和put
的原子操作。保证在同一时刻只有一个线程能够执行创建单例 Bean 的操作。假设不加sync :
有两个线程同时调用
getSingleton
方法获取同一个单例 Bean,此时singletonObjects
中还没有该 Bean 实例。如果没有使用synchronized
进行同步,可能会出现以下情况:- 线程 A 检查
singletonObjects
发现该 Bean 实例不存在。 - 同时,线程 B 也检查
singletonObjects
发现该 Bean 实例不存在。 - 线程 A 和线程 B 都认为需要创建该 Bean 实例,于是各自创建了一个新的 Bean 实例,并将其入
singletonObjects
中,这样就会导致创建了多个单例 Bean 实例,违反了单例模式的原则。
- 线程 A 检查
工厂模式
BeanFactory
是Spring框架里工厂模式的核心体现,它负责创建和管理Bean实例。AbstractBeanFactory
是BeanFactory
的一个重要抽象实现类。
以下是部分源码分析:
java
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
@Override
public Object getBean(String name) throws BeansException {
return doGetBean(name, null, null, false);
}
protected <T> T doGetBean(
String name, @Nullable Class<T> requiredType, @Nullable Object[] args, boolean typeCheckOnly)
throws BeansException {
String beanName = transformedBeanName(name);
Object bean;
// 从缓存中获取单例Bean
Object sharedInstance = getSingleton(beanName);
if (sharedInstance != null && args == null) {
if (logger.isTraceEnabled()) {
if (isSingletonCurrentlyInCreation(beanName)) {
logger.trace("Returning eagerly cached instance of singleton bean '" + beanName +
"' that is not fully initialized yet - a consequence of a circular reference");
}
else {
logger.trace("Returning cached instance of singleton bean '" + beanName + "'");
}
}
bean = getObjectForBeanInstance(sharedInstance, name, beanName, null);
}
else {
// 创建Bean实例
if (isPrototypeCurrentlyInCreation(beanName)) {
throw new BeanCurrentlyInCreationException(beanName);
}
BeanFactory parentBeanFactory = getParentBeanFactory();
if (parentBeanFactory != null && !containsBeanDefinition(beanName)) {
// Not found -> check parent.
String nameToLookup = originalBeanName(name);
if (parentBeanFactory instanceof AbstractBeanFactory) {
return ((AbstractBeanFactory) parentBeanFactory).doGetBean(
nameToLookup, requiredType, args, typeCheckOnly);
}
else if (args != null) {
// Delegation to parent with explicit args.
return (T) parentBeanFactory.getBean(nameToLookup, args);
}
else {
// No args -> delegate to standard getBean method.
return parentBeanFactory.getBean(nameToLookup, requiredType);
}
}
if (!typeCheckOnly) {
markBeanAsCreated(beanName);
}
try {
RootBeanDefinition mbd = getMergedLocalBeanDefinition(beanName);
checkMergedBeanDefinition(mbd, beanName, args);
// Guarantee initialization of beans that the current bean depends on.
String[] dependsOn = mbd.getDependsOn();
if (dependsOn != null) {
for (String dep : dependsOn) {
if (isDependent(beanName, dep)) {
throw new BeanCreationException(mbd.getResourceDescription(), beanName,
"Circular depends-on relationship between '" + beanName + "' and '" + dep + "'");
}
registerDependentBean(dep, beanName);
getBean(dep);
}
}
// Create bean instance.
if (mbd.isSingleton()) {
sharedInstance = getSingleton(beanName, () -> {
try {
return createBean(beanName, mbd, args);
}
catch (BeansException ex) {
// Explicitly remove instance from singleton cache: It might have been put there
// eagerly by the creation process, to allow for circular reference resolution.
// Also remove any beans that received a temporary reference to the bean.
destroySingleton(beanName);
throw ex;
}
});
bean = getObjectForBeanInstance(sharedInstance, name, beanName, mbd);
}
else if (mbd.isPrototype()) {
// It's a prototype -> create a new instance.
Object prototypeInstance = null;
try {
beforePrototypeCreation(beanName);
prototypeInstance = createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
bean = getObjectForBeanInstance(prototypeInstance, name, beanName, mbd);
}
else {
String scopeName = mbd.getScope();
final Scope scope = this.scopes.get(scopeName);
if (scope == null) {
throw new IllegalStateException("No Scope registered for scope name '" + scopeName + "'");
}
try {
Object scopedInstance = scope.get(beanName, () -> {
beforePrototypeCreation(beanName);
try {
return createBean(beanName, mbd, args);
}
finally {
afterPrototypeCreation(beanName);
}
});
bean = getObjectForBeanInstance(scopedInstance, name, beanName, mbd);
}
catch (IllegalStateException ex) {
throw new BeanCreationException(beanName,
"Scope '" + scopeName + "' is not active for the current thread; consider " +
"defining a scoped proxy for this bean if you intend to refer to it from a singleton",
ex);
}
}
}
catch (BeansException ex) {
cleanupAfterBeanCreationFailure(beanName);
throw ex;
}
}
// Check if required type matches the type of the actual bean instance.
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
T convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
}
doGetBean
方法会依据Bean的名称获取对应的Bean实例。要是缓存里没有,就会调用createBean
方法来创建新的实例。
代理模式
Spring AOP借助代理模式达成面向切面编程。JdkDynamicAopProxy
是基于JDK动态代理实现的AOP代理类。
以下是简化的源码分析:
java
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.getTargetSource();
Object target = null;
try {
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target,
// in case it comes from a pool.
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// Get the interception chain for this method.
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// Check whether we have any advice. If we don't, we can fallback on direct
// reflective invocation of the target, and avoid creating a MethodInvocation.
if (chain.isEmpty()) {
// We can skip creating a MethodInvocation: just invoke the target directly
// Note that the final invoker must be an InvokerInterceptor so we know it does
// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// We need to create a method invocation...
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// Proceed to the joinpoint through the interceptor chain.
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned "this" and the return type of the method
// is type-compatible. Note that we can't help if the target sets
// a reference to itself in another returned object.
retVal = proxy;
}
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
invoke
方法是代理对象的核心方法,在调用目标方法时,会先获取拦截器链,接着按顺序执行拦截器逻辑,最后调用目标方法。
观察者模式
Spring的事件驱动机制运用了观察者模式。SimpleApplicationEventMulticaster
是事件广播器的实现类。
以下是简化的源码分析:
java
public class CustomEvent extends ApplicationEvent {
public CustomEvent(Object source) {
super(source);
}
}
import org.springframework.context.ApplicationListener;
import org.springframework.stereotype.Component;
@Component
public class CustomEventListener implements ApplicationListener<CustomEvent> {
@Override
public void onApplicationEvent(CustomEvent event) {
System.out.println("Custom event received: " + event.getSource());
}
}
SimpleApplicationEventMulticaster
是事件广播器的实现类,multicastEvent
方法将事件广播给所有注册的监听器。
java
@Override
public void multicastEvent(final ApplicationEvent event, @Nullable ResolvableType eventType) {
ResolvableType type = (eventType != null ? eventType : resolveDefaultEventType(event));
Executor executor = getTaskExecutor();
for (ApplicationListener<?> listener : getApplicationListeners(event, type)) {
if (executor != null) {
executor.execute(() -> invokeListener(listener, event));
}
else {
invokeListener(listener, event);
}
}
}
模板方法模式
JdbcTemplate
是Spring JDBC模块里模板方法模式的典型应用。
以下是简化的源码分析:
java
public class JdbcTemplate extends JdbcAccessor implements JdbcOperations {
@Override
public <T> T query(final String sql, final ResultSetExtractor<T> rse) throws DataAccessException {
Assert.notNull(sql, "SQL must not be null");
Assert.notNull(rse, "ResultSetExtractor must not be null");
if (logger.isDebugEnabled()) {
logger.debug("Executing SQL query [" + sql + "]");
}
class QueryStatementCallback implements StatementCallback<T>, SqlProvider {
@Override
public T doInStatement(Statement stmt) throws SQLException {
ResultSet rs = null;
try {
rs = stmt.executeQuery(sql);
return rse.extractData(rs);
}
finally {
JdbcUtils.closeResultSet(rs);
}
}
@Override
public String getSql() {
return sql;
}
}
return execute(new QueryStatementCallback());
}
@Override
public <T> T execute(StatementCallback<T> action) throws DataAccessException {
Assert.notNull(action, "Callback object must not be null");
Connection con = DataSourceUtils.getConnection(obtainDataSource());
Statement stmt = null;
try {
stmt = con.createStatement();
applyStatementSettings(stmt);
T result = action.doInStatement(stmt);
handleWarnings(stmt);
return result;
}
catch (SQLException ex) {
// Release Connection early, to avoid potential connection pool deadlock
// in the case when the exception translator hasn't been initialized yet.
String sql = getSql(action);
JdbcUtils.closeStatement(stmt);
stmt = null;
DataSourceUtils.releaseConnection(con, getDataSource());
con = null;
throw getExceptionTranslator().translate("StatementCallback", sql, ex);
}
finally {
JdbcUtils.closeStatement(stmt);
DataSourceUtils.releaseConnection(con, getDataSource());
}
}
}
query
方法定义了查询操作的模板,把具体的结果集处理逻辑委托给ResultSetExtractor
。execute
方法则封装了通用的数据库连接和语句执行逻辑。
装饰器模式
- 原理 :装饰器模式允许向一个现有的对象添加新的功能,同时又不改变其结构。在 Spring Boot 中,
BufferedReader
和BufferedWriter
的使用类似装饰器模式,用于增强Reader
和Writer
的功能。 - 应用场景:当需要在不修改现有对象结构的前提下,动态地给对象添加额外的功能时使用。
- 代码示例:
java
import java.io.BufferedReader;
import java.io.FileReader;
import java.io.IOException;
public class DecoratorExample {
public static void main(String[] args) {
try (BufferedReader br = new BufferedReader(new FileReader("test.txt"))) {
String line;
while ((line = br.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}
}
- 源码体现:虽然 Spring Boot 本身没有典型的装饰器模式代码,但 Java I/O 流的设计是装饰器模式的经典应用,Spring Boot 在使用 I/O 流时间接运用了该模式。
策略模式
- 原理 :策略模式定义了一系列的算法,并将每个算法封装起来,使它们可以相互替换。在 Spring Boot 中,不同的
MessageConverter
实现就是策略模式的应用,用于处理不同类型的消息转换。 - 应用场景:当需要根据不同的条件选择不同的算法或行为时使用。
- 代码示例:
java
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.List;
@RestController
public class ConverterController {
private final List<HttpMessageConverter<?>> messageConverters;
public ConverterController(List<HttpMessageConverter<?>> messageConverters) {
this.messageConverters = messageConverters;
}
@GetMapping("/converters")
public String getConverters() {
StringBuilder sb = new StringBuilder();
for (HttpMessageConverter<?> converter : messageConverters) {
sb.append(converter.getClass().getName()).append("\n");
}
return sb.toString();
}
}
适配器模式
-
原理:将一个类的接口转换成客户希望的另外一个接口,使得原本由于接口不兼容而不能一起工作的那些类能一起工作。
-
应用场景 :在 Spring MVC 中,
HandlerAdapter
就是适配器模式的典型应用。Spring MVC 为不同类型的处理器(如HttpRequestHandler
、Controller
等)提供了不同的适配器,将不同处理器的调用适配到统一的HandlerAdapter
接口上,这样DispatcherServlet
就可以通过统一的方式调用不同类型的处理器。 -
代码示例:
java
kotlin
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
public class MyController {
@GetMapping("/example")
@ResponseBody
public String handleRequest() {
return "This is an example response.";
}
}
在上述代码中,MyController
是自定义的处理器。Spring MVC 内部通过 HandlerAdapter
来适配对 MyController
中方法的调用。
- 源码体现 :
RequestMappingHandlerAdapter
是处理@RequestMapping
注解的处理器适配器,它实现了HandlerAdapter
接口,将带有@RequestMapping
注解的控制器方法适配到统一的调用流程中。
责任链模式
-
原理:为请求创建了一个接收者对象的链,每个接收者都包含对另一个接收者的引用,如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推。
-
应用场景 :Spring Security 中使用了责任链模式来处理安全验证。一系列的
Filter
组成了一个过滤器链,每个Filter
负责特定的安全验证任务,如身份验证、权限检查等。请求会依次经过这些过滤器,直到找到能够处理该请求的过滤器或者整个链处理完毕。 -
代码示例:
java
java
import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;
@WebFilter(urlPatterns = "/*")
public class MyFilter implements Filter {
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
// 执行过滤逻辑
System.out.println("Before filtering...");
chain.doFilter(request, response);
System.out.println("After filtering...");
}
}
在这个示例中,MyFilter
是一个自定义的过滤器,它可以在请求处理前后执行特定的逻辑。多个这样的过滤器可以组成一个责任链。
- 源码体现 :
FilterChainProxy
是 Spring Security 中过滤器链的代理类,它管理着一系列的Filter
,并按照顺序依次调用这些过滤器。
建造者模式
-
原理:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
-
应用场景 :在 Spring Boot 的配置类中,有时会使用建造者模式来创建复杂的配置对象。例如,
RestTemplateBuilder
用于构建RestTemplate
对象,它提供了一系列的方法来设置RestTemplate
的各种属性,如消息转换器、拦截器等,最后通过build()
方法创建出RestTemplate
实例。 -
代码示例:
java
typescript
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.web.client.RestTemplate;
public class RestTemplateExample {
public static void main(String[] args) {
RestTemplate restTemplate = new RestTemplateBuilder()
.setConnectTimeout(java.time.Duration.ofSeconds(5))
.setReadTimeout(java.time.Duration.ofSeconds(5))
.build();
}
}
在上述代码中,通过 RestTemplateBuilder
逐步设置 RestTemplate
的连接超时时间和读取超时时间,最后调用 build()
方法创建出 RestTemplate
实例。
-
源码体现 :
RestTemplateBuilder
类提供了一系列的方法用于设置RestTemplate
的属性,最终通过build()
方法构建出RestTemplate
对象。 -
源码体现 :Spring 框架中定义了
HttpMessageConverter
接口,不同的实现类(如MappingJackson2HttpMessageConverter
、StringHttpMessageConverter
等)封装了不同的消息转换策略。