Spring中用到的设计模式

工厂模式

工厂模式的好处:把创建对象的任务交给工厂,从而降低类与类之间的耦合。

Spring使用工厂模式可以通过BeanFactory或ApplicationContext创建bean对象。

单例模式

单例模式

单例模式的好处:对于一些重量级对象,省略了重复创建对象的开销;并且减少了创建的对象数量,对于GC的压力也会小一些。

Spring中bean的默认作用域就是singleton。
Spring通过ConcurrentHashMap作为单例注册表来实现单例模式

// 通过 ConcurrentHashMap(线程安全) 实现单例注册表  
private final Map<String, Object> singletonObjects = new ConcurrentHashMap<String, Object>(64);  
public Object getSingleton(String beanName, ObjectFactory<?> singletonFactory) {  
    Assert.notNull(beanName, "'beanName' must not be null");  
    synchronized (this.singletonObjects) {  
        // 检查缓存中是否存在实例    
        Object singletonObject = this.singletonObjects.get(beanName);  
        if (singletonObject == null) {  
            //...省略了很多代码  
            try {  
                singletonObject = singletonFactory.getObject();  
            }  
            //...省略了很多代码  
            // 如果实例对象在不存在,我们注册到单例注册表中。  
            addSingleton(beanName, singletonObject);  
        }  
        return (singletonObject != NULL_OBJECT ? singletonObject : null);  
    }  
}  
//将对象添加到单例注册表  
protected void addSingleton(String beanName, Object singletonObject) {  
    synchronized (this.singletonObjects) {  
        this.singletonObjects.put(beanName, (singletonObject != null ? singletonObject : NULL_OBJECT));  
    }  
}  
} 

代理模式

代理模式

代理模式作为面向对象的一种补充,用于将那些与业务无关,但却对多个对象产生影响的公共行为和逻辑,抽取并封装为一个可重用的模块,减少系统中的重复代码,降低了模块间的耦合度,提高系统的可维护性。可用于权限认证、日志、事务处理。

Spring AOP就是基于代理模式。

  • JDK动态代理只提供接口的代理,不支持类的代理,要求被代理类实现接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
    • 在获取代理对象时,使用Proxy类来动态创建目标类的代理类(即最终真正的代理类,这个类继承自Proxy并实现了我们定义的接口),当代理对象调用真实对象的方法时, InvocationHandler 通过invoke()方法反射来调用目标类中的代码,动态地将横切逻辑和业务编织在一起;
  • 如果被代理类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。
    • CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成指定类的一个子类对象,并覆盖其中特定方法并添加增强代码,从而实现AOP。
    • CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

image.png

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
	@Override
	public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
		if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
			Class<?> targetClass = config.getTargetClass();
			if (targetClass == null) {
				throw new AopConfigException("TargetSource cannot determine target class: " + "Either an interface or a target is required for proxy creation.");
			}
            //目标类是否实现了接口
			if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
				return new JdkDynamicAopProxy(config);
			}
			return new ObjenesisCglibAopProxy(config);
		}
		else {
			return new JdkDynamicAopProxy(config);
		}
	}
}

策略模式

策略模式

封装好一组策略,外部客户端根据不同的条件选择不同的策略算法解决问题。

如Spring的Resource类。针对不同的资源,Spring提供了不同的Resource类的实现类:
image.png

  • UrlResource:访问网络资源的实现类。
  • ServletContextResource:访问相对于 ServletContext 路径里的资源的实现类。
  • ByteArrayResource:访问字节数组资源的实现类。
  • PathResource:访问文件路径资源的实现类。
  • ClassPathResource:访问类加载路径里资源的实现类。

写一段伪代码来示范一下Resource类的应用:

@RequestMapping(value = "/resource", method = RequestMethod.GET)
public String resource(@RequestParam(name = "type") String type,
                       @RequestParam(name = "arg") String arg) throws Exception {
    Resource resource;
    //这里可以优化为通过工厂模式,根据type创建Resource的实现类
    if ("classpath".equals(type)) {
        //classpath下的资源
        resource = new ClassPathResource(arg);
    } else if ("file".equals(type)) {
        //本地文件系统的资源
        resource = new PathResource(arg);
    } else if ("url".equals(type)) {
        //网络资源
        resource = new UrlResource(arg);
    } else {
        return "fail";
    }
    InputStream is = resource.getInputStream();
    ByteArrayOutputStream os = new ByteArrayOutputStream();
    int i;
    while ((i = is.read()) != -1) {
        os.write(i);
    }
    String result = new String(os.toByteArray(), StandardCharsets.UTF_8);
    is.close();
    os.close();
    return "type:" + type + ",arg:" + arg + "\r\n" + result;
}

实际上就是if-else.....

模板模式

在模板方法模式中,我们可以将相同部分的代码放在父类中,而将不同的代码放入不同的子类中,从而解决代码重复的问题。对代码的规范化,抽象解耦也有一定的帮助。

Spring中的事务管理器就运用模板模式的设计,首先看PlatformTransactionManager类。这是最底层的接口,定义提交和回滚的方法。

public interface PlatformTransactionManager {
    TransactionStatus getTransaction(@Nullable TransactionDefinition definition) throws TransactionException;
    
    void commit(TransactionStatus status) throws TransactionException;
    
    void rollback(TransactionStatus status) throws TransactionException;
}

并且使用抽象类AbstractPlatformTransactionManager实现PlatformTransactionManager接口并把doRollback()doComit()方法作为抽象方法延迟到子类去实现。

@Override
public final void commit(TransactionStatus status) throws TransactionException {
    //省略...
    DefaultTransactionStatus defStatus = (DefaultTransactionStatus) status;
    if (defStatus.isLocalRollbackOnly()) {
        //省略...
        //调用processRollback()
        processRollback(defStatus, false);
        return;
    }
 
    if (!shouldCommitOnGlobalRollbackOnly() && defStatus.isGlobalRollbackOnly()) {
        //省略...
        //调用processRollback()
        processRollback(defStatus, true);
        return;
    }
    //调用processCommit()
    processCommit(defStatus);
}
 
//这个方法定义了骨架,里面会调用一个doRollback()的模板方法
private void processRollback(DefaultTransactionStatus status, boolean unexpected) {
    if (status.hasSavepoint()) {
        //省略...
    }
    else if (status.isNewTransaction()) {
        //调用doRollback()模板方法
        doRollback(status);
    }
    else {
        //省略...
    }
    //省略了很多代码...
}
 
private void processCommit(DefaultTransactionStatus status) throws TransactionException {
    //省略...
    if (status.hasSavepoint()) {
        //省略...
    }
    else if (status.isNewTransaction()) {
        //省略...
        //调用doCommit()模板方法
        doCommit(status);
    }
    else if (isFailEarlyOnGlobalRollbackOnly()) {
        unexpectedRollback = status.isGlobalRollbackOnly();
    }
    //省略了很多代码...
}
 
//模板方法doRollback(),把重要的步骤延迟到子类去实现
protected abstract void doRollback(DefaultTransactionStatus status) throws TransactionException;
 
//模板方法doCommit(),把重要的步骤延迟到子类去实现
protected abstract void doCommit(DefaultTransactionStatus status) throws TransactionException;

一般来说,Spring默认是使用的事务管理器的实现类是DataSourceTransactionManager。

//通过继承AbstractPlatformTransactionManager抽象类
public class DataSourceTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, InitializingBean {
    //重写doCommit()方法,实现具体commit的逻辑
    @Override
    protected void doCommit(DefaultTransactionStatus status) {
        DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
        Connection con = txObject.getConnectionHolder().getConnection();
        if (status.isDebug()) {
            logger.debug("Committing JDBC transaction on Connection [" + con + "]");
        }
        try {
            con.commit();
        }
        catch (SQLException ex) {
            throw new TransactionSystemException("Could not commit JDBC transaction", ex);
        }
    }
    
    //重写doRollback()方法,实现具体的rollback的逻辑
    @Override
    protected void doRollback(DefaultTransactionStatus status) {
    DataSourceTransactionObject txObject = (DataSourceTransactionObject) status.getTransaction();
    Connection con = txObject.getConnectionHolder().getConnection();
    if (status.isDebug()) {
      logger.debug("Rolling back JDBC transaction on Connection [" + con + "]");
    }
    try {
      con.rollback();
    }
    catch (SQLException ex) {
      throw new TransactionSystemException("Could not roll back JDBC transaction", ex);
    }
  }
}

如果用Hibernate框架来实现事务管理器,Hibernate也有自身的实现类,这就体现了设计模式的开闭原则,通过继承或者组合的方式进行扩展,而不是直接修改类的代码。Hibernate的事务管理器则是HibernateTransactionManager。

public class HibernateTransactionManager extends AbstractPlatformTransactionManager
		implements ResourceTransactionManager, BeanFactoryAware, InitializingBean {
    
  //重写doCommit()方法,实现Hibernate的具体commit的逻辑
  @Override
  protected void doCommit(DefaultTransactionStatus status) {HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
      Transaction hibTx = txObject.getSessionHolder().getTransaction();
      Assert.state(hibTx != null, "No Hibernate transaction");
      if (status.isDebug()) {
        logger.debug("Committing Hibernate transaction on Session [" +
            txObject.getSessionHolder().getSession() + "]");
      }
      try {
        hibTx.commit();
      }
      catch (org.hibernate.TransactionException ex) {
        throw new TransactionSystemException("Could not commit Hibernate transaction", ex);
      }
          //省略...
    }
    
  //重写doRollback()方法,实现Hibernate的具体rollback的逻辑
  @Override
  protected void doRollback(DefaultTransactionStatus status) {
    HibernateTransactionObject txObject = (HibernateTransactionObject) status.getTransaction();
    Transaction hibTx = txObject.getSessionHolder().getTransaction();
    Assert.state(hibTx != null, "No Hibernate transaction");
    //省略...
    try {
      hibTx.rollback();
    }
    catch (org.hibernate.TransactionException ex) {
      throw new TransactionSystemException("Could not roll back Hibernate transaction", ex);
    }
        //省略...
    finally {
      if (!txObject.isNewSession() && !this.hibernateManagedSession) {
        txObject.getSessionHolder().getSession().clear();
      }
    }
  }
}

适配器模式与责任链模式

适配器模式

适配器模式能够使接口不兼容的对象能够互相合作,将一个类的接口,转换成能够与客户端兼容的接口

在SpringAOP中有一个很重要的功能就是使用的 Advice(通知) 来增强被代理类的功能,Advice主要有MethodBeforeAdvice、AfterReturningAdvice、ThrowsAdvice这几种。每个Advice都有对应的拦截器:
image.png
Spring需要将每个 Advice 都封装成对应的拦截器类型返回给容器,所以需要使用适配器模式对 Advice 进行转换。对应的就有三个适配器:
image.png
在适配器(Adapter)中将通知类(Advice)接口转换为了拦截器(Interceptor)接口。

public interface AdvisorAdapter {
    //判断通知类是否匹配
    boolean supportsAdvice(Advice advice);
    //传入通知类,返回对应的拦截类
    MethodInterceptor getInterceptor(Advisor advisor);
}

具体实现类MethodBeforeAdviceAdapter:

class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
    //判断是否匹配MethodBeforeAdvice通知类
	@Override
	public boolean supportsAdvice(Advice advice) {
		return (advice instanceof MethodBeforeAdvice);
	}
	//传入MethodBeforeAdvice,转换为MethodBeforeAdviceInterceptor拦截类
	@Override
	public MethodInterceptor getInterceptor(Advisor advisor) {
		MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
		return new MethodBeforeAdviceInterceptor(advice);
	}
}

由适配器包装后返回的拦截器MethodBeforeAdviceInterceptor。

public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
  //成员变量,通知类
  private MethodBeforeAdvice advice;
    
  //定义了有参构造器,外部通过有参构造器创建MethodBeforeAdviceInterceptor
  public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
      Assert.notNull(advice, "Advice must not be null");
      this.advice = advice;
  }
  
  //当调用拦截器的invoke方法时,就调用通知类的before()方法,实现前置通知
  @Override
  public Object invoke(MethodInvocation mi) throws Throwable {
      //调用通知类的before()方法,实现前置通知
      this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
      return mi.proceed();
  }
 
}

适配器(Adapter)是如何将拦截器(Interceptor)注册到容器中的?答案在DefaultAdvisorAdapterRegistry类中。

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
 
  private final List<AdvisorAdapter> adapters = new ArrayList<>(3);
 
  public DefaultAdvisorAdapterRegistry() {
    //初始化三种适配器,添加到adapters集合以注册到容器中。
    registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
    registerAdvisorAdapter(new AfterReturningAdviceAdapter());
    registerAdvisorAdapter(new ThrowsAdviceAdapter());
  }
    
  @Override
  public void registerAdvisorAdapter(AdvisorAdapter adapter) {
    this.adapters.add(adapter);
  }
    
  //获取拦截器(Interceptor)集合
  @Override
  public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
    List<MethodInterceptor> interceptors = new ArrayList<>(3);
    Advice advice = advisor.getAdvice();
	if (advice instanceof MethodInterceptor) {
       interceptors.add((MethodInterceptor) advice);
    }
    //遍历适配器集合
    for (AdvisorAdapter adapter : this.adapters) {
    	//调用supportsAdvice()方法,判断入参的advisor是否有匹配的适配器
    	if (adapter.supportsAdvice(advice)) {
            //如果匹配,则调用getInterceptor()转换成对应的拦截器,添加到interceptors集合中
            interceptors.add(adapter.getInterceptor(advisor));
        }
    }
    if (interceptors.isEmpty()) {
        throw new UnknownAdviceTypeException(advisor.getAdvice());
    }
    //返回拦截器集合
    return interceptors.toArray(new MethodInterceptor[0]);
	}
    
}

适配器将通知类转换为拦截器并添加到拦截器集合并注册到容器中后,当调用目标类方法时,就会获取拦截器集合并遍历以实现通知功能。
以JDK动态代理为例。

@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    MethodInvocation invocation;
    //这里就是获取拦截器集合,最后就会调用到上文说的getInterceptors()
    List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
    if (chain.isEmpty()) {
        //省略...
    }else {
        //创建一个MethodInvocation
        invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
        //调用proceed()方法,底层会通过指针遍历拦截器集合,然后实现前置通知等功能
        retVal = invocation.proceed();
    }
    //省略...
}

最后在ReflectiveMethodInvocation里调用proceed()方法,proceed是一个递归方法,通过指针控制递归的结束。这就是很典型的责任链模式。

责任链模式

public class ReflectiveMethodInvocation implements ProxyMethodInvocation, Cloneable {
    protected final List<?> interceptorsAndDynamicMethodMatchers;
    //指针
    private int currentInterceptorIndex = -1;
    
    protected ReflectiveMethodInvocation(Object proxy, @Nullable Object target, Method method, @Nullable Object[] arguments, @Nullable Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
        //省略...
        //拦截器的集合
        this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
    }
    
    @Override
    @Nullable
    public Object proceed() throws Throwable {
        //	We start with an index of -1 and increment early.
        if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
            //递归结束
            return invokeJoinpoint();
        }
        //获取拦截器,并且当前的指针+1
        Object interceptorOrInterceptionAdvice = this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
        if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
            InterceptorAndDynamicMethodMatcher dm =
                (InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
            if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
                return dm.interceptor.invoke(this);
            }
            else {
                //匹配失败,跳过,递归下一个
                return proceed();
            }
        }
        else {
            //匹配拦截器,强转为拦截器,然后执行invoke()方法,然后就会调用拦截器里的成员变量的before(),afterReturning()等等,实现前置通知,后置通知,异常通知
            return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
        }
    }
}
posted @ 2023-03-23 16:06  青子Aozaki  阅读(88)  评论(0)    收藏  举报