设计模式-适配器设计模式

为什么需要适配器模式

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

在SpringAOP中有一个很重要的功能就是使用的 Advice(通知)来【增强】【被代理类】的功能,那么通知主要有三种

1、MethodBeforeAdvice
2、AfterReturningAdvice
3、ThrowsAdvice

每个Advice都有对应的拦截器,如下所示:

1、每一种通知,其实是有一个对应的拦截器,那么当目标方法被执行的时候,就会进到这个拦截器,在拦截里面会判断,当前目标类有哪些通知,这样就有哪些拦截器需要执行
2、Spring需要将每个Advice生成对应的拦截器返回给容器,所以需要使用适配器模式对Advice进行转换。对应的就有三个适配器,我们看个类图:

更具上面的情况我们需要用到几个东西,适配器Advice类型以及Advice类型所对应的拦截器

1、适配器
适配器在Spring中是怎么把通知类和拦截类进行转换的呢,我们先看适配器的接口。定义了两个方法,分别是supportsAdvice()和getInterceptor()。

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

其实很简单,可以看出转换的方法就是getInterceptor(),通过supportsAdvice()进行判断

我们看前置通知的适配器的实现类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);
	}
}

getInterceptor()方法中,调用了对应的拦截类的构造器创建对应的拦截器返回,传入通知类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();
  }
 
}

那么在哪里初始化这些适配器呢,或者这些拦截器是怎么被处理的,我们看DefaultAdvisorAdapterRegistry()

public class DefaultAdvisorAdapterRegistry implements AdvisorAdapterRegistry, Serializable {
 
  //将Advisor转成拦截器,存到该变量中
  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);
  }
    
    //获取所有的拦截器
    @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);
        }
        //遍历adapters集合
        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]);
    }
}

适配器模式在这里就是把通知类转为拦截器类,转为拦截类之后,就添加到拦截器集合中。添加到拦截器集合之后,就用到了责任链模式,在ReflectiveMethodInvocation类被调用,我们看JDK动态代理JdkDynamicAopProxy的invoke()方法。

@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);
        }
    }
}

这里可能没学过责任链模式的同学会看得有点晕,但是学过责任链模式应该很容易看懂,这其实跟SpringMVC的拦截器的逻辑实现几乎一样的。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值