Servlet生命周期了解

Servlet的生命(周期)是由容器(eg:Tomcat)管理的,换句话说,Servlet程序员不能用代码控制其生命。

加载和实例化:时机取决于web.xml的定义,如果有x则在容器启动时(eg:SSM),反之则在第一次针对这个Servlet的请求发生时(eg:Spring Boot)。

初始化(init):实例化后会立马进行初始化,也就是执行init方法,init方式只会执行一次。

请求处理:初始化后,Servlet就可以接受请求了,基本方式是执行Servlet接口中的service方法。

终止服务:容器会在合适的时候销毁某个Servlet对象,这个策略取决于容器的开发者/商,销毁时destroy方法会被调用。

核心处理请求流程图

入口



前端控制器DispatcherServlet也是一个Servlet,他父类的父类HttpServletBean覆写了Servlet接口的init方法,在容器第一次加载或者第一次请求时会触发(延迟加载),这个方法是Sring Mvc初始化的入口。

启动初始化

容器启动

  1. Spring容器启动过程,会执行Bean的加载、创建和初始化,此处以Controller层为例分析,暂不关注其他类型资源。
  2. RequestMappingHandlerMapping类也是其中一个Bean,负责解析所有标识有@Controller或者@RequestMapping注解的Bean。
  3. RequestMappingHandlerMapping的父类实现了InitializingBean接口,覆写了afterPropertiesSet()方法,该接口是Spring的扩展点之一,在Bean初始化过程中,所i有属性注入完毕之后,会执行一系列回调(回调入口:AbstractAutowireCapableBeanFactory#initializeBean),其中一个回调会验证当前类是否实现了InitializingBean接口,如果实现了会调用afterPropertiesSet()方法,此方法是解析Controller层路径和方法对应关系的入口。
  4. 解析完毕之后会存储在AbstractHandlerMethodMapping#MappingRegistry中,控制器方法HandlerMethod存储了当前路径对应方法的主要信息,它只负责准备数据,封装数据,而而不提供具体使用的方式方法。
  5. 在接收请求时会先根据路径从urlLookup 中获取匹配条件,然后根据匹配条件获取控制器方法HandlerMethod。

  1. class MappingRegistry {
  2. // T:RequestMappingInfo => <请求匹配条件,控制器方法>
  3. private final Map<T, HandlerMethod> mappingLookup = new LinkedHashMap<>();
  4. // T:RequestMappingInfo => <路径,请求匹配条件>
  5. private final MultiValueMap<String, T> urlLookup = new LinkedMultiValueMap<>();
  6. }
  1. public class HandlerMethod {
  2. /** Logger that is available to subclasses */
  3. protected final Log logger = LogFactory.getLog(getClass());
  4. // Web控制器方法所在的Web控制器bean。可以是字符串,代表bean的名称;也可以是bean实例对象本身。
  5. private final Object bean;
  6. // Bean工程,如果bean属性是Sring的beanName就可以用beanName获取到对应的bean作用Handler
  7. @Nullable
  8. private final BeanFactory beanFactory;
  9. // Web控制器方法所在的Web控制器bean的类型,如果该bean被代理,这里记录的是被代理的用户类信息
  10. private final Class<?> beanType;
  11. // Web控制器方法
  12. private final Method method;
  13. private final Method bridgedMethod;
  14. // Web控制器方法的参数信息:所在类所在方法,参数,索引,参数类型
  15. private final MethodParameter[] parameters;
  16. // 注解@ResponseStatus的code属性
  17. @Nullable
  18. private HttpStatus responseStatus;
  19. // 注解@ResponseStatus的reason属性
  20. @Nullable
  21. private String responseStatusReason;
  22. @Nullable
  23. private HandlerMethod resolvedFromHandlerMethod;
  24. ....
  25. }





策略初始化

  1. protected void initStrategies(ApplicationContext context) {
  2. // 初始化文件解析器,用于支持服务器的文件上传
  3. initMultipartResolver(context);
  4. // 初始化国际化解析器,用来提供国际化功能;
  5. initLocaleResolver(context);
  6. // 初始化主题解析器,用来提供皮肤主题功能;
  7. initThemeResolver(context);
  8. // 初始化处理器映射器
  9. initHandlerMappings(context);
  10. // 初始化处理器适配器,为不同的处理器提供上下文运行环境;
  11. initHandlerAdapters(context);
  12. // 处理器异常解析器,用来解析处理器产生的异常;
  13. initHandlerExceptionResolvers(context);
  14. // 初始化视图逻辑名称转换器,根据逻辑视图的名称找到具体的视图。
  15. // 当处理器没有返回逻辑视图名时,将请求的URL自动映射为逻辑视图名;
  16. initRequestToViewNameTranslator(context);
  17. // 初始化视图解析器,当控制器返回后,通过试图解析器会把逻辑视图名进行解析,从而定位实际视图;
  18. initViewResolvers(context);
  19. // 初始化FlashMap管理器接口,负责重定向时,保存参数到临时存储中
  20. initFlashMapManager(context);
  21. }

映射器初始化

  1. private void initHandlerMappings(ApplicationContext context) {
  2. this.handlerMappings = null;
  3. // 默认获取应用上下文所有的处理器映射
  4. if (this.detectAllHandlerMappings) {
  5. // Find all HandlerMappings in the ApplicationContext, including ancestor contexts.
  6. // 获取所有的处理器映射
  7. Map<String, HandlerMapping> matchingBeans =
  8. BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerMapping.class, true, false);
  9. if (!matchingBeans.isEmpty()) {
  10. // 赋值,用于请求时查找
  11. this.handlerMappings = new ArrayList<>(matchingBeans.values());
  12. // We keep HandlerMappings in sorted order.
  13. AnnotationAwareOrderComparator.sort(this.handlerMappings);
  14. }
  15. }
  16. else {
  17. try {
  18. // 根据名称获取指定的bean:handlerMapping
  19. HandlerMapping hm = context.getBean(HANDLER_MAPPING_BEAN_NAME, HandlerMapping.class);
  20. this.handlerMappings = Collections.singletonList(hm);
  21. }
  22. catch (NoSuchBeanDefinitionException ex) {
  23. // Ignore, we'll add a default HandlerMapping later.
  24. }
  25. }
  26. // Ensure we have at least one HandlerMapping, by registering
  27. // a default HandlerMapping if no other mappings are found.
  28. if (this.handlerMappings == null) {
  29. // 获取默认的处理器映射
  30. // 从【DispatcherServlet.properties】文件中读取默认配置
  31. // BeanNameUrlHandlerMapping 和 RequestMappingHandlerMapping
  32. this.handlerMappings = getDefaultStrategies(context, HandlerMapping.class);
  33. if (logger.isDebugEnabled()) {
  34. logger.debug("No HandlerMappings found in servlet '" + getServletName() + "': using default");
  35. }
  36. }
  37. }

适配器初始化(和映射器逻辑一致)

  1. private void initHandlerAdapters(ApplicationContext context) {
  2. this.handlerAdapters = null;
  3. if (this.detectAllHandlerAdapters) {
  4. // Find all HandlerAdapters in the ApplicationContext, including ancestor contexts.
  5. Map<String, HandlerAdapter> matchingBeans =
  6. BeanFactoryUtils.beansOfTypeIncludingAncestors(context, HandlerAdapter.class, true, false);
  7. if (!matchingBeans.isEmpty()) {
  8. this.handlerAdapters = new ArrayList<>(matchingBeans.values());
  9. // We keep HandlerAdapters in sorted order.
  10. AnnotationAwareOrderComparator.sort(this.handlerAdapters);
  11. }
  12. }
  13. else {
  14. try {
  15. HandlerAdapter ha = context.getBean(HANDLER_ADAPTER_BEAN_NAME, HandlerAdapter.class);
  16. this.handlerAdapters = Collections.singletonList(ha);
  17. }
  18. catch (NoSuchBeanDefinitionException ex) {
  19. // Ignore, we'll add a default HandlerAdapter later.
  20. }
  21. }
  22. // Ensure we have at least some HandlerAdapters, by registering
  23. // default HandlerAdapters if no other adapters are found.
  24. if (this.handlerAdapters == null) {
  25. this.handlerAdapters = getDefaultStrategies(context, HandlerAdapter.class);
  26. if (logger.isDebugEnabled()) {
  27. logger.debug("No HandlerAdapters found in servlet '" + getServletName() + "': using default");
  28. }
  29. }
  30. }

请求处理

流程图

doDispatch方法解析

  1. protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. HttpServletRequest processedRequest = request;
  3. HandlerExecutionChain mappedHandler = null;
  4. boolean multipartRequestParsed = false;
  5. WebAsyncManager asyncManager = WebAsyncUtils.getAsyncManager(request);
  6. try {
  7. try {
  8. ModelAndView mv = null;
  9. Object dispatchException = null;
  10. try {
  11. processedRequest = this.checkMultipart(request);
  12. multipartRequestParsed = processedRequest != request;
  13. // 2.获取处理器映射器
  14. mappedHandler = this.getHandler(processedRequest);
  15. if (mappedHandler == null) {
  16. // 获取不到handler 抛异常或者返回404
  17. this.noHandlerFound(processedRequest, response);
  18. return;
  19. }
  20. // 4.获取处理器适配器器
  21. HandlerAdapter ha = this.getHandlerAdapter(mappedHandler.getHandler());
  22. String method = request.getMethod();
  23. boolean isGet = "GET".equals(method);
  24. if (isGet || "HEAD".equals(method)) {
  25. long lastModified = ha.getLastModified(request, mappedHandler.getHandler());
  26. if ((new ServletWebRequest(request, response)).checkNotModified(lastModified) && isGet) {
  27. return;
  28. }
  29. }
  30. // 6.循环调用拦截器的preHandle方法
  31. if (!mappedHandler.applyPreHandle(processedRequest, response)) {
  32. return;
  33. }
  34. // 8.实际执行代码,handler通过反射执行控制器方法
  35. mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
  36. if (asyncManager.isConcurrentHandlingStarted()) {
  37. return;
  38. }
  39. // 默认视图
  40. this.applyDefaultViewName(processedRequest, mv);
  41. // 10.循环调用拦截的postHandle
  42. mappedHandler.applyPostHandle(processedRequest, response, mv);
  43. } catch (Exception var20) {
  44. dispatchException = var20;
  45. } catch (Throwable var21) {
  46. dispatchException = new NestedServletException("Handler dispatch failed", var21);
  47. }
  48. // 11.处理结果,进行视图解析 & 模板引擎渲染 & request域填充
  49. // 12.内部会调用拦截器的afterCompletion方法
  50. this.processDispatchResult(processedRequest, response, mappedHandler, mv, (Exception)dispatchException);
  51. } catch (Exception var22) {
  52. // 目标方法完成之后执行
  53. this.triggerAfterCompletion(processedRequest, response, mappedHandler, var22);
  54. } catch (Throwable var23) {
  55. // 目标方法完成之后执行
  56. this.triggerAfterCompletion(processedRequest, response, mappedHandler, new NestedServletException("Handler processing failed", var23));
  57. }
  58. } finally {
  59. if (asyncManager.isConcurrentHandlingStarted()) {
  60. if (mappedHandler != null) {
  61. mappedHandler.applyAfterConcurrentHandlingStarted(processedRequest, response);
  62. }
  63. } else if (multipartRequestParsed) {
  64. this.cleanupMultipart(processedRequest);
  65. }
  66. }
  67. }

获取处理器映射器

  1. @Nullable
  2. protected HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  3. if (this.handlerMappings != null) {
  4. Iterator var2 = this.handlerMappings.iterator();
  5. while(var2.hasNext()) {
  6. HandlerMapping mapping = (HandlerMapping)var2.next();
  7. // 核心方法获取执行链
  8. HandlerExecutionChain handler = mapping.getHandler(request);
  9. if (handler != null) {
  10. return handler;
  11. }
  12. }
  13. }
  14. return null;
  15. }
  1. public final HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception {
  2. // 获取handler
  3. Object handler = this.getHandlerInternal(request);
  4. if (handler == null) {
  5. handler = this.getDefaultHandler();
  6. }
  7. if (handler == null) {
  8. // 不满足,返回
  9. return null;
  10. } else {
  11. if (handler instanceof String) {
  12. String handlerName = (String)handler;
  13. handler = this.obtainApplicationContext().getBean(handlerName);
  14. }
  15. // 以handler为参数获取执行链:创建一个执行链对象,handler赋值到内部变量,添加所有拦截器
  16. HandlerExecutionChain executionChain = this.getHandlerExecutionChain(handler, request);
  17. ...
  18. ...
  19. return executionChain;
  20. }
  21. }

获取处理器适配器

  1. protected HandlerAdapter getHandlerAdapter(Object handler) throws ServletException {
  2. if (this.handlerAdapters != null) {
  3. Iterator var2 = this.handlerAdapters.iterator();
  4. while(var2.hasNext()) {
  5. HandlerAdapter adapter = (HandlerAdapter)var2.next();
  6. // 核心判断方法,找到支持该handler的适配器
  7. if (adapter.supports(handler)) {
  8. return adapter;
  9. }
  10. }
  11. }
  12. throw new ServletException("No adapter for handler [" + handler +
  13. "]: The DispatcherServlet configuration needs to include a HandlerAdapter that supports this handler");
  14. }

执行拦截器前置处理preHandle方法

HandlerExecutionChain#applyPreHandle

  • 拦截器的preHandle方法任意一个返回false则访问不到目标方法
  • 拦截器的afterCompletion方法一定会执行
  1. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. HandlerInterceptor[] interceptors = this.getInterceptors();
  3. if (!ObjectUtils.isEmpty(interceptors)) {
  4. for(int i = 0; i < interceptors.length; this.interceptorIndex = i++) {
  5. HandlerInterceptor interceptor = interceptors[i];
  6. // 循环调用
  7. if (!interceptor.preHandle(request, response, this.handler)) {
  8. // 执行完毕拦截器的所有AfterCompletio方法后return
  9. this.triggerAfterCompletion(request, response, (Exception)null);
  10. // 一个返回false即停止循环
  11. return false;
  12. }
  13. }
  14. }
  15. return true;
  16. }

执行控制器的目标方法



InvocableHandlerMethod#doInvoke

  1. @Nullable
  2. protected Object doInvoke(Object... args) throws Exception {
  3. ReflectionUtils.makeAccessible(this.getBridgedMethod());
  4. try {
  5. // method.invoke(obj,args);
  6. // 反射调用目标类的目标方法
  7. // 目标方法:this.getBridgedMethod()
  8. // this.getBean()获取handler中的bean,即为容器中的目标类实例/可能是一个CGLIB增强后的代理对象
  9. return this.getBridgedMethod().invoke(this.getBean(), args);
  10. } catch (IllegalArgumentException var4) {
  11. this.assertTargetBean(this.getBridgedMethod(), this.getBean(), args);
  12. String text = var4.getMessage() != null ? var4.getMessage() : "Illegal argument";
  13. throw new IllegalStateException(this.formatInvokeError(text, args), var4);
  14. } catch (InvocationTargetException var5) {
  15. Throwable targetException = var5.getTargetException();
  16. if (targetException instanceof RuntimeException) {
  17. throw (RuntimeException)targetException;
  18. } else if (targetException instanceof Error) {
  19. throw (Error)targetException;
  20. } else if (targetException instanceof Exception) {
  21. throw (Exception)targetException;
  22. } else {
  23. throw new IllegalStateException(this.formatInvokeError("Invocation failure", args), targetException);
  24. }
  25. }
  26. }

处理返回结果 & 执行拦截器afterCompletion方法

DispatcherServlet#processDispatchResult

  1. private void processDispatchResult(HttpServletRequest request, HttpServletResponse response, @Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv, @Nullable Exception exception) throws Exception {
  2. boolean errorView = false;
  3. if (exception != null) {
  4. if (exception instanceof ModelAndViewDefiningException) {
  5. this.logger.debug("ModelAndViewDefiningException encountered", exception);
  6. mv = ((ModelAndViewDefiningException)exception).getModelAndView();
  7. } else {
  8. Object handler = mappedHandler != null ? mappedHandler.getHandler() : null;
  9. mv = this.processHandlerException(request, response, handler, exception);
  10. errorView = mv != null;
  11. }
  12. }
  13. if (mv != null && !mv.wasCleared()) {
  14. // a.视图解析 & 模板引擎渲染
  15. this.render(mv, request, response);
  16. if (errorView) {
  17. WebUtils.clearErrorRequestAttributes(request);
  18. }
  19. } else if (this.logger.isTraceEnabled()) {
  20. this.logger.trace("No view rendering, null ModelAndView returned.");
  21. }
  22. if (!WebAsyncUtils.getAsyncManager(request).isConcurrentHandlingStarted()) {
  23. if (mappedHandler != null) {
  24. // b.调用拦截器afterCompletion方法
  25. mappedHandler.triggerAfterCompletion(request, response, (Exception)null);
  26. }
  27. }
  28. }

a.视图解析 & 模板引擎渲染

DispatcherServlet#render

  1. protected void render(ModelAndView mv, HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. Locale locale = this.localeResolver != null ? this.localeResolver.resolveLocale(request) : request.getLocale();
  3. response.setLocale(locale);
  4. String viewName = mv.getViewName();
  5. View view;
  6. if (viewName != null) {
  7. // 视图解析
  8. view = this.resolveViewName(viewName, mv.getModelInternal(), locale, request);
  9. if (view == null) {
  10. throw new ServletException("Could not resolve view with name '" + mv.getViewName() + "' in servlet with name '" + this.getServletName() + "'");
  11. }
  12. } else {
  13. view = mv.getView();
  14. if (view == null) {
  15. throw new ServletException("ModelAndView [" + mv + "] neither contains a view name nor a View object in servlet with name '" + this.getServletName() + "'");
  16. }
  17. }
  18. if (this.logger.isTraceEnabled()) {
  19. this.logger.trace("Rendering view [" + view + "] ");
  20. }
  21. try {
  22. if (mv.getStatus() != null) {
  23. response.setStatus(mv.getStatus().value());
  24. }
  25. // 模板引擎渲染
  26. view.render(mv.getModelInternal(), request, response);
  27. } catch (Exception var8) {
  28. if (this.logger.isDebugEnabled()) {
  29. this.logger.debug("Error rendering view [" + view + "]", var8);
  30. }
  31. throw var8;
  32. }
  33. }

b.调用拦截器afterCompletion方法,一定会执行

HandlerExecutionChain#afterCompletion

  1. public void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) throws Exception {
  2. HandlerInterceptor[] interceptors = this.getInterceptors();
  3. if (!ObjectUtils.isEmpty(interceptors)) {
  4. for(int i = this.interceptorIndex; i >= 0; --i) {
  5. HandlerInterceptor interceptor = interceptors[i];
  6. try {
  7. interceptor.afterCompletion(request, response, this.handler, ex);
  8. } catch (Throwable var8) {
  9. logger.error("HandlerInterceptor.afterCompletion threw exception", var8);
  10. }
  11. }
  12. }
  13. }

同一路径时启动报错源码位置

AbstractHandlerMethodMapping#assertUniqueMethodMapping

  1. private void assertUniqueMethodMapping(HandlerMethod newHandlerMethod, T mapping) {
  2. // 根据路径信息获取方法信息
  3. // 一个路径对应2个方法时第二个方法解析时会获取到上个方法的信息
  4. HandlerMethod handlerMethod = this.mappingLookup.get(mapping);
  5. // 根据路径获取到方法信息 并且 2个不是同一个方法时报错提示已经存在
  6. if (handlerMethod != null && !handlerMethod.equals(newHandlerMethod)) {
  7. throw new IllegalStateException(
  8. "Ambiguous mapping. Cannot map '" + newHandlerMethod.getBean() + "' method \n" +
  9. newHandlerMethod + "\nto " + mapping + ": There is already '" +
  10. handlerMethod.getBean() + "' bean method\n" + handlerMethod + " mapped.");
  11. }
  12. }

Spring Mvc原理分析(一)的更多相关文章

  1. Spring MVC 原理探秘 - 容器的创建过程

    1.简介 在上一篇文章中,我向大家介绍了 Spring MVC 是如何处理 HTTP 请求的.Spring MVC 可对外提供服务时,说明其已经处于了就绪状态.再次之前,Spring MVC 需要进行 ...

  2. Spring MVC 原理探秘 - 一个请求的旅行过程

    1.简介 在前面的文章中,我较为详细的分析了 Spring IOC 和 AOP 部分的源码,并写成了文章.为了让我的 Spring 源码分析系列文章更为丰富一些,所以从本篇文章开始,我将来向大家介绍一 ...

  3. spring MVC原理

    spring MVC原理   Spring MVC工作流程图   图一   图二    Spring工作流程描述       1. 用户向服务器发送请求,请求被Spring 前端控制Servelt D ...

  4. Spring学习 6- Spring MVC (Spring MVC原理及配置详解)

    百度的面试官问:Web容器,Servlet容器,SpringMVC容器的区别: 我还写了个文章,说明web容器与servlet容器的联系,参考:servlet单实例多线程模式 这个文章有web容器与s ...

  5. Spring MVC原理及配置

    Spring MVC原理及配置 1. Spring MVC概述 Spring MVC是Spring提供的一个强大而灵活的web框架.借助于注解,Spring MVC提供了几乎是POJO的开发模式,使得 ...

  6. Spring事务原理分析-部分二

    Spring事务原理分析-部分二 说明:这是我在蚂蚁课堂学习了余老师Spring手写框架的课程的一些笔记,部分代码代码会用到余老师的课件代码.这不是广告,是我听了之后觉得很好. 课堂链接:Spring ...

  7. Spring事务原理分析-部分一

    Spring事务原理分析-部分一 什么事务 事务:逻辑上的一组操作,组成这组操作的各个单元,要么全都成功,要么全都失败. 事务基本特性 ⑴ 原子性(Atomicity) 原子性是指事务包含的所有操作要 ...

  8. Spring核心原理分析之MVC九大组件(1)

    本文节选自<Spring 5核心原理> 1 什么是Spring MVC Spring MVC 是 Spring 提供的一个基于 MVC 设计模式的轻量级 Web 开发框架,本质上相当于 S ...

  9. spring之mvc原理分析及简单模拟实现

    在之前的一篇博客中已经简单的实现了spring的IOC和DI功能,本文将在之前的基础上实现mvc功能. 一 什么是MVC MVC简单的说就是一种软件实现的设计模式,将整个系统进行分层,M(model ...

随机推荐

  1. UI自动化学习笔记- PO模型介绍和使用

    一.PO模型 1.PO介绍:page(页面) object(对象) 在自动化中,Selenium 自动化测试中有一个名字经常被提及 PageObject (思想与面向对象的特征相同),通常PO 模型可 ...

  2. tomcat的单例多线程代码示例(十)

    一.懒汉式单例多线程模式 1.创建模拟的servlet生成器 package cn.bjsxt.sing; import java.util.UUID; public class LszySingle ...

  3. js 正序、倒序、按字段排序方法

    js 基础--sort方法: arrayObject.sort(sortby); 参数:定义排序规则(正序.倒序.按字段排序)的函数: 返回值:对数组的引用.请注意,数组在原数组上进行排序,不生成副本 ...

  4. jvm源码解读--15 oop对象详解

    (gdb) p obj $15 = (oopDesc *) 0xf3885d08 (gdb) p * obj $16 = { _mark = 0x70dea4e01, _metadata = { _k ...

  5. Docker与k8s的恩怨情仇(七)—— “服务发现”大法让你的内外交互原地起飞

    转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 第一章:Docker与k8s的恩怨情仇(一)-成为PaaS前浪的Cloud Foundry 第二章:Dock ...

  6. 题解 P6688 可重集

    己所欲者,杀而夺之,亦同天赐 解题思路 一定不要用自动溢出的 Hash!!!!!!! 我真的是调吐了... 思路非常简单明了 : 需要我们创新一下 Hash. 首先我们的 Hash 要满足无序性.. ...

  7. JUC学习笔记(二)

    JUC学习笔记(一)https://www.cnblogs.com/lm66/p/15118407.html 1.Lock接口 1.1.Synchronized 1.1.1.Synchronized关 ...

  8. RHCE_DAY07

    文件共享服务FTP介绍 FTP(File Transfet Protocol):文件传输协议 FTP是一种在互联网中基于TCP协议端到端的数据传输协议 基于C/S架构,默认使用20.21号端口 端口2 ...

  9. Windows协议 Kerberos篇

    认证流程 角色 功能 Domain Controller 也就是域控 Key Distribution Center 秘钥分发中心,简称KDC,默认安装在域控里,包括AS.AD和TGS. Accoun ...

  10. solr7.4.0+mysql+solrj(简而优美)

    目录: 1 solr7部署+创建核心2 solr mysql 连接 2.1 导入相关 jar包 2.2 配置连接信息 2.3 配置中文分析器3 solrj JAVA客户端应用 3.1 solrj 构建 ...