Talk about sentinel’s DefaultSlotsChainBuilder

  sentinel

Order

This article mainly studies sentinel’s DefaultSlotsChainBuilder

DefaultSlotsChainBuilder

com/alibaba/csp/sentinel/slots/DefaultSlotsChainBuilder.java

public class DefaultSlotsChainBuilder implements SlotsChainBuilder {

    @Override
    public ProcessorSlotChain build() {
        ProcessorSlotChain chain = new DefaultProcessorSlotChain();
        chain.addLast(new NodeSelectorSlot());
        chain.addLast(new ClusterBuilderSlot());
        chain.addLast(new LogSlot());
        chain.addLast(new StatisticSlot());
        chain.addLast(new SystemSlot());
        chain.addLast(new AuthoritySlot());
        chain.addLast(new FlowSlot());
        chain.addLast(new DegradeSlot());

        return chain;
    }

}
  • Implement the build method, return DefaultProcessorSlotChain, and use it to add the addLast method to construct a chain call.

DefaultProcessorSlotChain

com/alibaba/csp/sentinel/slotchain/DefaultProcessorSlotChain.java

public class DefaultProcessorSlotChain extends ProcessorSlotChain {

    AbstractLinkedProcessorSlot<?> first = new AbstractLinkedProcessorSlot<Object>() {

        @Override
        public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, Object... args)
            throws Throwable {
            super.fireEntry(context, resourceWrapper, t, count, args);
        }

        @Override
        public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
            super.fireExit(context, resourceWrapper, count, args);
        }

    };
    AbstractLinkedProcessorSlot<?> end = first;

    @Override
    public void addFirst(AbstractLinkedProcessorSlot<?> protocolProcessor) {
        protocolProcessor.setNext(first.getNext());
        first.setNext(protocolProcessor);
        if (end == first) {
            end = protocolProcessor;
        }
    }

    @Override
    public void addLast(AbstractLinkedProcessorSlot<?> protocolProcessor) {
        end.setNext(protocolProcessor);
        end = protocolProcessor;
    }

    /**
     * Same as {@link #addLast(AbstractLinkedProcessorSlot)}.
     *
     * @param next processor to be added.
     */
    @Override
    public void setNext(AbstractLinkedProcessorSlot<?> next) {
        addLast(next);
    }

    @Override
    public AbstractLinkedProcessorSlot<?> getNext() {
        return first.getNext();
    }

    @Override
    public void entry(Context context, ResourceWrapper resourceWrapper, Object t, int count, Object... args)
        throws Throwable {
        first.transformEntry(context, resourceWrapper, t, count, args);
    }

    @Override
    public void exit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        first.exit(context, resourceWrapper, count, args);
    }

}
  • There are mainly two attributes, one is first and the other is end. They are of type AbstractLinkedProcessorSlot
  • The main methods are addFirst, addLast, setNext
  • First is set by default here, and then the chain call is mainly opened through the getNext method, which returns first’s next.

AbstractLinkedProcessorSlot

com/alibaba/csp/sentinel/slotchain/AbstractLinkedProcessorSlot.java

public abstract class AbstractLinkedProcessorSlot<T> implements ProcessorSlot<T> {

    private AbstractLinkedProcessorSlot<?> next = null;

    @Override
    public void fireEntry(Context context, ResourceWrapper resourceWrapper, Object obj, int count, Object... args)
        throws Throwable {
        if (next != null) {
            next.transformEntry(context, resourceWrapper, obj, count, args);
        }
    }

    @SuppressWarnings("unchecked")
    void transformEntry(Context context, ResourceWrapper resourceWrapper, Object o, int count, Object... args)
        throws Throwable {
        T t = (T)o;
        entry(context, resourceWrapper, t, count, args);
    }

    @Override
    public void fireExit(Context context, ResourceWrapper resourceWrapper, int count, Object... args) {
        if (next != null) {
            next.exit(context, resourceWrapper, count, args);
        }
    }

    public AbstractLinkedProcessorSlot<?> getNext() {
        return next;
    }

    public void setNext(AbstractLinkedProcessorSlot<?> next) {
        this.next = next;
    }

}
  • AbstractLinkedProcessorSlot is the base class for all slots and has a next attribute to identify the next slot
  • Entry is the entry of the whole chain call. The default is to trigger fireEntry. If next is not null, then next’s transformEntry is called, and then next’s Entry method is called.
  • The entry method of the subclass will do some pre-verification work and then call the fireEntry method to complete the whole chain call.

Summary

Sentinel uses the responsibility chain pattern to execute various slot logics, and its construction is carried out through DefaultSlotsChainBuilder.

doc