从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【一起学Spring MVC】

每篇一句

想当火影的人没有近道可寻,当上火影的人同样无路可退

前言

HandlerMethod它作为Spring MVC的非公开API,可能绝大多数小伙伴都对它比较陌生,但我相信你对它又不是那么的生疏,因为你可能没用过但肯定见过。
比如Spring MVC的拦截器HandlerInterceptor的拦截方法的第三个入参Object handler,虽然它是Object类型,但其实绝大部分情况下我们都会当作HandlerMethod来使用;又比如我之前的这篇讲RequestMappingHandlerMapping的文章也大量的提到过HandlerMethod这个类。

经由我这么“忽悠”,你是否觉得它还是相对比较重要的一个类了呢?不管你信不信,反正我是这么认为的:HandlerMethod它是理解Spring MVC不可或缺的一个类,甚至可以说是你希望参与到Spring MVC的定制化里面来不可忽略的一个关键API。

HandlerMethod

HandlerMethod它不是一个接口,也不是个抽象类,且还是public的。HandlerMethod封装了很多属性,在访问请求方法的时候可以方便的访问到方法、方法参数、方法上的注解、所属类等并且对方法参数封装处理,也可以方便的访问到方法参数的注解等信息。

// @since 3.1
public class HandlerMethod {

    // Object类型,既可以是个Bean,也可以是个BeanName
    private final Object bean;
    // 如果是BeanName,拿就靠它拿出Bean实例了~
    @Nullable
    private final BeanFactory beanFactory;
    private final Class<?> beanType; // 该方法所属的类
    private final Method method; // 该方法本身
    private final Method bridgedMethod; // 被桥接的方法,如果method是原生的,它的值同method
    // 封装方法参数的类实例,**一个MethodParameter就是一个入参**
    // MethodParameter也是Spring抽象出来的一个非常重要的概念
    private final MethodParameter[] parameters;
    @Nullable
    private HttpStatus responseStatus; // http状态码(毕竟它要负责处理和返回)
    @Nullable
    private String responseStatusReason; // 如果状态码里还要复数原因,就是这个字段  可以为null

    // 通过createWithResolvedBean()解析此handlerMethod实例的handlerMethod。
    @Nullable
    private HandlerMethod resolvedFromHandlerMethod;
    // 标注在**接口入参**上的注解们(此处数据结构复杂,List+二维数组)
    @Nullable
    private volatile List<Annotation[][]> interfaceParameterAnnotations;

    // 它的构造方法众多  此处我只写出关键的步骤
    public HandlerMethod(Object bean, Method method) {
        ...
        this.beanType = ClassUtils.getUserClass(bean);
        this.bridgedMethod = BridgeMethodResolver.findBridgedMethod(method);
        this.parameters = initMethodParameters();
        ...
        evaluateResponseStatus();
    }
    // 这个构造方法抛出了一个异常NoSuchMethodException
    public HandlerMethod(Object bean, String methodName, Class<?>... parameterTypes) throws NoSuchMethodException {
        ...
        this.method = bean.getClass().getMethod(methodName, parameterTypes);
        this.parameters = initMethodParameters();
        ...
        evaluateResponseStatus();
    }
    // 此处传的是BeanName
    public HandlerMethod(String beanName, BeanFactory beanFactory, Method method) {
        ...
        // 这部判断:这个BeanName是必须存在的
        Class<?> beanType = beanFactory.getType(beanName);
        if (beanType == null) {
            throw new IllegalStateException("Cannot resolve bean type for bean with name '" + beanName + "'");
        }
        this.parameters = initMethodParameters();
        ...
        evaluateResponseStatus();
    }

    // 供给子类copy使用的
    protected HandlerMethod(HandlerMethod handlerMethod) { ... }

    // 所有构造都执行了两个方法:initMethodParameters和evaluateResponseStatus

    // 初始化该方法所有的入参,此处使用的是内部类HandlerMethodParameter
    // 注意:处理了泛型的~~~
    private MethodParameter[] initMethodParameters() {
        int count = this.bridgedMethod.getParameterCount();
        MethodParameter[] result = new MethodParameter[count];
        for (int i = 0; i < count; i++) {
            HandlerMethodParameter parameter = new HandlerMethodParameter(i);
            GenericTypeResolver.resolveParameterType(parameter, this.beanType);
            result[i] = parameter;
        }
        return result;
    }

    // 看看方法上是否有标注了@ResponseStatus注解(接口上或者父类 组合注解上都行)
    // 若方法上没有,还会去所在的类上去看看有没有标注此注解
    // 主要只解析这个注解,把它的两个属性code和reason拿过来,最后就是返回它俩了~~~
    // code状态码默认是HttpStatus.INTERNAL_SERVER_ERROR-->(500, "Internal Server Error")
    private void evaluateResponseStatus() {
        ResponseStatus annotation = getMethodAnnotation(ResponseStatus.class);
        if (annotation == null) {
            annotation = AnnotatedElementUtils.findMergedAnnotation(getBeanType(), ResponseStatus.class);
        }
        if (annotation != null) {
            this.responseStatus = annotation.code();
            this.responseStatusReason = annotation.reason();
        }
    }
    ... // 省略所有属性的get方法(无set方法)

    // 返回方法返回值的类型  此处也使用的MethodParameter
    public MethodParameter getReturnType() {
        return new HandlerMethodParameter(-1);
    }
    // 注意和上面的区别。举个列子:比如方法返回的是Object,但实际return “fsx”字符串
    // 那么上面返回永远是Object.class,下面你实际的值是什么类型就是什么类型
    public MethodParameter getReturnValueType(@Nullable Object returnValue) {
        return new ReturnValueMethodParameter(returnValue);
    }

    // 该方法的返回值是否是void
    public boolean isVoid() {
        return Void.TYPE.equals(getReturnType().getParameterType());
    }
    // 返回标注在方法上的指定类型的注解   父方法也成
    // 子类ServletInvocableHandlerMethod对下面两个方法都有复写~~~
    @Nullable
    public <A extends Annotation> A getMethodAnnotation(Class<A> annotationType) {
        return AnnotatedElementUtils.findMergedAnnotation(this.method, annotationType);
    }
    public <A extends Annotation> boolean hasMethodAnnotation(Class<A> annotationType) {
        return AnnotatedElementUtils.hasAnnotation(this.method, annotationType);
    }

    // resolvedFromHandlerMethod虽然它只能被构造进来,但是它实际是铜鼓调用下面方法赋值
    @Nullable
    public HandlerMethod getResolvedFromHandlerMethod() {
        return this.resolvedFromHandlerMethod;
    }
    // 根据string类型的BeanName把Bean拿出来,再new一个HandlerMethod出来~~~这才靠谱嘛
    public HandlerMethod createWithResolvedBean() {
        Object handler = this.bean;
        if (this.bean instanceof String) {
            Assert.state(this.beanFactory != null, "Cannot resolve bean name without BeanFactory");
            String beanName = (String) this.bean;
            handler = this.beanFactory.getBean(beanName);
        }
        return new HandlerMethod(this, handler);
    }

    public String getShortLogMessage() {
        return getBeanType().getName() + "#" + this.method.getName() + "[" + this.method.getParameterCount() + " args]";
    }

    // 这个方法是提供给内部类HandlerMethodParameter来使用的~~ 它使用的数据结构还是蛮复杂的
    private List<Annotation[][]> getInterfaceParameterAnnotations() {
        List<Annotation[][]> parameterAnnotations = this.interfaceParameterAnnotations;
        if (parameterAnnotations == null) {
            parameterAnnotations = new ArrayList<>();

            // 遍历该方法所在的类所有的实现的接口们(可以实现N个接口嘛)
            for (Class<?> ifc : this.method.getDeclaringClass().getInterfaces()) {

                // getMethods:拿到所有的public的方法,包括父接口的  接口里的私有方法可不会获取来
                for (Method candidate : ifc.getMethods()) {
                    // 判断这个接口方法是否正好是当前method复写的这个~~~
                    // 刚好是复写的方法,那就添加进来,标记为接口上的注解们~~~
                    if (isOverrideFor(candidate)) {
                        // getParameterAnnotations返回的是个二维数组~~~~
                        // 因为参数有多个,且每个参数前可以有多个注解
                        parameterAnnotations.add(candidate.getParameterAnnotations());
                    }
                }
            }
            this.interfaceParameterAnnotations = parameterAnnotations;
        }
        return parameterAnnotations;
    }

    // 看看内部类的关键步骤
    protected class HandlerMethodParameter extends SynthesizingMethodParameter {
        @Nullable
        private volatile Annotation[] combinedAnnotations;
        ...

        // 父类只会在本方法拿,这里支持到了接口级别~~~
        @Override
        public Annotation[] getParameterAnnotations() {
            Annotation[] anns = this.combinedAnnotations;
            if (anns == null) { // 都只需要解析一次
                anns = super.getParameterAnnotations();
                int index = getParameterIndex();
                if (index >= 0) { // 有入参才需要去分析嘛
                    for (Annotation[][] ifcAnns : getInterfaceParameterAnnotations()) {
                        if (index < ifcAnns.length) {
                            Annotation[] paramAnns = ifcAnns[index];
                            if (paramAnns.length > 0) {
                                List<Annotation> merged = new ArrayList<>(anns.length + paramAnns.length);
                                merged.addAll(Arrays.asList(anns));
                                for (Annotation paramAnn : paramAnns) {
                                    boolean existingType = false;
                                    for (Annotation ann : anns) {
                                        if (ann.annotationType() == paramAnn.annotationType()) {
                                            existingType = true;
                                            break;
                                        }
                                    }
                                    if (!existingType) {
                                        merged.add(adaptAnnotation(paramAnn));
                                    }
                                }
                                anns = merged.toArray(new Annotation[0]);
                            }
                        }
                    }
                }
                this.combinedAnnotations = anns;
            }
            return anns;
        }
    }

    // 返回值的真正类型~~~
    private class ReturnValueMethodParameter extends HandlerMethodParameter {
        @Nullable
        private final Object returnValue;
        public ReturnValueMethodParameter(@Nullable Object returnValue) {
            super(-1); // 此处传的-1哦~~~~ 比0小是很有意义的
            this.returnValue = returnValue;
        }
        ...
        // 返回值类型使用returnValue就行了~~~
        @Override
        public Class<?> getParameterType() {
            return (this.returnValue != null ? this.returnValue.getClass() : super.getParameterType());
        }
    }
}

可以看到HandlerMethod它持有的属性是非常多的,提供的能力也是很强的。
但是不知道小伙伴有没有发现,虽然它持有了目标的Method,但是它并没有提供invoke执行它的能力,如果你要执行它还得自己把Method拿去自己执行。

所以总的来说它的职责还是很单一的:HandlerMethod它只负责准备数据,封装数据,而而不提供具体使用的方式方法~

看看它的继承树:

它主要有两个子类:InvocableHandlerMethodServletInvocableHandlerMethod,从命名就知道他俩都是有invoke调用能力的~

InvocableHandlerMethod

它是对HandlerMethod的扩展,增加了调用能力。这个能力在Spring MVC可是非常非常重要的,它能够在调用的时候,把方法入参的参数都封装进来(从HTTP request里,当然借助的必然是HandlerMethodArgumentResolver

// @since 3.1
public class InvocableHandlerMethod extends HandlerMethod {
    private static final Object[] EMPTY_ARGS = new Object[0];

    // 它额外提供的几个属性,可以看到和数据绑定、数据校验就扯上关系了~~~

    // 用于产生数据绑定器、校验器
    @Nullable
    private WebDataBinderFactory dataBinderFactory;
    // HandlerMethodArgumentResolver用于入参的解析
    private HandlerMethodArgumentResolverComposite resolvers = new HandlerMethodArgumentResolverComposite();
    // 用于获取形参名
    private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();

    ... // 省略构造函数 全部使用super的
    // 它自己的三大属性都使用set方法设置进来~~~并且没有提供get方法
    // 也就是说:它自己内部使用就行了~~~

    // 在给定请求的上下文中解析方法的参数值后调用该方法。 也就是说:方法入参里就能够自动使用请求域(包括path里的,requestParam里的、以及常规对象如HttpSession这种)
    // 解释下providedArgs作用:调用者可以传进来,然后直接doInvoke()的时候原封不动的使用它
    //(弥补了请求域没有所有对象的不足,毕竟有些对象是用户自定义的嘛~)
    @Nullable
    public Object invokeForRequest(NativeWebRequest request, @Nullable ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        // 虽然它是最重要的方法,但是此处不讲,因为核心原来还是`HandlerMethodArgumentResolver`
        // 它只是把解析好的放到对应位置里去~~~
        // 说明:这里传入了ParameterNameDiscoverer,它是能够获取到形参名的。
        // 这就是为何注解里我们不写value值,通过形参名字来匹配也是ok的核心原因~
        Object[] args = getMethodArgumentValues(request, mavContainer, providedArgs);
        if (logger.isTraceEnabled()) { // trace信息,否则日志也特多了~
            logger.trace("Arguments: " + Arrays.toString(args));
        }
        return doInvoke(args);
    }

    // doInvoke()方法就不说了,就是个普通的方法调用
    // ReflectionUtils.makeAccessible(getBridgedMethod());
    // return getBridgedMethod().invoke(getBean(), args);
}

对于最后的invoke(),说明一点:这里可是执行的目标方法getBean()哦~~~

这个子类主要提供的能力就是提供了invoke调用目标Bean目标方法的能力,在这个调用过程中可大有文章可为,当然最为核心的逻辑可是各种各样的HandlerMethodArgumentResolver来完成的,详见下文有分晓。
InvocableHandlerMethod这个子类虽然它提供了调用了能力,但是它却依旧还没有和Servlet的API绑定起来,毕竟使用的是Spring自己通用的的NativeWebRequest,so很容易想到它还有一个子类就是干这事的~

ServletInvocableHandlerMethod

它是对InvocableHandlerMethod的扩展,它增加了返回值和响应状态码的处理,另外在ServletInvocableHandlerMethod有个内部类ConcurrentResultHandlerMethod继承于它,支持异常调用结果处理,Servlet容器下Controller在查找适配器时发起调用的最终就是ServletInvocableHandlerMethod

public class ServletInvocableHandlerMethod extends InvocableHandlerMethod {
    private static final Method CALLABLE_METHOD = ClassUtils.getMethod(Callable.class, "call");

    // 处理方法返回值
    @Nullable
    private HandlerMethodReturnValueHandlerComposite returnValueHandlers;

    // 构造函数略

    // 设置处理返回值的HandlerMethodReturnValueHandler
    public void setHandlerMethodReturnValueHandlers(HandlerMethodReturnValueHandlerComposite returnValueHandlers) {
        this.returnValueHandlers = returnValueHandlers;
    }

    // 它不是复写,但是是对invokeForRequest方法的进一步增强  因为调用目标方法还是靠invokeForRequest
    // 本处是把方法的返回值拿来进一步处理~~~比如状态码之类的
    public void invokeAndHandle(ServletWebRequest webRequest, ModelAndViewContainer mavContainer, Object... providedArgs) throws Exception {
        Object returnValue = invokeForRequest(webRequest, mavContainer, providedArgs);
        // 设置HttpServletResponse返回状态码 这里面还是有点意思的  因为@ResponseStatus#code()在父类已经解析了  但是子类才用
        setResponseStatus(webRequest);

        // 重点是这一句话:mavContainer.setRequestHandled(true); 表示该请求已经被处理过了
        if (returnValue == null) {

            // Request的NotModified为true 有@ResponseStatus注解标注 RequestHandled=true 三个条件有一个成立,则设置请求处理完成并返回
            if (isRequestNotModified(webRequest) || getResponseStatus() != null || mavContainer.isRequestHandled()) {
                mavContainer.setRequestHandled(true);
                return;
            }
        // 返回值不为null,@ResponseStatus存在reason 同样设置请求处理完成并返回
        } else if (StringUtils.hasText(getResponseStatusReason())) {
            mavContainer.setRequestHandled(true);
            return;
        }

        // 前边都不成立,则设置RequestHandled=false即请求未完成
        // 继续交给HandlerMethodReturnValueHandlerComposite处理
        // 可见@ResponseStatus的优先级还是蛮高的~~~~~
        mavContainer.setRequestHandled(false);
        Assert.state(this.returnValueHandlers != null, "No return value handlers");
        try {

            // 关于对方法返回值的处理,参见:https://blog.csdn.net/f641385712/article/details/90370542
            this.returnValueHandlers.handleReturnValue(returnValue, getReturnValueType(returnValue), mavContainer, webRequest);
        } catch (Exception ex) {
            if (logger.isTraceEnabled()) {
                logger.trace(formatErrorForReturnValue(returnValue), ex);
            }
            throw ex;
        }
    }

    // 设置返回的状态码到HttpServletResponse 里面去
    private void setResponseStatus(ServletWebRequest webRequest) throws IOException {
        HttpStatus status = getResponseStatus();
        if (status == null) { // 如果调用者没有标注ResponseStatus.code()此注解  此处就忽略它
            return;
        }

        HttpServletResponse response = webRequest.getResponse();
        if (response != null) {
            String reason = getResponseStatusReason();

            // 此处务必注意:若有reason,那就是sendError  哪怕你是200哦~
            if (StringUtils.hasText(reason)) {
                response.sendError(status.value(), reason);
            } else {
                response.setStatus(status.value());
            }
        }

        // 设置到request的属性,把响应码给过去。为了在redirect中使用
        // To be picked up by RedirectView
        webRequest.getRequest().setAttribute(View.RESPONSE_STATUS_ATTRIBUTE, status);
    }

    private boolean isRequestNotModified(ServletWebRequest webRequest) {
        return webRequest.isNotModified();
    }

    // 这个方法RequestMappingHandlerAdapter里有调用
    ServletInvocableHandlerMethod wrapConcurrentResult(Object result) {
        return new ConcurrentResultHandlerMethod(result, new ConcurrentResultMethodParameter(result));
    }

    // 内部类们
    private class ConcurrentResultMethodParameter extends HandlerMethodParameter {
        @Nullable
        private final Object returnValue;
        private final ResolvableType returnType;
        public ConcurrentResultMethodParameter(Object returnValue) {
            super(-1);
            this.returnValue = returnValue;
            // 主要是这个解析 兼容到了泛型类型 比如你的返回值是List<Person> 它也能把你的类型拿出来
            this.returnType = (returnValue instanceof ReactiveTypeHandler.CollectedValuesList ?
                    ((ReactiveTypeHandler.CollectedValuesList) returnValue).getReturnType() :
                    ResolvableType.forType(super.getGenericParameterType()).getGeneric());
        }

        // 若返回的是List  这里就是List的类型哦  下面才是返回泛型类型
        @Override
        public Class<?> getParameterType() {
            if (this.returnValue != null) {
                return this.returnValue.getClass();
            }
            if (!ResolvableType.NONE.equals(this.returnType)) {
                return this.returnType.toClass();
            }
            return super.getParameterType();
        }

        // 返回泛型类型
        @Override
        public Type getGenericParameterType() {
            return this.returnType.getType();
        }

        // 即使实际返回类型为ResponseEntity<Flux<T>>,也要确保对@ResponseBody-style处理从reactive 类型中收集值
        // 是对reactive 的一种兼容
        @Override
        public <T extends Annotation> boolean hasMethodAnnotation(Class<T> annotationType) {
            // Ensure @ResponseBody-style handling for values collected from a reactive type
            // even if actual return type is ResponseEntity<Flux<T>>
            return (super.hasMethodAnnotation(annotationType) ||
                    (annotationType == ResponseBody.class && this.returnValue instanceof ReactiveTypeHandler.CollectedValuesList));
        }
    }

    // 这个非常有意思   内部类继承了自己(外部类) 进行增强
    private class ConcurrentResultHandlerMethod extends ServletInvocableHandlerMethod {
        // 返回值
        private final MethodParameter returnType;

        // 此构造最终传入的handler是个Callable
        // result方法返回值 它支持支持异常调用结果处理
        public ConcurrentResultHandlerMethod(final Object result, ConcurrentResultMethodParameter returnType) {
            super((Callable<Object>) () -> {
                if (result instanceof Exception) {
                    throw (Exception) result;
                } else if (result instanceof Throwable) {
                    throw new NestedServletException("Async processing failed", (Throwable) result);
                }
                return result;
            }, CALLABLE_METHOD);

            // 给外部类把值设置上  因为wrapConcurrentResult一般都先调用,是对本类的一个增强
            if (ServletInvocableHandlerMethod.this.returnValueHandlers != null) {
                setHandlerMethodReturnValueHandlers(ServletInvocableHandlerMethod.this.returnValueHandlers);
            }
            this.returnType = returnType;
        }
        ...
    }
}

HandlerMethod用于封装Handler和处理请求的MethodInvocableHandlerMethod增加了方法参数解析和调用方法的能力;ServletInvocableHandlerMethod在此基础上在增加了如下三个能力:

  1. @ResponseStatus注解的支持
    1.当一个方法注释了@ResponseStatus后,响应码就是注解上的响应码并且,并且如果returnValue=null或者reason不为空(不为null且不为“”),将中断处理直接返回(不再渲染页面)
  2. 对返回值returnValue的处理
    1. 对返回值的处理是使用HandlerMethodReturnValueHandlerComposite完成的
  3. 异步处理结果的处理

    使用示例

    文首说了,HandlerMethod作为一个非公开API,如果你要直接使用起来,还是稍微要费点劲的。
    但本文还是给出一个Demo,给出小伙伴们最为关心也是对你们最有用的一个需求:ModelFactory.getNameForParameter(parameter)这个静态方法是给入参生成默认名称的,当然默认处理方案最底层依赖的是它Conventions.getVariableNameForParameter(parameter),为了验证这块对象、Object、List等等常用数据结构的默认处理,此处我借助HandlerMethod一次性全部打印出这个结论:

@Getter
@Setter
@ToString
public class Person {

    @NotNull
    private String name;
    @NotNull
    @Positive
    private Integer age;

    public Object demoMethod(Person person, Object object,
                             List<Integer> intList, List<Person> personList,
                             Set<Integer> intSet, Set<Person> personSet,
                             Map<String, Object> myMap,
                             String name, Integer age,
                             int number, double money) {
        return "hello parameter";
    }
}

借助HandlerMethod完成此测试用例

    public static void main(String[] args) {
        // 准备一个HandlerMethod
        HandlerMethod handlerMethod = new HandlerMethod(new Person(), getPersonSpecfyMethod());
        // 拿到该方法所有的参数
        MethodParameter[] methodParameters = handlerMethod.getMethodParameters();
        for (MethodParameter parameter : methodParameters) {
            Class<?> parameterType = parameter.getParameterType();
            String nameForParameter = ModelFactory.getNameForParameter(parameter);
            System.out.println("类型" + parameterType.getName() + "--->缺省的modelKey是:" + nameForParameter);
        }
    }

    private static Method getPersonSpecfyMethod() {
        for (Method method : Person.class.getMethods())
            if (method.getName().equals("demoMethod"))
                return method;
        return null;
    }

运行,打印结果如下:

类型com.fsx.bean.Person--->缺省的modelKey是:person
类型java.lang.Object--->缺省的modelKey是:object
类型java.util.List--->缺省的modelKey是:integerList
类型java.util.List--->缺省的modelKey是:personList
类型java.util.Set--->缺省的modelKey是:integerList // 可以看到即使是set 名称也是同List的
类型java.util.Set--->缺省的modelKey是:personList
类型java.util.Map--->缺省的modelKey是:map
类型java.lang.String--->缺省的modelKey是:string
类型java.lang.Integer--->缺省的modelKey是:integer
类型int--->缺省的modelKey是:int
类型double--->缺省的modelKey是:double

这个结果是不同类型对应的缺省的ModelKey,希望小伙伴们能够记下来,这对理解和正确使用@SessionAttribute、@ModelAttribute都是很重要的~

总结

HandlerMethod虽然接触少,但并不影响它的重要性。在理解Spring MVC的处理流程上它很重要,在与使用者关系较大的拦截器HandlerInterceptor定制化处理的时候,学会使用它一样是非常有必要的。

在最后还提示大家一个你可能没有关心到的小细节:

  1. HandlerMethod位于org.springframework.web.method包下,且是3.1后才有的
  2. MethodParameter位于org.springframework.core核心包中。2.0就存在了

相关阅读

【小家Spring】Spring MVC容器的web九大组件之---HandlerAdapter源码详解---一篇文章带你读懂返回值处理器HandlerMethodReturnValueHandler

知识交流

==The last:如果觉得本文对你有帮助,不妨点个赞呗。当然分享到你的朋友圈让更多小伙伴看到也是被作者本人许可的~==

若对技术内容感兴趣可以加入wx群交流:Java高工、架构师3群
若群二维码失效,请加wx号:fsx641385712(或者扫描下方wx二维码)。并且备注:"java入群" 字样,会手动邀请入群

若文章格式混乱或者图片裂开,请点击`:原文链接-原文链接-原文链接

原文地址:https://www.cnblogs.com/fangshixiang/p/11298197.html

时间: 2024-07-31 18:19:27

从原理层面掌握HandlerMethod、InvocableHandlerMethod、ServletInvocableHandlerMethod的使用【一起学Spring MVC】的相关文章

RestTemplate的使用和原理你都烂熟于胸了吗?【享学Spring MVC】

每篇一句 人圆月圆心圆,人和家和国和---中秋节快乐 前言 在阅读本篇之前,建议先阅读开山篇效果更佳.RestTemplate是Spring提供的用于访问Rest服务的客户端工具,它提供了多种便捷访问远程Http服务的方法,能够大大提高客户端的编写效率. 弱弱呼吁一句:对于那些在Spring环境下还在使用HttpClient(或其它Client)的同学,今儿看完本文后,建议切换到RestTemplate (有特殊需求的当然除外喽~). RestTemplate简化了与http服务的通信,程序代码

【Spring】Spring MVC原理及配置详解

1.Spring MVC概述: Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得控制器的开发和测试更加简单.这些控制器一般不直接处理请求,而是将其委托给Spring上下文中的其他bean,通过Spring的依赖注入功能,这些bean被注入到控制器中. Spring MVC主要由DispatcherServlet.处理器映射.处理器(控制器).视图解析器.视图组成.他的两个核心是两个核心: 处理器映射:选择使用

spring Mvc 执行原理 及 xml注解配置说明 (六)

Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 dispatcherServlet ,每个 DispatcherServlet 可以对应多个的 HandlerMapping ,每个 HandlerMapping 可以有自己的 Interceptor (拦截器). 1. 请求首先 由 前端 DispatcherServlet 捕获: 2. Disp

spring mvc控制框架的流程及原理1: 总概及源码分析

主要介绍spring mvc控制框架的流程及原理 Spring Web MVC处理请求的流程 具体执行步骤如下: 首先用户发送请求————>前端控制器,前端控制器根据请求信息(如URL)来决定选择哪一个页面控制器进行处理并把请求委托给它,即以前的控制器的控制逻辑部分:图2-1中的1.2步骤: 页面控制器接收到请求后,进行功能处理,首先需要收集和绑定请求参数到一个对象,这个对象在Spring Web MVC中叫命令对象,并进行验证,然后将命令对象委托给业务对象进行处理:处理完毕后返回一个Model

spring mvc 工作原理

SpringMVC框架介绍 1) Spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架.通过策略接口,Spring 框架是高度可配置的,而且包含多种视图技术,例如 JavaServer Pages(JSP)技术.Velocity.Til

【转】spring Mvc 执行原理 及 xml注解配置说明

Spring MVC 执行原理 在 Spring Mvc 访问过程里,每个请求都首先经过 许多的过滤器,经 DispatcherServlet 处理; 一个Spring MVC工程里,可以配置多个的 dispatcherServlet ,每个 DispatcherServlet 可以对应多个的 HandlerMapping ,每个 HandlerMapping 可以有自己的 Interceptor (拦截器). 1. 请求首先 由 前端 DispatcherServlet 捕获: 2. Disp

spring mvc的工作原理

该文转载自:http://blog.csdn.net/u012191627/article/details/41943393 SpringMVC框架介绍 1) spring MVC属于SpringFrameWork的后续产品,已经融合在Spring Web Flow里面. Spring 框架提供了构建 Web 应用程序的全功能 MVC 模块.使用 Spring 可插入的 MVC 架构,可以选择是使用内置的 Spring Web 框架还是 Struts 这样的 Web 框架.通过策略接口,Spri

Spring MVC原理及实例基础扫盲篇

最近 项目中刚接触了SpringMVC,就把这几天看的跟实践的东西写出来吧. 一.首先,先来了解一下SpringMVC到底是个什么样的框架? Spring Web MVC是一种基于Java的实现了Web MVC设计模式的请求驱动类型的轻量级Web框架,即使用了MVC架构模式的思想,将web层进行职责解耦,基于请求驱动指的就是使用请求-响应模型,框架的目的就是帮助我们简化开发. 二.SpringMVC的工作原理: 1. 客户端请求提交到DispatcherServlet 2. 由Dispatche

Spring MVC:原理与使用

本人上一篇博文提到了Spring的注入功能,这样在存在对象依赖(具体意思可见上一篇博文)的时候就不用自己生成一个对象了,特别是对于较多的无状态对象的时候,这个特别方便,加上Spring提供的用xml配置文件和代码注解两种方式,使得使用更加灵活.然而spring的功能远不止如此,Spring的强大功能其实还在于做Java后台框架,即Spring MVC,把后台的逻辑和和视图解耦分离,方便使用与扩展,特别是在大型项目中很有用. PS:卖个自己的广告,上一篇博文<Spring注入:配置与注解> (如