首页 > 其他分享 >7-DispatcherServlet的初始化时机和机制

7-DispatcherServlet的初始化时机和机制

时间:2024-07-09 19:00:44浏览次数:12  
标签:初始化 web springframework org 时机 DispatcherServlet servlet method

DispatcherServlet初始化机制

1. DispatcherServlet初始化时机

首先编写一段代码,手动使用内嵌tomcat服务器:

WebConfig.java

@Configuration
@ComponentScan
public class WebConfig {
    // 1. 内嵌web容器工厂
    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory(){
        return new TomcatServletWebServerFactory();
    }

    // 2. 创建DispatcherServlet
    @Bean
    public DispatcherServlet dispatcherServlet(){
        return new DispatcherServlet();
    }

    // 3. 注册DispatcherServlet到tomcat容器中
    // 凡是请求路径为"/"的请求都会交给dispatcherServlet来处理
    @Bean
    public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet){
        return new DispatcherServletRegistrationBean(dispatcherServlet,"/");
    }
}

编写一段测试类:

public class A20 {
    private static final Logger logger  = LoggerFactory.getLogger(A20.class);
    public static void main(String[] args) {
        // 准备一个支持内嵌tomcat容器的一个Spring容器的实现, 并加载配置类
        AnnotationConfigServletWebServerApplicationContext context =
                new AnnotationConfigServletWebServerApplicationContext(WebConfig.class);
    }
}

运行后的控制台如图所示:

20:58:34.577 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer -- Tomcat initialized with port 8080 (http)
七月 05, 2024 8:58:34 下午 org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8080"]
七月 05, 2024 8:58:34 下午 org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Tomcat]
七月 05, 2024 8:58:34 下午 org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet engine: [Apache Tomcat/10.1.25]
七月 05, 2024 8:58:34 下午 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring embedded WebApplicationContext
20:58:34.837 [main] INFO org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext -- Root WebApplicationContext: initialization completed in 1112 ms
七月 05, 2024 8:58:34 下午 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8080"]
20:58:34.969 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer -- Tomcat started on port 8080 (http) with context path '/'

我们从上面的日志发现,tomact和IOC容器已经初始化成功了。但是DispatcherServlet一开始并没有初始化。

DispatcherServlet对象是由IOC容器创建的,但是该对象是由TomcatServletWebServerFactory在首次使用到Dispatcher对象时初始化的。

我们首先访问一下"/"下面的路由看一下控制台日志:

七月 05, 2024 9:06:14 下午 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring DispatcherServlet 'dispatcherServletRegistrationBean'
21:06:14.583 [http-nio-8080-exec-1] INFO org.springframework.web.servlet.DispatcherServlet -- Initializing Servlet 'dispatcherServletRegistrationBean'
21:06:14.909 [http-nio-8080-exec-1] INFO org.springframework.web.servlet.DispatcherServlet -- Completed initialization in 326 ms
21:06:14.923 [http-nio-8080-exec-1] WARN org.springframework.web.servlet.PageNotFound -- No mapping for GET /hello
21:06:14.932 [http-nio-8080-exec-1] WARN org.springframework.web.servlet.PageNotFound -- No endpoint GET /hello.

我们可以从日志中看到,DispatcherServlet对象会在第一个请求以"/"为路由时进行初始化,紧接着会进行不同组件的初始化步骤。

那我们不想让DispatcherServlet对象在第一次请求发送过来的时候进行初始化,而是在ioc容器创建好DispatcherServlet对象后立刻进行初始化,我们可以在注册DispatcherServlet对象时设置DispatcherServlet对象启动优先级为最高。

@Bean
public DispatcherServletRegistrationBean dispatcherServletRegistrationBean(DispatcherServlet dispatcherServlet){
    DispatcherServletRegistrationBean bean = new DispatcherServletRegistrationBean(dispatcherServlet, "/");
    bean.setLoadOnStartup(1);
    return bean;
}

重新启动观察控制台日志:

21:14:54.420 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer -- Tomcat initialized with port 8080 (http)
七月 05, 2024 9:14:54 下午 org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-nio-8080"]
七月 05, 2024 9:14:54 下午 org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Tomcat]
七月 05, 2024 9:14:54 下午 org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet engine: [Apache Tomcat/10.1.25]
七月 05, 2024 9:14:54 下午 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring embedded WebApplicationContext
21:14:54.675 [main] INFO org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext -- Root WebApplicationContext: initialization completed in 1097 ms
七月 05, 2024 9:14:54 下午 org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8080"]
七月 05, 2024 9:14:54 下午 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring DispatcherServlet 'dispatcherServletRegistrationBean'
21:14:54.816 [main] INFO org.springframework.web.servlet.DispatcherServlet -- Initializing Servlet 'dispatcherServletRegistrationBean'	// DispatcherServlet 对象初始化成功!!!
21:14:55.234 [main] INFO org.springframework.web.servlet.DispatcherServlet -- Completed initialization in 418 ms
21:14:55.235 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer -- Tomcat started on port 8080 (http) with context path '/'

2 DispatherServlet 初始化做了什么

Dispatcher对象初始化的时机是在调用DispatcherServlet类中的onRefresh()方法,在该方法中又有如下方法:

protected void initStrategies(ApplicationContext context) {
    // 初始化文件上传方面的解析器
    this.initMultipartResolver(context);
    // 初始化本地化方面的解析器
    this.initLocaleResolver(context);
    this.initThemeResolver(context);
    // 初始化处理器(路径)映射方面的解析器,如RequestMapping, GetMapping等
    this.initHandlerMappings(context); ---> 重要
    // 初始化处理器(路径)适配 -- 用于适配不同形式的控制器方法,然后调用控制器
    this.initHandlerAdapters(context); ---> 重要
    // 初始化处理器异常解析器 -- 出现异常时解析异常
    this.initHandlerExceptionResolvers(context); ---> 重要
    this.initRequestToViewNameTranslator(context);
    // 初始化视图方面的解析
    this.initViewResolvers(context);
    this.initFlashMapManager(context);
}

3. RequestMappingHandlerMapping 基本用途

RequestMappingHandlerMapping又叫处理器映射器,是用来建立请求路径与处理器之间的映射关系

处理器映射器会在DispatcherServlet对象初始化时会在当前ioc容器中找到控制器类@Controller注解标注的类,找到控制器以后会进一步查看控制器中有哪些方法,如果方法上加上了类似于@Getpamming, @PostMapping, @RequetsMapping等注解,处理器映射器就会筛选出来,然后记录出它们的路径以及对应的控制器方法,并存储在RequestMappingHandlerMapping中。

首先在配置文件中手动创建一个RequestMappingHandlerMapping对象:

@Bean
public RequestMappingHandlerMapping requestMappingHandlerMapping(){
    return new RequestMappingHandlerMapping();
}

接着从ioc容器中获取 RequestMappingHandlerMapping 对象用于解析@RequestMapping以及派生注解,生成路径与方法之间的映射关系。并获取映射结果:其中key代表的是路径信息, value代表的是控制器方法信息

// 解析 @RequestMapping注解及其派生注解,生成路径与控制器方法之间的映射关系(在初始化时生成)
RequestMappingHandlerMapping handlerMapping =
            context.getBean(RequestMappingHandlerMapping.class);
Map<RequestMappingInfo, HandlerMethod> handlerMethods = handlerMapping.getHandlerMethods();
    handlerMethods.forEach((k,v)->{
        System.out.println(k +":"+v);
    });

最后写一个控制器并写几个请求方法,启动主程序查看上面Map打印的结果:

@Controller
public class Controller1 {
    private static final Logger logger = LoggerFactory.getLogger(Controller1.class);

    @GetMapping("/test1")
    public ModelAndView test1(){
        logger.debug("test1()");
        return null;
    }

    @GetMapping("/test2")
    public ModelAndView test2(@RequestParam("name")String name){
        logger.debug("test1({})",name);
        return null;
    }
}

运行结果如下:

INFO: Starting ProtocolHandler ["http-nio-8080"]
七月 06, 2024 12:08:23 上午 org.apache.catalina.core.ApplicationContext log
INFO: Initializing Spring DispatcherServlet 'dispatcherServletRegistrationBean'
00:08:23.882 [main] INFO org.springframework.web.servlet.DispatcherServlet -- Initializing Servlet 'dispatcherServletRegistrationBean'
00:08:24.692 [main] INFO org.springframework.web.servlet.DispatcherServlet -- Completed initialization in 809 ms
00:08:24.695 [main] INFO org.springframework.boot.web.embedded.tomcat.TomcatWebServer -- Tomcat started on port 8080 (http) with context path '/'
{GET [/test1]}:com.cherry.springanalyse.a20.Controller1#test1()
{GET [/test2]}:com.cherry.springanalyse.a20.Controller1#test2(String)

我们发现,处理器映射器会在在请求来之前就已经初始化好了。

但是当请求来的时候,处理器映射器又是怎么根据请求路由选择对应的方法以及获取控制器方法呢?

这是因为处理器映射器有一个getHandler()方法可以通过request请求的路由信息获取到对应的方法信息:

HandlerExecutionChain chanin = handlerMapping.getHandler(new MockHttpServletRequest("GET", "/test1"));
System.out.println(chanin);

getHandler()方法会返回一个处理器执行链对象,这个处理器链对象不光包括对应的方法信息,好多了一些拦截器,我们可以查看一下该拦截器对象:

HandlerExecutionChain with [com.cherry.springanalyse.a20.Controller1#test1()] and 0 interceptors

同时我们查看 HandlerExecutionChain的源码可以发现,该类有两个属性成员,一个是 url 上对应的处理器,还有一个是用于存储多个拦截器的List集合。

public class HandlerExecutionChain {

private static final Log logger = LogFactory.getLog(HandlerExecutionChain.class);

private final Object handler;

private final List<HandlerInterceptor> interceptorList = new ArrayList<>();

private int interceptorIndex = -1;

    ......
}

4. RequestMappingHandlerAdapter基本用途

RequestMappingHandlerAdapter又叫处理器适配器,作用就是根据路由去调用对应的控制器方法。

首先在配置文件中创建一个RequestMappingHandlerAdapter对象:

@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdapter(){
    return new RequestMappingHandlerAdapter();
}

在ioc容器中获取RequestMappingHandlerAdapter对象 。但是RequestMappingHandlerAdapter中的invokeHandlerMethod()方法是受保护的,不能直接调用,因此我们可以创建RequestMappingHandlerAdapter的子类,并将该方法访问修饰设置为public

public class MyRequestMappingHandlerAdapter extends RequestMappingHandlerAdapter {
    @Override
    public ModelAndView invokeHandlerMethod(HttpServletRequest request, HttpServletResponse response, HandlerMethod handlerMethod) throws Exception {
        return super.invokeHandlerMethod(request, response, handlerMethod);
    }
}

同样也需要在配置类中进行修改

@Bean
public MyRequestMappingHandlerAdapter myRequestMappingHandlerAdapter(){
    return new MyRequestMappingHandlerAdapter();
}
// 调用路由上对应的控制器方法
System.out.println(myRequestMappingHandlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chanin.getHandler()));MockHttpServletRequest request = new MockHttpServletRequest("GET","/test2");
    request.setParameter("name","syh");
    MockHttpServletResponse response = new MockHttpServletResponse() ;
    MyRequestMappingHandlerAdapter myRequestMappingHandlerAdapter =
            context.getBean(MyRequestMappingHandlerAdapter.class);
    HandlerExecutionChain chanin = handlerMapping.getHandler(request);
    System.out.println(chanin);


    System.out.println(">>>>>>>>>>>>>>>>>");
    // 调用路由上对应的控制器方法
    System.out.println(myRequestMappingHandlerAdapter.invokeHandlerMethod(request, response, (HandlerMethod) chanin.getHandler()));

运行结果如下:

com.cherry.web.controller.Controller	- test2(syh)

我们可以看到适配器找到了对应的控制器方法。

HandlerAdapter作用就是调用控制器方法,对于一些请求可能会比较复杂,例如会带一些解析器,那么HandlerAdapter是如何获取路由上的参数呢?这就涉及到了参数解析器。我们可以试着打印这些解析器:

List<HandlerMethodArgumentResolver> handlerMethodArgumentResolverList = handlerAdapter.getArgumentResolvers();
    handlerMethodArgumentResolverList.forEach(e->{
        System.out.println(e);
    });
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@245a060f
org.springframework.web.method.annotation.RequestParamMapMethodArgumentResolver@6edaa77a
org.springframework.web.servlet.mvc.method.annotation.PathVariableMethodArgumentResolver@1e63d216
org.springframework.web.servlet.mvc.method.annotation.PathVariableMapMethodArgumentResolver@62ddd21b
org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMethodArgumentResolver@16c3ca31
org.springframework.web.servlet.mvc.method.annotation.MatrixVariableMapMethodArgumentResolver@2d195ee4
org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@2d6aca33
org.springframework.web.servlet.mvc.method.annotation.RequestResponseBodyMethodProcessor@21ab988f
org.springframework.web.servlet.mvc.method.annotation.RequestPartMethodArgumentResolver@29314cc9
org.springframework.web.method.annotation.RequestHeaderMethodArgumentResolver@4e38d975
org.springframework.web.method.annotation.RequestHeaderMapMethodArgumentResolver@35f8a9d3
org.springframework.web.servlet.mvc.method.annotation.ServletCookieValueMethodArgumentResolver@48ea2003
org.springframework.web.method.annotation.ExpressionValueMethodArgumentResolver@6b1e7ad3
org.springframework.web.servlet.mvc.method.annotation.SessionAttributeMethodArgumentResolver@63e5e5b4
org.springframework.web.servlet.mvc.method.annotation.RequestAttributeMethodArgumentResolver@13a37e2a
org.springframework.web.servlet.mvc.method.annotation.ServletRequestMethodArgumentResolver@a50ae65
org.springframework.web.servlet.mvc.method.annotation.ServletResponseMethodArgumentResolver@1280851e
org.springframework.web.servlet.mvc.method.annotation.HttpEntityMethodProcessor@5e840abf
org.springframework.web.servlet.mvc.method.annotation.RedirectAttributesMethodArgumentResolver@56de6d6b
org.springframework.web.method.annotation.ModelMethodProcessor@5972d253
org.springframework.web.method.annotation.MapMethodProcessor@4fcc0416
org.springframework.web.method.annotation.ErrorsMethodArgumentResolver@31e32ea2
org.springframework.web.method.annotation.SessionStatusMethodArgumentResolver@1473b8c0
org.springframework.web.servlet.mvc.method.annotation.UriComponentsBuilderMethodArgumentResolver@5b5c0057
org.springframework.web.servlet.mvc.method.annotation.PrincipalMethodArgumentResolver@749f539e
org.springframework.web.method.annotation.RequestParamMethodArgumentResolver@5ca1f591
org.springframework.web.servlet.mvc.method.annotation.ServletModelAttributeMethodProcessor@551de37d

我们发现Spring的处理器适配器提供了很多参数解析器,例如解析Request Param参数的参数解析器,解析restful风格路由的参数解析器等等;除了参数解析器,还有一些返回值解析器,专门用于处理对返回对象的解析等

5. 自定义参数解析器

我们如何自己编写一个自定义参数解析器,例如@Token注解:

// 自定义参数注解,用户获取请求头中的 token信息, 用下面注解来标注哪个参数来获取它
@Target(ElementType.PARAMETER)
@Retention(RetentionPolicy.RUNTIME)
public @interface Token {
}

接下来我们为该注解编写一个参数解析器 TokenArgumentResolver

package com.cherry.springanalyse.a20;

import org.springframework.core.MethodParameter;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.support.WebDataBinderFactory;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.ModelAndViewContainer;

public class TokenArgumentResolver implements HandlerMethodArgumentResolver {
    /**
     * 该解析器是否支持某个参数
     * 如果该方法参数上有@Token注解,则会返回true, 否则返回false(不需要执行后面的解析)
     */
    @Override
    public boolean supportsParameter(MethodParameter parameter) {
        // 根据方法参数获取参数上的注解
        Token token = parameter.getParameterAnnotation(Token.class);
        // 如果返回的参数上有@Token注解则返回true,否则返回false
        return token != null;

    }

    // 解析参数
    @Override
    public Object resolveArgument(MethodParameter parameter,
                                  ModelAndViewContainer mavContainer,
                                  NativeWebRequest webRequest,
                                  WebDataBinderFactory binderFactory) throws Exception {
        return webRequest.getHeader("token");
    }
}

紧接着在处理器适配器中加入对该注解解析器的支持:

// 加入自定义参数解析器
@Bean
public MyRequestMappingHandlerAdapter myRequestMappingHandlerAdapter(){
    TokenArgumentResolver tokenArgumentResolver = new TokenArgumentResolver();
    MyRequestMappingHandlerAdapter adapter = new MyRequestMappingHandlerAdapter();
    adapter.setArgumentResolvers(List.of(tokenArgumentResolver));
    return new MyRequestMappingHandlerAdapter();
}

编写一个测试controller

@PutMapping("/test3")
public ModelAndView test3(@Token String token){
    logger.debug("test3({})",token);
    return null;
}
MockHttpServletRequest request = new MockHttpServletRequest("PUT","/test3");
request.setParameter("name","syh");
// 设置请求头
request.addHeader("token","1234567890");
MockHttpServletResponse response = new MockHttpServletResponse() ;
HandlerExecutionChain chain = handlerMapping.getHandler(request);
System.out.println(chain);

MyRequestMappingHandlerAdapter handlerAdapter =
        context.getBean(MyRequestMappingHandlerAdapter.class);

handlerAdapter.invokeHandlerMethod(request,response, (HandlerMethod) chain.getHandler());

测试结果如下:

[DEBUG] 20:43:32:523 [main] com/cherry/springanalyse/a20/Controller1	--test3(123456)

6. 自定义返回值处理器

返回值处理器可以根据控制器返回的类型不同而做出不同的选择,例如ModelAndViewString等等。同时还会根据控制器上是不是加了某些注解,例如@ResponseBody而做出一些不同的处理。

这里我们自定义一个注解@Yml用来感受一下,将返回值对象转换为JSON:

首先编写一个返回值处理器YmlReturenHandler

package com.cherry.springanalyse.a20;

import jakarta.servlet.http.HttpServletResponse;
import org.springframework.core.MethodParameter;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.method.support.ModelAndViewContainer;
import org.yaml.snakeyaml.Yaml;

public class YmlReturnValueHandler implements HandlerMethodReturnValueHandler {
    // 该方法主要用于判断方法上有没有包含@Yml注解,如果有,则放行
    // 如果没有,则不放行
    @Override
    public boolean supportsReturnType(MethodParameter returnType) {
        // 判断干方法上是否有@Yml注解
        Yml ymlAnnotation = returnType.getMethodAnnotation(Yml.class);
        return ymlAnnotation==null;
    }

    /**
     *
     * @param returnValue: 返回值对象(值)
     * @param returnType
     * @param mavContainer
     * @param webRequest
     * @throws Exception
     */
    @Override
    public void handleReturnValue(Object returnValue, MethodParameter returnType, ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
        // 将返回结果转换为yaml
        String str = new Yaml().dump(returnValue);
        // 将转换后的yaml字符串交给response
        HttpServletResponse response = webRequest.getNativeResponse(HttpServletResponse.class);
        // 设置内容类型
        response.setContentType("text/html;charset=utf-8");
        response.getWriter().print(str);
        // 由于这里已经直接将结果输出给response了,因此不再需要spring mvc来处理了,
        // 可以让spring mvc知道此次请求已经处理完毕了
        // 设置请求已经处理完毕
        mavContainer.setRequestHandled(true);
    }
}

同样的,在配置类里面将自己定义的返回处理器加入到处理器适配器中 。

@Bean
public MyRequestMappingHandlerAdapter myRequestMappingHandlerAdapter(){
    TokenArgumentResolver tokenArgumentResolver = new TokenArgumentResolver();
    YmlReturnValueHandler ymlReturnValueHandler = new YmlReturnValueHandler();
    MyRequestMappingHandlerAdapter adapter = new MyRequestMappingHandlerAdapter();
    adapter.setArgumentResolvers(List.of(tokenArgumentResolver));
    adapter.setReturnValueHandlers(List.of(ymlReturnValueHandler));
    return new MyRequestMappingHandlerAdapter();
}

编写一个测试类:

@GetMapping("/test4")
@Yml
public User test4(){
    return new User("lily",18);
}

class User{
    private String name;
    private int age;
    // 此处省略getter,setter,构造方法
}

MockHttpServletRequest request = new MockHttpServletRequest("GET","/test4");
MockHttpServletResponse response = new MockHttpServletResponse();
HandlerExecutionChain chain = handlerMapping.getHandler(request);
System.out.println(chain);
System.out.println(">>>>>>>>>>>>>>>>>>>>>>>>");
MyRequestMappingHandlerAdapter adapter = context.getBean(MyRequestMappingHandlerAdapter.class);
adapter.invokeHandlerMethod(request,response, (HandlerMethod) chain.getHandler());
// 检查响应
byte[] byteArray = response.getContentAsByteArray();
System.out.println(new String(byteArray, StandardCharsets.UTF_8));

测试结果如下:

{name:lily,age:18}

标签:初始化,web,springframework,org,时机,DispatcherServlet,servlet,method
From: https://www.cnblogs.com/lilyflower/p/18292562

相关文章

  • go 切片初始化
    当在Go语言中使用切片时,切片的初始化是一个常见的操作。在本篇博客中,我们将介绍切片的初始化方式以及一些常见的示例。什么是切片初始化?切片是一个动态数组,可以根据需要自动调整大小。切片的初始化是为切片分配底层数组并设置切片的长度和容量。切片可以通过字面量、make函数......
  • 何时入场才是好时机
    何时入场才是好时机1.当一个股票进入明确的趋势状态后,他将自动的运作,前后一致的贯穿整个趋势过程的路线演变下去2.当这轮运动开始的时候,开头几天你会注意到,伴随着价格的上涨,形成了非常巨大的成交量,随后将发生正常的回撤,在这个向下回落过程中,成交量远远小于前几天上升的时期,这种......
  • 在Winform程序中增加隐藏的按键处理,用于处理一些特殊的界面显示或者系统初始化操作
    以前,我看到一个朋友在对一个系统做初始化的时候,通过一组魔幻般的按键,调出来一个隐藏的系统设置界面,这个界面在常规的菜单或者工具栏是看不到的,因为它是一个后台设置的关键界面,不公开,同时避免常规用户的误操作,它是作为一个超级管理员的入口功能,这个是很不错的思路。其实Winform做这......
  • 代码随想录算法训练营第27天 | 122.买卖股票的最佳时机 II 55. 跳跃游戏 1005.K次取反
    122.买卖股票的最佳时机II给你一个整数数组prices,其中prices[i]表示某支股票第i天的价格。在每一天,你可以决定是否购买和/或出售股票。你在任何时候最多只能持有一股股票。你也可以先购买,然后在同一天出售。返回你能获得的最大利润。解题:思路:最终利润是可......
  • WPF ComboBox数据绑定:初始化动态加载ItemsSource后首次赋值Text不显示问题解决
    原来:<ComboBoxText="{BindingItem}"ItemsSource="{BindingItemLists}"></ComboBox>privatevoidParas_Init(){ItemLists=newObservableCollection<string>();ItemLists.Add("111......
  • 【C#】初始化三菱运动卡
    添加三菱dll引用WPF实现添加WindowsFormsIntegration引用初始化代码//解决因为第三方控件报错,将实例化的对象添加到控件合集中System.Windows.Controls.GridCTSGrid=newSystem.Windows.Controls.Grid();System.Windows.Forms.Integration.WindowsFormsHostho......
  • DispatcherServlet类关于protected HandlerAdapter getHandlerAdapter解释
    /** *ReturntheHandlerAdapterforthishandlerobject. *@paramhandlerthehandlerobjecttofindanadapterfor *@throwsServletExceptionifnoHandlerAdaptercanbefoundforthehandler.Thisisafatalerror. */ protectedHandlerAdapter......
  • mirai Bot初始化配置
    RT其实本来我的bot已经因为自己手贱登陆qqnt直接报废了,但是论坛里有佬提供了新的协议库,那这不赶紧复活bot都对不起这个新的协议库。本文写于2024年7月4日19:20:21,可能随着时间久远而无法实现功能。由于存在下载障碍,所以这里也搞了个存档,本帖中的相关标星*资源无法下载均可以......
  • Arm复位和初始化过程
    复位和初始化 1)   在大多数嵌入式系统中,在执行主任务之前,会执行初始化序列以设置系统。ARM默认初始化序列如下: __main 负责设置内存,__main 执行ZI数据的代码和数据复制、解压缩和零初始化。然后跳转到__rt_entry。__rt_entry 负责设置运行时环境,__rt_entry设......
  • aruba控制器初始化配置
    Auto-provisioningisinprogress.ItrequiresDHCPandActivateserversChooseoneofthefollowingoptionstooverrideordebugauto-provisioning...   'enable-debug'     :Enableauto-provisioningdebuglogs   'disable-debug'......