源码中的设计模式之拦截器设计模式

源码中的设计模式之拦截器设计模式

前言

这个拦截器的源码是从jersey框架下扒出来的,拦截器在这个框架中是对输入输出流信息的拦截,过滤器则是对请求与响应的过滤。

一、ReaderInterceptorExecutor源码

删除不必要的代码留下核心代码~~
读取拦截执行器下面 成员变量Iterator interceptors是核心,在创捷执行器的时候被初始化,这个集合interceptors是在服务启动时且相关配置OK的条件下通过一个Provider对象配置好的。process()方法就是拦截器执行器的执行方法来自接口ReaderInterceptorContext,通过遍历集合 interceptors获取下一个拦截器,拦截器主要执行的业务逻辑就在aroundReadFrom,这个方法将自己的引用当参数传入了aroundReadFrom()方法中(这里经典,嘿,get到了)。拦截器的链的最末端拦截器是TerminalReaderInterceptor对象。

/**
 * Represents reader interceptor chain executor for both client and server side.
 * It constructs wrapped interceptor chain and invokes it. At the end of the chain
 * a {@link MessageBodyReader message body reader} execution interceptor is inserted,
 * which finally reads an entity from the output stream provided by the chain.
 *
 * @author Miroslav Fuksa
 * @author Jakub Podlesak (jakub.podlesak at oracle.com)
 */
public final class ReaderInterceptorExecutor extends InterceptorExecutor<ReaderInterceptor>
        implements ReaderInterceptorContext, ServiceLocatorSupplier {

    private static final Logger LOGGER = Logger.getLogger(ReaderInterceptorExecutor.class.getName());

    private final MultivaluedMap<String, String> headers;
    private final Iterator<ReaderInterceptor> interceptors;
    private final MessageBodyWorkers workers;
    private final boolean translateNce;

    private final ServiceLocator serviceLocator;

    private InputStream inputStream;
    private int processedCount;
    public ReaderInterceptorExecutor(final Class<?> rawType, final Type type,
                                     final Annotation[] annotations,
                                     final MediaType mediaType,
                                     final MultivaluedMap<String, String> headers,
                                     final PropertiesDelegate propertiesDelegate,
                                     final InputStream inputStream,
                                     final MessageBodyWorkers workers,
                                     final Iterable<ReaderInterceptor> readerInterceptors,
                                     final boolean translateNce,
                                     final ServiceLocator serviceLocator) {

        super(rawType, type, annotations, mediaType, propertiesDelegate);
        this.headers = headers;
        this.inputStream = inputStream;
        this.workers = workers;
        this.translateNce = translateNce;
        this.serviceLocator = serviceLocator;

        final List<ReaderInterceptor> effectiveInterceptors = Lists.newArrayList(readerInterceptors);
        effectiveInterceptors.add(new TerminalReaderInterceptor());

        this.interceptors = effectiveInterceptors.iterator();
        this.processedCount = 0;
    }

    /**
     * Starts the interceptor chain execution.
     *
     * @return an entity read from the stream.
     */
    @Override
    @SuppressWarnings("unchecked")
    public Object proceed() throws IOException {
        if (!interceptors.hasNext()) {
            throw new ProcessingException(LocalizationMessages.ERROR_INTERCEPTOR_READER_PROCEED());
        }
        final ReaderInterceptor interceptor = interceptors.next();
        traceBefore(interceptor, MsgTraceEvent.RI_BEFORE);
        try {
            return interceptor.aroundReadFrom(this);
        } finally {
            processedCount++;
            traceAfter(interceptor, MsgTraceEvent.RI_AFTER);
        }
    }

    

   
    /**
     * Terminal reader interceptor which choose the appropriate {@link MessageBodyReader}
     * and reads the entity from the input stream. The order of actions is the following: <br>
     * 1. choose the appropriate {@link MessageBodyReader} <br>
     * 3. reads the entity from the output stream <br>
     */
    private class TerminalReaderInterceptor implements ReaderInterceptor {

        @Override
        @SuppressWarnings("unchecked")
        public Object aroundReadFrom(final ReaderInterceptorContext context) throws IOException, WebApplicationException {
            processedCount--; //this is not regular interceptor -> count down

            traceBefore(null, MsgTraceEvent.RI_BEFORE);
            try {
                final TracingLogger tracingLogger = getTracingLogger();
                if (tracingLogger.isLogEnabled(MsgTraceEvent.MBR_FIND)) {
                    tracingLogger.log(MsgTraceEvent.MBR_FIND,
                            context.getType().getName(),
                            (context.getGenericType() instanceof Class
                                    ? ((Class) context.getGenericType()).getName() : context.getGenericType()),
                            String.valueOf(context.getMediaType()), java.util.Arrays.toString(context.getAnnotations()));
                }

                final MessageBodyReader bodyReader = workers.getMessageBodyReader(
                        context.getType(),
                        context.getGenericType(),
                        context.getAnnotations(),
                        context.getMediaType(),
                        ReaderInterceptorExecutor.this);

                final EntityInputStream input = new EntityInputStream(context.getInputStream());

                if (bodyReader == null) {
                    if (input.isEmpty() && !context.getHeaders().containsKey(HttpHeaders.CONTENT_TYPE)) {
                        return null;
                    } else {
                        LOGGER.log(Level.FINE, LocalizationMessages.ERROR_NOTFOUND_MESSAGEBODYREADER(context.getMediaType(),
                                context.getType(), context.getGenericType()));
                        throw new MessageBodyProviderNotFoundException(LocalizationMessages.ERROR_NOTFOUND_MESSAGEBODYREADER(
                                context.getMediaType(), context.getType(), context.getGenericType()));
                    }
                }
                Object entity = invokeReadFrom(context, bodyReader, input);

                if (bodyReader instanceof CompletableReader) {
                    entity = ((CompletableReader) bodyReader).complete(entity);
                }
                return entity;
            } finally {
                clearLastTracedInterceptor();
                traceAfter(null, MsgTraceEvent.RI_AFTER);
            }
        }
    }
}


二.输入端拦截器接口ReaderInterceptor

实现该拦截器接口的类,必须需要显性调用 context.proceed()才能让executor执行当前拦截器链的下一个拦截器,否则就默认当前输入流就被拦截不许继续向下执行。

public interface ReaderInterceptor {

    /**
     * Interceptor method wrapping calls to {@link MessageBodyReader#readFrom} method.
     *
     * The parameters of the wrapped method called are available from {@code context}.
     * Implementations of this method SHOULD explicitly call {@link ReaderInterceptorContext#proceed}
     * to invoke the next interceptor in the chain, and ultimately the wrapped
     * {@link MessageBodyReader#readFrom} method.
     *
     * @param context invocation context.
     * @return result of next interceptor invoked or the wrapped method if last interceptor in chain.
     * @throws java.io.IOException if an IO error arises or is thrown by the wrapped
     *                             {@code MessageBodyReader.readFrom} method.
     * @throws javax.ws.rs.WebApplicationException
     *                             thrown by the wrapped {@code MessageBodyReader.readFrom} method.
     */
    public Object aroundReadFrom(ReaderInterceptorContext context)
            throws java.io.IOException, javax.ws.rs.WebApplicationException;
}

三.框架自己实现的一些拦截器接口的类ContentEncoder

@Priority(Priorities.ENTITY_CODER)
@Contract
public abstract class ContentEncoder implements ReaderInterceptor, WriterInterceptor {
    private final Set<String> supportedEncodings;

    protected ContentEncoder(String... supportedEncodings) {
        if (supportedEncodings.length == 0) {
            throw new IllegalArgumentException();
        }
        this.supportedEncodings = Collections.unmodifiableSet(Sets.newHashSet(Arrays.asList(supportedEncodings)));
    }

    public final Set<String> getSupportedEncodings() {
        return supportedEncodings;
    }

    public abstract InputStream decode(String contentEncoding, InputStream encodedStream) throws IOException;

    public abstract OutputStream encode(String contentEncoding, OutputStream entityStream) throws IOException;

    @Override
    public final Object aroundReadFrom(ReaderInterceptorContext context) throws IOException, WebApplicationException {
        String contentEncoding = context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);
        if (contentEncoding != null && getSupportedEncodings().contains(contentEncoding)) {
            context.setInputStream(decode(contentEncoding, context.getInputStream()));
        }
        return context.proceed();
    }

    @Override
    public final void aroundWriteTo(WriterInterceptorContext context) throws IOException, WebApplicationException {
        // must remove Content-Length header since the encoded message will have a different length

        String contentEncoding = (String) context.getHeaders().getFirst(HttpHeaders.CONTENT_ENCODING);
        if (contentEncoding != null && getSupportedEncodings().contains(contentEncoding)) {
            context.setOutputStream(encode(contentEncoding, context.getOutputStream()));
        }
        context.proceed();
    }
}

四. MessageBodyFactory

这家伙就是调用拦截器的家伙,其实它也是给InboundMessageContext,OutboundMessageContext干活。分别处理输入输出的上下文信息,
再往前找就是ContainerRequest(Jersey 容器的 请求上下文专门处理来自客户端的每一个请求),再往前就到了ServerRuntime(一个服务端的请求运行时)。


public class MessageBodyFactory implements MessageBodyWorkers {

    private static final Logger LOGGER = Logger.getLogger(MessageBodyFactory.class.getName());

   

    
    @Override
    public Object readFrom(final Class<?> rawType,
                           final Type type,
                           final Annotation[] annotations,
                           final MediaType mediaType,
                           final MultivaluedMap<String, String> httpHeaders,
                           final PropertiesDelegate propertiesDelegate,
                           final InputStream entityStream,
                           final Iterable<ReaderInterceptor> readerInterceptors,
                           final boolean translateNce) throws WebApplicationException, IOException {

        final ReaderInterceptorExecutor executor = new ReaderInterceptorExecutor(
                rawType,
                type,
                annotations,
                mediaType,
                httpHeaders,
                propertiesDelegate,
                entityStream,
                this,
                readerInterceptors,
                translateNce,
                serviceLocator);

        final TracingLogger tracingLogger = TracingLogger.getInstance(propertiesDelegate);
        final long timestamp = tracingLogger.timestamp(MsgTraceEvent.RI_SUMMARY);

        try {
            final Object instance = executor.proceed();
            if (!(instance instanceof Closeable) && !(instance instanceof Source)) {
                final InputStream stream = executor.getInputStream();
                if (stream != entityStream && stream != null) {
                    // We only close stream if it differs from the received entity stream,
                    // otherwise we let the caller close the stream.
                    ReaderWriter.safelyClose(stream);
                }
            }

            return instance;
        } finally {
            tracingLogger.logDuration(MsgTraceEvent.RI_SUMMARY, timestamp, executor.getProcessedCount());
        }
    }

    @Override
    public OutputStream writeTo(final Object t,
                                final Class<?> rawType,
                                final Type type,
                                final Annotation[] annotations,
                                final MediaType mediaType,
                                final MultivaluedMap<String, Object> httpHeaders,
                                final PropertiesDelegate propertiesDelegate,
                                final OutputStream entityStream,
                                final Iterable<WriterInterceptor> writerInterceptors)
            throws IOException, WebApplicationException {

        final WriterInterceptorExecutor executor = new WriterInterceptorExecutor(
                t,
                rawType,
                type,
                annotations,
                mediaType,
                httpHeaders,
                propertiesDelegate,
                entityStream,
                this,
                writerInterceptors,
                serviceLocator);

        final TracingLogger tracingLogger = TracingLogger.getInstance(propertiesDelegate);
        final long timestamp = tracingLogger.timestamp(MsgTraceEvent.WI_SUMMARY);

        try {
            executor.proceed();
        } finally {
            tracingLogger.logDuration(MsgTraceEvent.WI_SUMMARY, timestamp, executor.getProcessedCount());
        }

        return executor.getOutputStream();
    }
}

水完才叫学到,嘿嘿。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值