首页 > 编程语言 >【Spring AOP】【八】Spring AOP源码解析-拦截器/通知器链的执行顺序

【Spring AOP】【八】Spring AOP源码解析-拦截器/通知器链的执行顺序

时间:2023-02-22 22:26:30浏览次数:38  
标签:拦截器 return int Spring getOrder 通知 AOP 排序 public

1  前言

上节我们看过了代理对象执行方法的大致过程,我们留着通知器链的具体执行没说,这节我们先讲解一下通知器的执行顺序。

通知器或者叫拦截器,叫法不一样,这里我们还是都统一叫通知器吧。

这是我的AOP类,方便调试。

 1 @Component
 2 @Aspect
 3 public class MyAspect {
 4 
 5     @Pointcut("execution( * com.virtuous.demo.spring.cycle.a.A.*(..))")
 6     public void myPointCut() {
 7     }
 8 
 9 
10     @After("myPointCut()")
11     public void myAfter(JoinPoint point) {
12         System.out.println("myAfter");
13     }
14 
15     @Before("myPointCut()")
16     public void myBefore(JoinPoint point) {
17         System.out.println("myBefore");
18     }
19 
20 
21     @Around("myPointCut()")
22     public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
23         System.out.println("around before");
24         Object res = joinPoint.proceed();
25         System.out.println("around after");
26         return res;
27     }
28 
29     @AfterThrowing(value = "myPointCut()", throwing = "e")
30     public void afterThrowing(Exception e) {
31         System.out.println("afterThrowing");
32     }
33 
34 
35     @AfterReturning(value = "myPointCut()")
36     public void afterReturning() {
37         System.out.println("afterReturning");
38     }
39 
40 
41 }
View Code

2  通知器类型的演变过程

首先我们简单回忆一下,我们的通知器的一个类型变化过程,辅助你更好的理解,因为边看边调试中间做了好几次转换封装有点麻,我大概汇总下:

  1. XML配置解析或者是注解方式的解析,都会生成对应的通知类
  2. 创建代理的时候,对我们的通知类又进行的一个wrap操作,也就是类型的转变
  3. 执行代理的时候,把我们的通知器转变成拦截器(当前有的通知类其实已经实现了拦截器的接口,所以有的就不需要进行适配器的变换)

那么我大概总结了一下,我是针对我的Aspect每个阶段调试总结的哈,可能每个人版本或者配置不一样,但是应该都差不多。

 调试结果:

3  通知器的顺序来源

我们的通知器是有顺序的,那这个顺序是什么时候确定的呢,这个顺序有涉及到两个地方:

  • 第一个排序是在获取所有的通知器的时候,也就是解析有哪些通知器的时候,会对一个Aspect里的所有通知进行排序(记住这里只是对一个Aspect里的)
  • 第二次排序是在创建代理的时候,获取当前bean适合的通知器的时候会做排序

3.1 第一次排序

我们先来看下第一次排序时机的调用过程,如图:

那么我们看下源码的过程:

private List<Method> getAdvisorMethods(Class<?> aspectClass) {
    List<Method> methods = new ArrayList<>();
    ReflectionUtils.doWithMethods(aspectClass, methods::add, adviceMethodFilter);
    if (methods.size() > 1) {
        // 对某个Aspect里的所有通知器进行排序
        methods.sort(adviceMethodComparator);
    }
    return methods;
}
private static final Comparator<Method> adviceMethodComparator;
static {
    /**
     * 整体的排序思路就是:先按下边顺序排,然后通知器类型相同的再按字符串排序(字母首字母以及长度升序)
     * 注意看这个顺序:Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class
     */
    Comparator<Method> adviceKindComparator = new ConvertingComparator<>(
            new InstanceComparator<>(
                    Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class),
            (Converter<Method, Annotation>) method -> {
                AspectJAnnotation<?> ann = AbstractAspectJAdvisorFactory.findAspectJAnnotationOnMethod(method);
                return (ann != null ? ann.getAnnotation() : null);
            });
    Comparator<Method> methodNameComparator = new ConvertingComparator<>(Method::getName);
    adviceMethodComparator = adviceKindComparator.thenComparing(methodNameComparator);
}
public InstanceComparator(Class<?>... instanceOrder) {
    Assert.notNull(instanceOrder, "'instanceOrder' array must not be null");
    this.instanceOrder = instanceOrder;
}
@Override
public int compare(T o1, T o2) {
    int i1 = getOrder(o1);
    int i2 = getOrder(o2);
    return (Integer.compare(i1, i2));
}
/**
 * InstanceComparator 
 * instanceOrder也就是你刚才传过来的注解类的顺序
 * @param object
 * @return
 */
private int getOrder(@Nullable T object) {
    if (object != null) {
        for (int i = 0; i < this.instanceOrder.length; i++) {
            if (this.instanceOrder[i].isInstance(object)) {
                return i;
            }
        }
    }
    return this.instanceOrder.length;
}

看一下我的排序结果:

所以针对第一次排序,大概思路就是:

  1. 每个Aspect先按照Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class的顺序排好,至于Aspect和Aspect谁在前谁在后这里不处理;
  2. 通知类型相同的情况下按照字符串顺序升序排序。

3.2 第二次排序

接下里我们看下第二次排序的时机,这次排序有点懵,东西很多,我先前置几个知识点,否则有点晕。

3.2.1 OrderComparator

Spring有个排序器OrderComparator,这个的排序规则我们看下源码:

/**
 * @see Ordered          接口  有个getOrder() 方法   你懂的就是返回你的排序值
 * @see PriorityOrdered  接口  没有任何方法 只是一个标志  就是标志我最强我是老大都听我的
 * @see org.springframework.core.annotation.AnnotationAwareOrderComparator  对注解的增强 增加OrderComparator对注解排序值的支持
 */
public class OrderComparator implements Comparator<Object> {
    public static final OrderComparator INSTANCE = new OrderComparator();
    public Comparator<Object> withSourceProvider(OrderSourceProvider sourceProvider) {
        return (o1, o2) -> doCompare(o1, o2, sourceProvider);
    }
    /**
     * !!!优先级排序 越小优先级越高 比如a的优先级高于b 那么 a.compare(b) == -1  别搞晕奥
     * 我们只看当前类的OrderComparator
     * 在不考虑OrderSourceProvider的前提下,那影响排序的因素就是 PriorityOrdered和Ordered接口两种方式
     * a、b 比较的话
     * 1、有且只有一个实现了PriorityOrdered 那谁的优先级就高
     * 2、都实现了或者都没实现的话,就getOrder()获取排序值
     *    没实现的话 会有默认值Ordered.LOWEST_PRECEDENCE
     *    然后就比较排序值大小  小的优先级高
     *
     */
    @Override
    public int compare(@Nullable Object o1, @Nullable Object o2) {
        return doCompare(o1, o2, null);
    }

    private int doCompare(@Nullable Object o1, @Nullable Object o2, @Nullable OrderSourceProvider sourceProvider) {
        boolean p1 = (o1 instanceof PriorityOrdered);
        boolean p2 = (o2 instanceof PriorityOrdered);
        if (p1 && !p2) {
            return -1;
        }
        else if (p2 && !p1) {
            return 1;
        }

        int i1 = getOrder(o1, sourceProvider);
        int i2 = getOrder(o2, sourceProvider);
        return Integer.compare(i1, i2);
    }
   protected int getOrder(@Nullable Object obj) {
      if (obj != null) {
          Integer order = findOrder(obj);
          if (order != null) {
              return order;
          }
      }
      return Ordered.LOWEST_PRECEDENCE;  // 没有排序值的话默认为Integer.MAX_VALUE,int最大值 别晕 最大表示优先级越低
    }  
}

正如我上边注释的哈,影响它的排序大小的因素有是否有实现PriorityOrdered接口标识、是否有实现Ordered接口都没有的话,也会有默认值,这样来比较。

3.2.2 AnnotationAwareOrderComparator

 AnnotationAwareOrderComparator这个类是上边类的子类,对上边的类的增强,主要就是findOrder的时候,先调用父类的方法,父类为空的话这个类会去从注解上去继续取排序值,这样来切进来逻辑。

@Override
@Nullable
protected Integer findOrder(Object obj) {
    // 先调用父类的
    Integer order = super.findOrder(obj);
    if (order != null) {
        return order;
    }
    // 父类为空的话则找注解上有没有排序值
    return findOrderFromAnnotation(obj);
}
// 具体怎么拿的就不看了
@Nullable
private Integer findOrderFromAnnotation(Object obj) {
    AnnotatedElement element = (obj instanceof AnnotatedElement ? (AnnotatedElement) obj : obj.getClass());
    MergedAnnotations annotations = MergedAnnotations.from(element, SearchStrategy.TYPE_HIERARCHY);
    Integer order = OrderUtils.getOrderFromAnnotations(element, annotations);
    if (order == null && obj instanceof DecoratingProxy) {
        return findOrderFromAnnotation(((DecoratingProxy) obj).getDecoratedClass());
    }
    return order;
}

AnnotationAwareOrderComparator,它带来了注解的增强 @Order(可以在类上、方法上、属性上)、@Priority(可以在类上、方法参数上),它影响的是findOrder的增强, OrderComparator先去找排序值 找不到的话才会AnnotationAwareOrderComparator注解中去找,最后都找不到的话会有默认值Ordered.LOWEST_PRECEDENCE。

3.2.3 PartialOrder.sort偏序排序

偏序排序相对应的有个全序排序,全序排序我们都知道就是整个数组都是有顺序的,那么偏序排序就是部分排序,不是所有的都有序,只是数组中的某些元素有先后顺序,这样的排序为偏序排序。

我们先看下偏序排序的方法入口:

// 也就是说集合中的元素都要是PartialComparable类型的
public static <T extends PartialComparable> List<T> sort(List<T> objects) {}
public interface PartialComparable {
    /**
     * 主要排序
     * 1 表示大于other
     * -1表示小于other
     * 0 表示两者无关系
     * @param other
     * @return
     */
    int compareTo(Object other);

    /**
     * 次要排序
     * 也就是对主要排序的辅助排序
     * !!当主要排序结果为0时,才会调用该方法进行次要排序
     * @param other
     * @return
     */
    int fallbackCompareTo(Object other);
}

那么对应到我们这里通知器里的实现是怎么呢,我们看下:

/**
 * 我们通知器排序的偏序排序的元素类
 * 即每个元素都要实现的PartialComparable的元素包装类
 */
private static class PartiallyComparableAdvisorHolder implements PartialComparable {
    private final Advisor advisor;
    private final Comparator<Advisor> comparator;
    /**
     * 我们看到其实就是把通知和一个比较器传进来
     * @param advisor
     * @param comparator
     */
    public PartiallyComparableAdvisorHolder(Advisor advisor, Comparator<Advisor> comparator) {
        this.advisor = advisor;
        this.comparator = comparator;
    }
    /**
     * 这个是什么呢,就是我们刚才讲的上边的偏序排序的 主要排序
     * 那么这里的具体实现是什么呢?
     * 可以看到它是调用了参数里的comparator进行比较的
     * @param obj
     * @return
     */
    @Override
    public int compareTo(Object obj) {
        Advisor otherAdvisor = ((PartiallyComparableAdvisorHolder) obj).advisor;
        return this.comparator.compare(this.advisor, otherAdvisor);
    }
    /**
     * 次要排序 这里返回的0 也就是不排序不做处理
     * @param obj
     * @return
     */
    @Override
    public int fallbackCompareTo(Object obj) {
        return 0;
    }
}

3.2.4 通知器集合的比较器-AspectJPrecedenceComparator

好,那么我们来看下参数里的比较器,也就是AspectJPrecedenceComparator的源码:

partiallyComparableAdvisors.add(new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
private static final Comparator<Advisor> DEFAULT_PRECEDENCE_COMPARATOR = new AspectJPrecedenceComparator();
// 这里就是我们的通知器比较器
public AspectJPrecedenceComparator() {
    public AspectJPrecedenceComparator() {
        // 这个默认初始化的advisorComparator 其实也就是带注解的增强排序器AnnotationAwareOrderComparator
        this.advisorComparator = AnnotationAwareOrderComparator.INSTANCE;
    }

    @Override
    public int compare(Advisor o1, Advisor o2) {
        // 首先是AnnotationAwareOrderComparator进行排序
        int advisorPrecedence = this.advisorComparator.compare(o1, o2);
        // 如果等于0表示两者没关系,并且是在一个Aspect里则调用comparePrecedenceWithinAspect
        if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
            advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
        }
        return advisorPrecedence;
    }

    private int comparePrecedenceWithinAspect(Advisor advisor1, Advisor advisor2) {
        // 两个通知器是否有一个是后置通知
        boolean oneOrOtherIsAfterAdvice =
                (AspectJAopUtils.isAfterAdvice(advisor1) || AspectJAopUtils.isAfterAdvice(advisor2));
        /**
         * 调用两个的getAspectDeclarationOrder 进行比较 
         * 这里给你们埋个引子,adviceDeclarationOrderDelta其实会一直等于0的 
         * !!!因为getAspectDeclarationOrder值所有的通知器都是相等的,并且都是0
         */
        int adviceDeclarationOrderDelta = getAspectDeclarationOrder(advisor1) - getAspectDeclarationOrder(advisor2);
        // 如果有后置通知器
        if (oneOrOtherIsAfterAdvice) {
            // adviceDeclarationOrderDelta小于0 说明advisor1的值小 说明优先级高 那么就应该排在前边 就返回-1
            if (adviceDeclarationOrderDelta < 0) {
                return LOWER_PRECEDENCE;
            }
            // adviceDeclarationOrderDelta大于0 说明advisor1的值大 说明优先级低 那么就应该排在后边 就返回1
            else if (adviceDeclarationOrderDelta == 0) {
                return SAME_PRECEDENCE;
            }
            // 等于0 返回0不处理
            else {
                return HIGHER_PRECEDENCE;
            }
        }
        // 下边一样
        else {
            if (adviceDeclarationOrderDelta < 0) {
                return HIGHER_PRECEDENCE;
            }
            else if (adviceDeclarationOrderDelta == 0) {
                return SAME_PRECEDENCE;
            }
            else {
                return LOWER_PRECEDENCE;
            }
        }
    }
}

3.2.5 通知器外层的包装-InstantiationModelAwarePointcutAdvisorImpl

我们上边提过,在解析配置或者XML的AOP配置时,都会把每个通知类外边包一层InstantiationModelAwarePointcutAdvisorImpl,我们回忆下部分源码哈,如果这个你不知道的话,建议你再看一遍。

// 记住这里的factory类型,下边会用到
MetadataAwareAspectInstanceFactory factory = new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName); // 获取通知器 List<Advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
// 参数aspectInstanceFactory就是上边传过来的factory
public List<Advisor> getAdvisors(MetadataAwareAspectInstanceFactory aspectInstanceFactory) {
    // 获取 aspectClass 和 aspectName
    Class<?> aspectClass = aspectInstanceFactory.getAspectMetadata().getAspectClass();
    String aspectName = aspectInstanceFactory.getAspectMetadata().getAspectName();
    validate(aspectClass);
    MetadataAwareAspectInstanceFactory lazySingletonAspectInstanceFactory =
            new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory);
    List<Advisor> advisors = new ArrayList<>();
    // getAdvisorMethods 用于返回不包含 @Pointcut 注解的方法
    for (Method method : getAdvisorMethods(aspectClass)) {
        // 为每个方法分别调用 getAdvisor 方法  看这里的0 对应的参数就是下边方法的declarationOrder
        Advisor advisor = getAdvisor(method, lazySingletonAspectInstanceFactory, 0, aspectName);
        if (advisor != null) {
            advisors.add(advisor);
        }
}
// aspectInstanceFactory就是上边的new LazySingletonAspectInstanceFactoryDecortor(aspectInstantceFactory)
public Advisor getAdvisor(Method candidateAdviceMethod, MetadataAwareAspectInstanceFactory aspectInstanceFactory,
        int declarationOrderInAspect, String aspectName) {
    validate(aspectInstanceFactory.getAspectMetadata().getAspectClass());
    // 获取切点实现类
    AspectJExpressionPointcut expressionPointcut = getPointcut(
            candidateAdviceMethod, aspectInstanceFactory.getAspectMetadata().getAspectClass());
    if (expressionPointcut == null) {
        return null;
    }
    // 创建 Advisor 实现类
    return new InstantiationModelAwarePointcutAdvisorImpl(expressionPointcut, candidateAdviceMethod,
            this, aspectInstanceFactory, declarationOrderInAspect, aspectName);
}

我们还要再仔细看一个细节就是InstantiationModelAwarePointcutAdvisorImpl这个类实现了AspectJPrecedenceInformation,而AspectJPrecedenceInformation又继承了Ordered接口,那么说明什么呢,也就是我们的每个通知器都实现了Ordered接口,都有getOrder()方法咯,那么我们看下getOrder()的实现:

// InstantiationModelAwarePointcutAdvisorImpl里的getOrder()
@Override public int getOrder() { return this.aspectInstanceFactory.getOrder(); } // aspectInstanceFactory是什么?就是上边的new LazySingletonAspectInstanceFactoryDecorator(aspectInstanceFactory); // 那么继续进入LazySingletonAspectInstanceFactoryDecorator的getOrder() @Override public int getOrder() { return this.maaif.getOrder(); } // 继续进入this.maaif 也就是BeanFactoryAspectInstanceFactory的getOrder() @Override public int getOrder() { // this.name也就是通知器所属的Aspect的bean的name Class<?> type = this.beanFactory.getType(this.name); if (type != null) { // 当切面类即Aspect实现了Ordered并且Aspect是单例的 就返回切面类Aspect的getOrder() if (Ordered.class.isAssignableFrom(type) && this.beanFactory.isSingleton(this.name)) { return ((Ordered) this.beanFactory.getBean(this.name)).getOrder(); } // 否则就返回切面类Aspect注解上的@Order的值,没有的话默认Ordered.LOWEST_PRECEDENCE return OrderUtils.getOrder(type, Ordered.LOWEST_PRECEDENCE); }
// 默认返回 return Ordered.LOWEST_PRECEDENCE; }

好了,到这里为止第二次排序过程中的几个很重要的知识点就介绍完了,随着介绍其实第二次排序怎么排我们大概也有了眉目,我们看下源码入口:

protected List<Advisor> sortAdvisors(List<Advisor> advisors) {
    List<PartiallyComparableAdvisorHolder> partiallyComparableAdvisors = new ArrayList<>(advisors.size());
    for (Advisor advisor : advisors) {
        partiallyComparableAdvisors.add(
                new PartiallyComparableAdvisorHolder(advisor, DEFAULT_PRECEDENCE_COMPARATOR));
    }
    // 就是这里把每个通知器包装成PartialComparable,然后调用PartialOrder.sort进行一个偏序排序
    List<PartiallyComparableAdvisorHolder> sorted = PartialOrder.sort(partiallyComparableAdvisors);
    if (sorted != null) {
        List<Advisor> result = new ArrayList<>(advisors.size());
        for (PartiallyComparableAdvisorHolder pcAdvisor : sorted) {
            result.add(pcAdvisor.getAdvisor());
        }
        return result;
    }
    else {
        return super.sortAdvisors(advisors);
    }
}

偏序排序的比较器也就是AspectJPrecedenceComparator的compare方法,那我们再来看下:

public interface PartialComparable {
    @Override
    public int compare(Advisor o1, Advisor o2) {
        /**
         * 首先advisorComparator就是AnnotationAwareOrderComparator进行排序
         * AnnotationAwareOrderComparator排序我们说过取值优先级从PriorityOrdered接口、Ordered接口、@Order注解、@Prio
         * 我们上边看到我们的每个通知器其实都实现了Ordered接口,
         * getOrder的值的取法:
         *         1、切面类Aspect有没有实现Ordered接口,并且是单例的就返回切面类的getOrder值
         *         2、否则就从切面类Aspect上取@Order注解的值, 没有注解返回Integer.MAX 即最小优先级
         * 说白了:
         *      1、一个切面类Aspect里的所有通知器的getOrder都是相等的 默认都是Integer.MAX 
         *      2、@Order能写在方法在但是对于通知器的方法不好使不管用的
         *      3、当切面类Aspect实现了Ordered接口的话,实现getOrder()接口 
         *      4、当切面类Aspect上有注解@Order的话 取注解的值  当然实现Ordered接口优先于注解@Order
         */
        int advisorPrecedence = this.advisorComparator.compare(o1, o2);
        // comparePrecedenceWithinAspect这个其实没啥用 因为在一个切面里通知器的排序值都是相等的
        if (advisorPrecedence == SAME_PRECEDENCE && declaredInSameAspect(o1, o2)) {
            advisorPrecedence = comparePrecedenceWithinAspect(o1, o2);
        }
        return advisorPrecedence;
    }
}

好了,到这里我们通知器的顺序来源,就结束了,不知道你晕没晕,这里我们总结就一句话:其实比较的不是每个通知器,而是比较的是每个通知器所属的Aspect的排序值。

这句话你认可不,每个通知器其实都是一组一组的排序,比如有Aspect1、Aspect2,  假如Aspect1的优先级高,那么通知器的顺序就是Aspect1所有的通知器、然后是Aspect2所有的通知器,Aspect1或者Aspect2里每个器又是按照【Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class】的顺序排列,相同类型的按照方法的全名字(包名+类名+方法名)即字符串升序排列;

4 小结

好了,这节我们主要讲了一下通知器的顺序问题,东西很多,但是最后其实看起来能控制顺序的也就是Aspect自己,当然有理解错误的地方欢迎指正哈,下节我们看看执行过程。

 

标签:拦截器,return,int,Spring,getOrder,通知,AOP,排序,public
From: https://www.cnblogs.com/kukuxjx/p/17142351.html

相关文章

  • spring-申明式事务
    一.什么是事务事务的原则是:处于事务中的sql代码块会保持一致状态,即要么都能改变数据库,要么都不能改变数据库ACID原则:原子性一致性隔离性多个业务可能操作同一个业......
  • ssm学习笔记23001-spring+mybatis修改删除和查询
    spring+mybatis修改删除和查询1、在UserMapper接口类中,创建接口在UserMapper接口类中,创建接口packagecom.wjw.mybatis.mapper;importcom.wjw.mybatis.pojo.User;......
  • spring5随笔
    1、Spring1.1、简介Spring:春天----->给软件行业带来了春天!2002,首次推出了Spring框架的雏形:interface21框架!Spring框架即以interface21框架为基础,经过重新设计,......
  • 【Spring 源码】001-环境准备:Spring模块梳理
    【Spring源码】001-环境准备:Spring模块梳理文章目录​​【Spring源码】001-环境准备:Spring模块梳理​​​​一、本节课程的目的​​​​二、出于信仰学习Spring的简史​​......
  • 整合mybatis-spring
    一.整合mybatis步骤:第一步:导入相关的jar包:junitmybatismysql数据库spring相关的aop植入mybatis-spring【新包,兼容mybatis和spring】<dependencies>......
  • 利用SpringBoot自动装配原理自定义starter
    在使用SpringBoot时候我们经常会碰到引入很多的starter的自动化配置,有了这些starter以后我们就可以很轻松的完成一个企业级的开发项目,很多小朋友就会对于starter很神奇,其实......
  • IDEA一键运行多个springboot微服务模块
    效果图  如果在idea工具底部看到Services      那么点击可以看到RunDashBoard面板,SpringBoot->Running是启动的多个微服务模块 如果没有Services......
  • 拦截器和过滤器
    过滤器过滤器实际上就是对web资源进行拦截,做一些处理后再交给下一个过滤器或servlet处理,通常都是用来拦截request进行处理的,也可以对返回的response进行拦截处理为什么......
  • Mybatis-Plus取消自动转驼峰拦截器
    背景项目使用Mybatis-Plus,开启了全局结果集字段转驼峰map-underscore-to-camel-case:true。开启之后如果需要返回下划线需要自定义resultMap现需要返回List<Map>,且返回......
  • 理论:第十二章:Dubbo的运行原理,支持什么协议,与SpringCould相比它为什么效率要高一些,Zook
    Dubbo简单的介绍一下Dubbo?(Dubbo是什么)dubbo就是个服务调用的东东。为什么怎么说呢?因为Dubbo是由阿里开源的一个RPC分布式框架那么RPC是什么呢?就是不同的应用部署到......