说在前面
前期回顾
sharding-jdbc源码解析 更新完毕
spring源码解析 更新完毕
spring-mvc源码解析 更新完毕
spring-tx源码解析 更新完毕
spring-boot源码解析 更新完毕
rocketmq源码解析 更新完毕
dubbbo源码解析 更新完毕
netty源码解析 更新完毕
spring源码架构更新完毕
spring-mvc源码架构更新完毕
springboot源码架构更新中
github https://github.com/tianheframe
sharding-jdbc源码解析 更新完毕
rocketmq源码解析 更新完毕
seata 源码解析 更新完毕
dubbo 源码解析 更新完毕
netty 源码解析 更新完毕
源码解析
org.springframework.boot.web.servlet.ErrorPageRegistry 注册ErrorPage的接口。
void addErrorPages(ErrorPage... errorPages);
添加ErrorPage
org.springframework.boot.context.embedded.ConfigurableEmbeddedServletContainer 初始化EmbeddedServletContainer的接口。
void setContextPath(String contextPath);
设置嵌入式servlet容器的上下文路径。上下文应该以“/”字符开始,而不是以“/”字符结束。可以使用空字符串指定缺省上下文路径。
void setPort(int port);
设置嵌入式servlet容器应该监听的端口。如果没有指定端口“8080”将被使用。使用端口-1禁用自动启动(i。启动web应用程序上下文,但不让它侦听任何端口)。
void setSessionTimeout(int sessionTimeout);
会话超时以秒为单位(默认为30分钟)。如果为0或负数,则会话永远不会过期。
void setAddress(InetAddress address);
设置InetAddress
void setRegisterDefaultServlet(boolean registerDefaultServlet);
设置是否应该注册DefaultServlet。缺省值为true,因此将提供来自文档根目录的文件。
void setErrorPages(Set extends ErrorPage> errorPages);
设置ErrorPage
void setInitializers(List extends ServletContextInitializer> initializers);
设置除了EmbeddedServletContainerFactory.getEmbeddedServletContainer(ServletContextInitializer…)参数之外,还应该应用的ServletContextInitializer。此方法将替换任何以前设置或添加的初始化器。
void addInitializers(ServletContextInitializer... initializers);
将servletcontextinitialalizer添加到除了EmbeddedServletContainerFactory.getEmbeddedServletContainer(ServletContextInitializer…)参数之外,还应该应用的那些参数。
void setJspServlet(JspServlet jspServlet);
设置JspServlet
void setCompression(Compression compression);
设置将应用于容器的默认连接器的压缩配置。
org.springframework.boot.context.embedded.EmbeddedServletContainerFactory 可以用来创建embeddedservletcontainer的工厂接口。如果可能的话,我们鼓励实现扩展AbstractEmbeddedServletContainerFactory。
EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers);
获取一个新的已完全配置但暂停的EmbeddedServletContainer实例。在调用EmbeddedServletContainer.start()之前,客户机不应该能够连接到返回的服务器(当ApplicationContext被完全刷新时才会发生这种情况)。
org.springframework.boot.context.embedded.AbstractConfigurableEmbeddedServletContainer ConfigurableEmbeddedServletContainer抽象实现
private static final int DEFAULT_SESSION_TIMEOUT = (int) TimeUnit.MINUTES .toSeconds(30);
默认session超时时间
private String contextPath = "";
contextPath
private boolean registerDefaultServlet = true;
是否注册默认的servlet
private int port = 8080;
集成servlet容器端口
private List initializers = new ArrayList();
ServletContextInitializer
private Set errorPages = new LinkedHashSet();
errorPages
private JspServlet jspServlet = new JspServlet();
jspServlet
private Compression compression;
compression
protected final ServletContextInitializer[] mergeInitializers( ServletContextInitializer... initializers) { List mergedInitializers = new ArrayList(); mergedInitializers.addAll(Arrays.asList(initializers)); mergedInitializers.addAll(this.initializers); return mergedInitializers .toArray(new ServletContextInitializer[mergedInitializers.size()]); }
希望将指定的ServletContextInitializer参数与在此实例中定义的参数组合使用的子类可以使用的实用程序方法。
protected boolean shouldRegisterJspServlet() { return this.jspServlet != null && this.jspServlet.getRegistered() && ClassUtils .isPresent(this.jspServlet.getClassName(), getClass().getClassLoader()); }
返回是否应该向嵌入容器注册JSP servlet。
org.springframework.boot.context.embedded.AbstractEmbeddedServletContainerFactory EmbeddedServletContainerFactory抽象实现
private static final String[] COMMON_DOC_ROOTS = { "src/main/webapp", "public", "static" };
默认文档路径
protected final File getValidDocumentRoot() { File file = getDocumentRoot(); // If document root not explicitly set see if we are running from a war archive如果没有显式地设置文档根目录,请查看是否从war存档运行 file = (file != null) ? file : getWarFileDocumentRoot(); // If not a war archive maybe it is an exploded war 查询web-inf下的war包 file = (file != null) ? file : getExplodedWarFileDocumentRoot(); // Or maybe there is a document root in a well-known location 查询"src/main/webapp", "public" ,"static" 路径下的文件 file = (file != null) ? file : getCommonDocumentRoot(); if (file == null && this.logger.isDebugEnabled()) { this.logger .debug("None of the document roots " + Arrays.asList(COMMON_DOC_ROOTS) + " point to a directory and will be ignored."); } else if (this.logger.isDebugEnabled()) { this.logger.debug("Document root: " + file); } return file; }
查询war包文件,"src/main/webapp", "public" ,"static"的文件
private boolean isStaticResourceJar(URL url) { try { if ("file".equals(url.getProtocol())) { File file = new File(url.toURI()); return (file.isDirectory() && new File(file, "META-INF/resources").isDirectory()) || isResourcesJar(file); } else { URLConnection connection = url.openConnection(); if (connection instanceof JarURLConnection && isResourcesJar((JarURLConnection) connection)) { return true; } } } catch (Exception ex) { throw new IllegalStateException(ex); } return false; }
判断是不是静态资源
private boolean isResourcesJar(File file) { try { return file.getName().endsWith(".jar") && isResourcesJar(new JarFile(file)); } catch (IOException ex) { this.logger.warn("Unable to open jar '" + file + "' to determine if it contains static resources", ex); return false; } }
是不是jar文件
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory EmbeddedServletContainerFactory,可用于创建JettyEmbeddedServletContainers。可以使用Spring的servletcontextinitialalizer或Jetty配置进行初始化。除非显式配置,否则此工厂将创建在端口8080上侦听HTTP请求的容器。
private List jettyServerCustomizers = new ArrayList();
jettyServerCustomizers
private int acceptors = -1;
acceptor线程,-1代表无限制
private int selectors = -1;
selector线程,-1代表无限制
private ThreadPool threadPool;
threadPool
@Override public EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers) { JettyEmbeddedWebAppContext context = new JettyEmbeddedWebAppContext(); int port = (getPort() >= 0) ? getPort() : 0; InetSocketAddress address = new InetSocketAddress(getAddress(), port);// 创建jetty server Server server = createServer(address);// 配置jetty WebAppContext configureWebAppContext(context, initializers);// 初始化handler server.setHandler(addHandlerWrappers(context)); this.logger.info("Server initialized with port: " + port); if (getSsl() != null && getSsl().isEnabled()) { SslContextFactory sslContextFactory = new SslContextFactory(); configureSsl(sslContextFactory, getSsl());// 初始化connector AbstractConnector connector = getSslServerConnectorFactory() .createConnector(server, sslContextFactory, address); server.setConnectors(new Connector[] { connector }); }// 执行JettyServerCustomizer for (JettyServerCustomizer customizer : getServerCustomizers()) { customizer.customize(server); } if (this.useForwardHeaders) { new ForwardHeadersCustomizer().customize(server); } return getJettyEmbeddedServletContainer(server); }
初始化EmbeddedServletContainer
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory#createServer 创建jettyServer
private Server createServer(InetSocketAddress address) { Server server; if (ClassUtils.hasConstructor(Server.class, ThreadPool.class)) {// 设置jettyServer的线程池 server = new Jetty9ServerFactory().createServer(getThreadPool()); } else { server = new Jetty8ServerFactory().createServer(getThreadPool()); }// 设置jettyServer的connector server.setConnectors(new Connector[] { createConnector(address, server) }); return server; }
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory#configureWebAppContext 配置webAppContext
protected final void configureWebAppContext(WebAppContext context, ServletContextInitializer... initializers) { Assert.notNull(context, "Context must not be null");// 设置java.io.tmpdir 临时目录 context.setTempDirectory(getTempDirectory()); if (this.resourceLoader != null) { context.setClassLoader(this.resourceLoader.getClassLoader()); }// 获取servlet的contextPath String contextPath = getContextPath(); context.setContextPath(StringUtils.hasLength(contextPath) ? contextPath : "/"); context.setDisplayName(getDisplayName()); configureDocumentRoot(context); if (isRegisterDefaultServlet()) {// 注册默认的servlet addDefaultServlet(context); } if (shouldRegisterJspServlet()) { addJspServlet(context);// 添加jetty的初始化器 context.addBean(new JasperInitializer(context), true); } addLocaleMappings(context);// 初始化ServletContextInitializer ServletContextInitializer[] initializersToUse = mergeInitializers(initializers);// 设置配置 Configuration[] configurations = getWebAppContextConfigurations(context, initializersToUse); context.setConfigurations(configurations); context.setThrowUnavailableOnStartupException(true); configureSession(context);// 处理WebAppContext之前的钩子方法 postProcessWebAppContext(context); }
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory#addDefaultServlet 注册默认的servlet
protected final void addDefaultServlet(WebAppContext context) { Assert.notNull(context, "Context must not be null"); ServletHolder holder = new ServletHolder(); holder.setName("default"); holder.setClassName("org.eclipse.jetty.servlet.DefaultServlet"); holder.setInitParameter("dirAllowed", "false"); holder.setInitOrder(1);// 添加 servletMapping context.getServletHandler().addServletWithMapping(holder, "/"); context.getServletHandler().getServletMapping("/").setDefault(true); }
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory#addJspServlet 注册jspServlet
protected final void addJspServlet(WebAppContext context) { Assert.notNull(context, "Context must not be null"); ServletHolder holder = new ServletHolder(); holder.setName("jsp"); holder.setClassName(getJspServlet().getClassName()); holder.setInitParameter("fork", "false");// servlet初始化参数 holder.setInitParameters(getJspServlet().getInitParameters()); holder.setInitOrder(3);// 添加jsp servlet context.getServletHandler().addServlet(holder); ServletMapping mapping = new ServletMapping(); mapping.setServletName("jsp"); mapping.setPathSpecs(new String[] { "*.jsp", "*.jspx" }); context.getServletHandler().addServletMapping(mapping); }
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory#getWebAppContextConfigurations 获得webAppContext配置
protected Configuration[] getWebAppContextConfigurations(WebAppContext webAppContext, ServletContextInitializer... initializers) { List configurations = new ArrayList(); configurations.add( getServletContextInitializerConfiguration(webAppContext, initializers));// 获得配置 configurations.addAll(getConfigurations());// 获得错误页面配置 configurations.add(getErrorPageConfiguration()); configurations.add(getMimeTypeConfiguration()); return configurations.toArray(new Configuration[configurations.size()]); }
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory#postProcessWebAppContext 在与Jetty服务器一起使用之前,Post处理Jetty WebAppContext。子类可以覆盖此方法,将额外的处理应用于WebAppContext。
protected void postProcessWebAppContext(WebAppContext webAppContext) { }
子类可以覆盖这个钩子方法
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainerFactory#addHandlerWrappers 配置压缩的handler
private Handler addHandlerWrappers(Handler handler) { if (getCompression() != null && getCompression().getEnabled()) {// 设置压缩的handler handler = applyWrapper(handler, createGzipHandler()); } if (StringUtils.hasText(getServerHeader())) { handler = applyWrapper(handler, new ServerHeaderHandler(getServerHeader())); } return handler; }
private Resource createResource(URL url) throws Exception { if ("file".equals(url.getProtocol())) { File file = new File(url.toURI()); if (file.isFile()) { return Resource.newResource("jar:" + url + "!/META-INF/resources"); } }// 加载资源 return Resource.newResource(url + "META-INF/resources"); }
加载资源
private Configuration getErrorPageConfiguration() { return new AbstractConfiguration() {// 添加错误handler,页面 @Override public void configure(WebAppContext context) throws Exception {// 获得errorHandler ErrorHandler errorHandler = context.getErrorHandler(); context.setErrorHandler(new JettyEmbeddedErrorHandler(errorHandler));// 添加错误页面 addJettyErrorPages(errorHandler, getErrorPages()); } }; }
获得error配置
@Override public AbstractConnector createConnector(Server server, InetSocketAddress address, int acceptors, int selectors) { try { Class> connectorClass = ClassUtils.forName(CONNECTOR_JETTY_8, getClass().getClassLoader());// 创建connector AbstractConnector connector = (AbstractConnector) connectorClass .newInstance();// 设置port ReflectionUtils.findMethod(connectorClass, "setPort", int.class) .invoke(connector, address.getPort());// 设置host ReflectionUtils.findMethod(connectorClass, "setHost", String.class) .invoke(connector, address.getHostString());// 设置acceptor线程数 if (acceptors > 0) { ReflectionUtils.findMethod(connectorClass, "setAcceptors", int.class) .invoke(connector, acceptors); } if (selectors > 0) {// 设置selectorManager Object selectorManager = ReflectionUtils .findMethod(connectorClass, "getSelectorManager") .invoke(connector); ReflectionUtils.findMethod(selectorManager.getClass(), "setSelectSets", int.class) .invoke(selectorManager, selectors); } return connector; } catch (Exception ex) { throw new RuntimeException("Failed to configure Jetty 8 connector", ex); } }
创建connector
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory EmbeddedServletContainerFactory,可用于创建TomcatEmbeddedServletContainers。可以使用Spring的servletcontextinitialators或Tomcat LifecycleListeners初始化。除非显式地进行了其他配置,否则此工厂将创建侦听端口8080上的HTTP请求的容器。
private List contextLifecycleListeners = new ArrayList();
contextLifecycleListeners
private List tomcatContextCustomizers = new ArrayList();
tomcatContextCustomizers
private List tomcatConnectorCustomizers = new ArrayList();
tomcatConnectorCustomizers
private List additionalTomcatConnectors = new ArrayList();
additionalTomcatConnectors
@Override public EmbeddedServletContainer getEmbeddedServletContainer( ServletContextInitializer... initializers) {// 创建tomcat Tomcat tomcat = new Tomcat(); File baseDir = (this.baseDirectory != null) ? this.baseDirectory : createTempDir("tomcat"); tomcat.setBaseDir(baseDir.getAbsolutePath());// 创建connector Connector connector = new Connector(this.protocol);// 设置connector tomcat.getService().addConnector(connector);// 定制化connector customizeConnector(connector); tomcat.setConnector(connector); tomcat.getHost().setAutoDeploy(false);// 配置engine configureEngine(tomcat.getEngine()); for (Connector additionalConnector : this.additionalTomcatConnectors) { tomcat.getService().addConnector(additionalConnector); } prepareContext(tomcat.getHost(), initializers); return getTomcatEmbeddedServletContainer(tomcat); }
创建EmbeddedServletContainer
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#customizeConnector 定制化connector
protected void customizeConnector(Connector connector) { int port = (getPort() >= 0) ? getPort() : 0;// 设置connector端口 connector.setPort(port); if (StringUtils.hasText(this.getServerHeader())) { connector.setAttribute("server", this.getServerHeader()); } if (connector.getProtocolHandler() instanceof AbstractProtocol) { customizeProtocol((AbstractProtocol>) connector.getProtocolHandler()); }// 设置编码 if (getUriEncoding() != null) { connector.setURIEncoding(getUriEncoding().name()); } // If ApplicationContext is slow to start we want Tomcat not to bind to the socket // prematurely...//如果ApplicationContext启动缓慢,我们希望Tomcat不绑定到套接字//过早… connector.setProperty("bindOnInit", "false"); if (getSsl() != null && getSsl().isEnabled()) { customizeSsl(connector); } if (getCompression() != null && getCompression().getEnabled()) {// 定制化压缩相关配置 customizeCompression(connector); }// 执行TomcatConnectorCustomizer的customize方法 for (TomcatConnectorCustomizer customizer : this.tomcatConnectorCustomizers) { customizer.customize(connector); } }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#prepareContext 上下文预处理
protected void prepareContext(Host host, ServletContextInitializer[] initializers) { File docBase = getValidDocumentRoot(); docBase = (docBase != null) ? docBase : createTempDir("tomcat-docbase"); final TomcatEmbeddedContext context = new TomcatEmbeddedContext(); context.setName(getContextPath()); context.setDisplayName(getDisplayName()); context.setPath(getContextPath()); context.setDocBase(docBase.getAbsolutePath()); context.addLifecycleListener(new FixContextListener()); context.setParentClassLoader( (this.resourceLoader != null) ? this.resourceLoader.getClassLoader() : ClassUtils.getDefaultClassLoader()); resetDefaultLocaleMapping(context); addLocaleMappings(context); try { context.setUseRelativeRedirects(false); } catch (NoSuchMethodError ex) { // Tomcat is < 8.0.30. Continue } SkipPatternJarScanner.apply(context, this.tldSkipPatterns); WebappLoader loader = new WebappLoader(context.getParentClassLoader()); loader.setLoaderClass(TomcatEmbeddedWebappClassLoader.class.getName()); loader.setDelegate(true); context.setLoader(loader); if (isRegisterDefaultServlet()) {// 添加默认的servlet addDefaultServlet(context); } if (shouldRegisterJspServlet()) {// 添加jspServlet addJspServlet(context);// 提那家jsp初始化器 addJasperInitializer(context); context.addLifecycleListener(new StoreMergedWebXmlListener()); } context.addLifecycleListener(new LifecycleListener() { @Override public void lifecycleEvent(LifecycleEvent event) { if (event.getType().equals(Lifecycle.CONFIGURE_START_EVENT)) { TomcatResources.get(context) .addResourceJars(getUrlsOfJarsWithMetaInfResources()); } } }); ServletContextInitializer[] initializersToUse = mergeInitializers(initializers); host.addChild(context);// 配置上下文 configureContext(context, initializersToUse); postProcessContext(context); }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#addDefaultServlet 添加默认的servlet
private void addDefaultServlet(Context context) { Wrapper defaultServlet = context.createWrapper(); defaultServlet.setName("default"); defaultServlet.setServletClass("org.apache.catalina.servlets.DefaultServlet"); defaultServlet.addInitParameter("debug", "0"); defaultServlet.addInitParameter("listings", "false"); defaultServlet.setLoadOnStartup(1); // Otherwise the default location of a Spring DispatcherServlet cannot be set defaultServlet.setOverridable(true); context.addChild(defaultServlet); addServletMapping(context, "/", "default"); }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#addJspServlet 添加jspServlet
private void addJspServlet(Context context) { Wrapper jspServlet = context.createWrapper(); jspServlet.setName("jsp"); jspServlet.setServletClass(getJspServlet().getClassName()); jspServlet.addInitParameter("fork", "false"); for (Entry<String, String> initParameter : getJspServlet().getInitParameters() .entrySet()) { jspServlet.addInitParameter(initParameter.getKey(), initParameter.getValue()); } jspServlet.setLoadOnStartup(3); context.addChild(jspServlet); addServletMapping(context, "*.jsp", "jsp"); addServletMapping(context, "*.jspx", "jsp"); }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#addJasperInitializer 添加jsp初始化器
private void addJasperInitializer(TomcatEmbeddedContext context) { try { ServletContainerInitializer initializer = (ServletContainerInitializer) ClassUtils .forName("org.apache.jasper.servlet.JasperInitializer", null) .newInstance(); context.addServletContainerInitializer(initializer, null); } catch (Exception ex) { // Probably not Tomcat 8 } }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#configureContext 配置上下文
protected void configureContext(Context context, ServletContextInitializer[] initializers) {// 创建TomcatStarter TomcatStarter starter = new TomcatStarter(initializers); if (context instanceof TomcatEmbeddedContext) { // Should be true ((TomcatEmbeddedContext) context).setStarter(starter); } context.addServletContainerInitializer(starter, NO_CLASSES); for (LifecycleListener lifecycleListener : this.contextLifecycleListeners) { context.addLifecycleListener(lifecycleListener); } for (Valve valve : this.contextValves) { context.getPipeline().addValve(valve); }// 创建errorPage for (ErrorPage errorPage : getErrorPages()) { new TomcatErrorPage(errorPage).addToContext(context); } for (MimeMappings.Mapping mapping : getMimeMappings()) { context.addMimeMapping(mapping.getExtension(), mapping.getMimeType()); } configureSession(context);// 执行TomcatContextCustomizer的customize方法 for (TomcatContextCustomizer customizer : this.tomcatContextCustomizers) { customizer.customize(context); } }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#postProcessContext 在Tomcat服务器使用Tomcat上下文之前,Post处理它。子类可以覆盖此方法,以便对上下文应用额外的处理。
protected void postProcessContext(Context context) { }
子类可以覆盖这个钩子方法
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainerFactory#getTomcatEmbeddedServletContainer 子类可以覆盖这个方法来返回一个不同的TomcatEmbeddedServletContainer,或者对Tomcat服务器应用额外的处理。
protected TomcatEmbeddedServletContainer getTomcatEmbeddedServletContainer( Tomcat tomcat) { return new TomcatEmbeddedServletContainer(tomcat, getPort() >= 0); }
private void configureSession(Context context) {// 获得session超时时间 long sessionTimeout = getSessionTimeoutInMinutes(); context.setSessionTimeout((int) sessionTimeout); if (isPersistSession()) { Manager manager = context.getManager(); if (manager == null) { manager = new StandardManager(); context.setManager(manager); }// 配置持久化session configurePersistSession(manager); } else { context.addLifecycleListener(new DisablePersistSessionListener()); } }
配置session
public void setContextLifecycleListeners( Collection extends LifecycleListener> contextLifecycleListeners) { Assert.notNull(contextLifecycleListeners, "ContextLifecycleListeners must not be null"); this.contextLifecycleListeners = new ArrayList( contextLifecycleListeners); }
设置contextLifecycleListeners
public void addContextLifecycleListeners( LifecycleListener... contextLifecycleListeners) { Assert.notNull(contextLifecycleListeners, "ContextLifecycleListeners must not be null"); this.contextLifecycleListeners.addAll(Arrays.asList(contextLifecycleListeners)); }
设置contextLifecycleListeners
public void setTomcatContextCustomizers( Collection extends TomcatContextCustomizer> tomcatContextCustomizers) { Assert.notNull(tomcatContextCustomizers, "TomcatContextCustomizers must not be null"); this.tomcatContextCustomizers = new ArrayList( tomcatContextCustomizers); }
设置tomcatContextCustomizers
public void addContextCustomizers( TomcatContextCustomizer... tomcatContextCustomizers) { Assert.notNull(tomcatContextCustomizers, "TomcatContextCustomizers must not be null"); this.tomcatContextCustomizers.addAll(Arrays.asList(tomcatContextCustomizers)); }
设置tomcatContextCustomizers
public void setTomcatConnectorCustomizers( Collection extends TomcatConnectorCustomizer> tomcatConnectorCustomizers) { Assert.notNull(tomcatConnectorCustomizers, "TomcatConnectorCustomizers must not be null"); this.tomcatConnectorCustomizers = new ArrayList( tomcatConnectorCustomizers); }
设置tomcatConnectorCustomizers
public void addConnectorCustomizers( TomcatConnectorCustomizer... tomcatConnectorCustomizers) { Assert.notNull(tomcatConnectorCustomizers, "TomcatConnectorCustomizers must not be null"); this.tomcatConnectorCustomizers.addAll(Arrays.asList(tomcatConnectorCustomizers)); }
添加tomcatConnectorCustomizers
public void addAdditionalTomcatConnectors(Connector... connectors) { Assert.notNull(connectors, "Connectors must not be null"); this.additionalTomcatConnectors.addAll(Arrays.asList(connectors)); }
添加additionalTomcatConnectors
org.springframework.boot.web.support.ErrorPageFilter 一个Servlet过滤器,它为非嵌入式应用程序(即部署的WAR文件)提供了一个ErrorPageRegistry。它注册错误页面,并通过过滤请求并转发到错误页面来处理应用程序错误,而不是让容器处理它们。错误页面是servlet规范的一个特性,但是在规范中没有用于注册错误页面的Java API。
@Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { this.delegate.doFilter(request, response, chain); } private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException { ErrorWrapperResponse wrapped = new ErrorWrapperResponse(response); try {// 执行filterChain的doFilter方法 chain.doFilter(request, wrapped); if (wrapped.hasErrorToSend()) {// 操作错误状态码 handleErrorStatus(request, response, wrapped.getStatus(), wrapped.getMessage()); response.flushBuffer(); } else if (!request.isAsyncStarted() && !response.isCommitted()) { response.flushBuffer(); } } catch (Throwable ex) { Throwable exceptionToHandle = ex; if (ex instanceof NestedServletException) { exceptionToHandle = ((NestedServletException) ex).getRootCause(); }// 操作异常 handleException(request, response, wrapped, exceptionToHandle); response.flushBuffer(); } }
org.springframework.boot.web.support.ErrorPageFilter#handleErrorStatus 操作错误状态码
private void handleErrorStatus(HttpServletRequest request, HttpServletResponse response, int status, String message) throws ServletException, IOException { if (response.isCommitted()) { handleCommittedResponse(request, null); return; } String errorPath = getErrorPath(this.statuses, status); if (errorPath == null) {// 发送错误 response.sendError(status, message); return; } response.setStatus(status);// 设置错误绑定参数 setErrorAttributes(request, status, message);// 请求转发 request.getRequestDispatcher(errorPath).forward(request, response); }
org.springframework.boot.web.support.ErrorPageFilter#handleException 操作异常
private void handleException(HttpServletRequest request, HttpServletResponse response, ErrorWrapperResponse wrapped, Throwable ex) throws IOException, ServletException { Class> type = ex.getClass(); String errorPath = getErrorPath(type); if (errorPath == null) { rethrow(ex); return; } if (response.isCommitted()) { handleCommittedResponse(request, ex); return; }// 转发错误页面 forwardToErrorPage(errorPath, request, wrapped, ex); }
org.springframework.boot.web.support.ErrorPageFilter#forwardToErrorPage 转发错误页面
private void forwardToErrorPage(String path, HttpServletRequest request, HttpServletResponse response, Throwable ex) throws ServletException, IOException { if (logger.isErrorEnabled()) { String message = "Forwarding to error page from request " + getDescription(request) + " due to exception [" + ex.getMessage() + "]"; logger.error(message, ex); }// 设置错误实行 setErrorAttributes(request, 500, ex.getMessage()); request.setAttribute(ERROR_EXCEPTION, ex); request.setAttribute(ERROR_EXCEPTION_TYPE, ex.getClass()); response.reset(); response.setStatus(500);// 转发500错误 request.getRequestDispatcher(path).forward(request, response); request.removeAttribute(ERROR_EXCEPTION); request.removeAttribute(ERROR_EXCEPTION_TYPE); }
org.springframework.boot.context.embedded.EmbeddedServletContainer 表示完全配置的嵌入式servlet容器的简单接口(例如Tomcat或Jetty)。允许启动和停止容器。该类的实例通常通过EmbeddedServletContainerFactory获得。
void start() throws EmbeddedServletContainerException;
启动嵌入式servlet容器。在已经启动的容器上调用此方法没有效果。
void stop() throws EmbeddedServletContainerException;
停止嵌入的servlet容器。在已经停止的容器上调用此方法没有效果。
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer 可用于控制嵌入式Tomcat服务器的EmbeddedServletContainer。通常,这个类应该使用TomcatEmbeddedServletContainerFactory创建,而不是直接创建。
private final Map serviceConnectors = new HashMap();
serviceConnectors
private final Tomcat tomcat;
tomcat
private final boolean autoStart;
是否自动启动
private volatile boolean started;
是否已启动
public TomcatEmbeddedServletContainer(Tomcat tomcat, boolean autoStart) { Assert.notNull(tomcat, "Tomcat Server must not be null"); this.tomcat = tomcat; this.autoStart = autoStart; initialize(); }
初始化servlet容器
private void initialize() throws EmbeddedServletContainerException { TomcatEmbeddedServletContainer.logger .info("Tomcat initialized with port(s): " + getPortsDescription(false)); synchronized (this.monitor) { try {// 设置tomcat引擎 addInstanceIdToEngineName(); try {// 获得tomcat容器上下文 final Context context = findContext(); context.addLifecycleListener(new LifecycleListener() { @Override public void lifecycleEvent(LifecycleEvent event) { if (context.equals(event.getSource()) && Lifecycle.START_EVENT.equals(event.getType())) { // Remove service connectors so that protocol // binding doesn't happen when the service is // started.//删除服务连接器以使协议//绑定不会在服务存在时发生//开始。 removeServiceConnectors(); } } }); // Start the server to trigger initialization listeners 启动服务器以触发初始化侦听器 this.tomcat.start(); // We can re-throw failure exception directly in the main thread 我们可以直接在主线程中重新抛出失败异常 rethrowDeferredStartupExceptions(); try { ContextBindings.bindClassLoader(context, getNamingToken(context), getClass().getClassLoader()); } catch (NamingException ex) { // Naming is not enabled. Continue } // Unlike Jetty, all Tomcat threads are daemon threads. We create a 与Jetty不同,所有Tomcat线程都是守护进程线程。我们创建一个 // blocking non-daemon to stop immediate shutdown 阻塞非守护进程以停止立即关闭 startDaemonAwaitThread(); } catch (Exception ex) { containerCounter.decrementAndGet(); throw ex; } } catch (Exception ex) {// 停止tomcat容器 stopSilently(); throw new EmbeddedServletContainerException( "Unable to start embedded Tomcat", ex); } } }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer#removeServiceConnectors 删除服务connector
private void removeServiceConnectors() {// 获得tomcat服务 for (Service service : this.tomcat.getServer().findServices()) {// 获取服务的connector Connector[] connectors = service.findConnectors().clone(); this.serviceConnectors.put(service, connectors); for (Connector connector : connectors) {// 删除connector service.removeConnector(connector); } } }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer#startDaemonAwaitThread 设置后台线程等待
private void startDaemonAwaitThread() { Thread awaitThread = new Thread("container-" + (containerCounter.get())) { @Override public void run() {// 等待tomcat服务启动 TomcatEmbeddedServletContainer.this.tomcat.getServer().await(); } }; awaitThread.setContextClassLoader(getClass().getClassLoader()); awaitThread.setDaemon(false); awaitThread.start(); }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer#stopSilently 出现异常停止tomcat
private void stopSilently() { try {// 通知tomcat stopTomcat(); } catch (LifecycleException ex) { // Ignore } }
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer#stopTomcat
private void stopTomcat() throws LifecycleException { if (Thread.currentThread() .getContextClassLoader() instanceof TomcatEmbeddedWebappClassLoader) { Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); } this.tomcat.stop(); }
@Override public void start() throws EmbeddedServletContainerException {// 同步线程开关 synchronized (this.monitor) { if (this.started) { return; } try {// 添加之前删除的connector addPreviouslyRemovedConnectors();// 获取tomcat的connector Connector connector = this.tomcat.getConnector(); if (connector != null && this.autoStart) {// 自动启动tomcat performDeferredLoadOnStartup(); } checkThatConnectorsHaveStarted(); this.started = true; TomcatEmbeddedServletContainer.logger .info("Tomcat started on port(s): " + getPortsDescription(true)); } catch (ConnectorStartFailedException ex) {// 停止tomcat stopSilently(); throw ex; } catch (Exception ex) { throw new EmbeddedServletContainerException( "Unable to start embedded Tomcat servlet container", ex); } finally { Context context = findContext(); ContextBindings.unbindClassLoader(context, getNamingToken(context), getClass().getClassLoader()); } } }
启动tomcat
org.springframework.boot.context.embedded.tomcat.TomcatEmbeddedServletContainer#addPreviouslyRemovedConnectors 删除之前删除的connector
private void addPreviouslyRemovedConnectors() {// 查询tomcat服务 Service[] services = this.tomcat.getServer().findServices(); for (Service service : services) {// 获取服务的connector Connector[] connectors = this.serviceConnectors.get(service); if (connectors != null) { for (Connector connector : connectors) {// 添加服务的connector service.addConnector(connector); if (!this.autoStart) {// 停止tomcat的protocolHandler stopProtocolHandler(connector); } } this.serviceConnectors.remove(service); } } }
@Override public void stop() throws EmbeddedServletContainerException {// 同步线程开关 synchronized (this.monitor) { boolean wasStarted = this.started; try { this.started = false; try {// 停止tomcat stopTomcat(); this.tomcat.destroy(); } catch (LifecycleException ex) { // swallow and continue } } catch (Exception ex) { throw new EmbeddedServletContainerException( "Unable to stop embedded Tomcat", ex); } finally { if (wasStarted) { containerCounter.decrementAndGet(); } } } }
停止tomcat
org.springframework.boot.context.embedded.jetty.JettyEmbeddedServletContainer 可用于控制嵌入式Jetty服务器的EmbeddedServletContainer。通常这个类应该使用JettyEmbeddedServletContainerFactory来创建,而不是直接创建。
private final Server server;
server
private final boolean autoStart;
是否自动启动
private Connector[] connectors;
connectors
private volatile boolean started;
是否已启动
public JettyEmbeddedServletContainer(Server server, boolean autoStart) { this.autoStart = autoStart; Assert.notNull(server, "Jetty Server must not be null"); this.server = server; initialize(); }
初始化servlet容器
private void initialize() { synchronized (this.monitor) { try { // Cache the connectors and then remove them to prevent requests being // handled before the application context is ready.//缓存连接器,然后删除它们,以防止出现请求// 在应用程序上下文准备好之前处理。// 获得server的connector this.connectors = this.server.getConnectors(); this.server.addBean(new AbstractLifeCycle() { @Override protected void doStart() throws Exception { for (Connector connector : JettyEmbeddedServletContainer.this.connectors) { Assert.state(connector.isStopped(), "Connector " + connector + " has been started prematurely"); } JettyEmbeddedServletContainer.this.server.setConnectors(null); } }); // Start the server so that the ServletContext is available jetty服务启用动 this.server.start(); this.server.setStopAtShutdown(false); } catch (Throwable ex) { // Ensure process isn't left running 停止jetty stopSilently(); throw new EmbeddedServletContainerException( "Unable to start embedded Jetty servlet container", ex); } } }
初始化jetty并启动,出现异常停止jetty
private void stopSilently() { try { this.server.stop(); } catch (Exception ex) { // Ignore } }
停止jetty
@Override public void start() throws EmbeddedServletContainerException { synchronized (this.monitor) { if (this.started) { return; }// 设置connector this.server.setConnectors(this.connectors); if (!this.autoStart) { return; } try {// 启动jetty this.server.start(); for (Handler handler : this.server.getHandlers()) {// 初始化handler handleDeferredInitialize(handler); } Connector[] connectors = this.server.getConnectors(); for (Connector connector : connectors) { try {// 启动connector connector.start(); } catch (IOException ex) { if (connector instanceof NetworkConnector && findBindException(ex) != null) { throw new PortInUseException( ((NetworkConnector) connector).getPort()); } throw ex; } } this.started = true; JettyEmbeddedServletContainer.logger .info("Jetty started on port(s) " + getActualPortsDescription()); } catch (EmbeddedServletContainerException ex) {// 停止 stopSilently(); throw ex; } catch (Exception ex) { stopSilently(); throw new EmbeddedServletContainerException( "Unable to start embedded Jetty servlet container", ex); } } }
启动jetty容器,出现异常停止
@Override public void stop() {// 同步线程开关 synchronized (this.monitor) { this.started = false; try {// 通知jetty服务 this.server.stop(); } catch (InterruptedException ex) { Thread.currentThread().interrupt(); } catch (Exception ex) { throw new EmbeddedServletContainerException( "Unable to stop embedded Jetty servlet container", ex); } } }
停止jetty服务
org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizerBeanPostProcessor 将bean工厂中的所有embeddedservletcontainercustomizer应用到ConfigurableEmbeddedServletContainer bean的BeanPostProcessor。
实现了org.springframework.beans.factory.config.BeanPostProcessor、org.springframework.beans.factory.BeanFactoryAware接口。
private ListableBeanFactory beanFactory;
beanFactory
private List customizers;
customizers
@Override public void setBeanFactory(BeanFactory beanFactory) { Assert.isInstanceOf(ListableBeanFactory.class, beanFactory, "EmbeddedServletContainerCustomizerBeanPostProcessor can only be used " + "with a ListableBeanFactory"); this.beanFactory = (ListableBeanFactory) beanFactory; }
重写org.springframework.beans.factory.BeanFactoryAware#setBeanFactory方法,设置BeanFactory
@Override public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { if (bean instanceof ConfigurableEmbeddedServletContainer) { postProcessBeforeInitialization((ConfigurableEmbeddedServletContainer) bean); } return bean; }
重写org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization方法,执行org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer#customize方法
private void postProcessBeforeInitialization( ConfigurableEmbeddedServletContainer bean) { for (EmbeddedServletContainerCustomizer customizer : getCustomizers()) { customizer.customize(bean); } }
@Override public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { return bean; }
重写org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization方法,不做处理
private Collection getCustomizers() { if (this.customizers == null) { // Look up does not include the parent context 从BeanFactory中获得EmbeddedServletContainerCustomizer this.customizers = new ArrayList( this.beanFactory .getBeansOfType(EmbeddedServletContainerCustomizer.class, false, false) .values()); Collections.sort(this.customizers, AnnotationAwareOrderComparator.INSTANCE); this.customizers = Collections.unmodifiableList(this.customizers); } return this.customizers; }
从BeanFactory中获取EmbeddedServletContainerCustomizer
org.springframework.boot.context.embedded.WebApplicationContextServletContextAwareProcessor servletcontext - wareprocessor的变体,用于ConfigurableWebApplicationContext。可以在初始化ServletContext或ServletConfig之前注册处理器时使用。
实现了org.springframework.web.context.support.ServletContextAwareProcessor接口。
private final ConfigurableWebApplicationContext webApplicationContext;
webApplicationContext
@Override protected ServletContext getServletContext() { ServletContext servletContext = this.webApplicationContext.getServletContext(); return (servletContext != null) ? servletContext : super.getServletContext(); } @Override protected ServletConfig getServletConfig() { ServletConfig servletConfig = this.webApplicationContext.getServletConfig(); return (servletConfig != null) ? servletConfig : super.getServletConfig(); }
获得servletContext、servletConfig
org.springframework.boot.context.embedded.InitParameterConfiguringServletContextInitializer 配置servlet初始化参数的org.springframework.boot.web.servlet.ServletContextInitializer实现
@Override public void onStartup(ServletContext servletContext) throws ServletException { for (Entry<String, String> entry : this.parameters.entrySet()) { servletContext.setInitParameter(entry.getKey(), entry.getValue()); } }
设置servletContext参数
org.springframework.boot.context.embedded.ServerPortInfoApplicationContextInitializer ApplicationContextInitializer为嵌入servletcontainer服务器实际监听的端口设置环境属性。local.server财产”。port”可以直接使用@Value注入到测试中,也可以通过环境获得。如果EmbeddedWebApplicationContext有一个名称空间集,它将用于构造属性名。例如,“management”执行器上下文将具有属性名称“local.management.port”。
属性将自动传播到任何父上下文。
org.springframework.boot.context.embedded.EmbeddedServletContainerInitializedEvent 事件,该事件将在刷新上下文并准备好EmbeddedServletContainer后发布。用于获取正在运行的服务器的本地端口。正常情况下,它已经启动,但是监听器可以自由地检查服务器并停止和启动它。
private final EmbeddedWebApplicationContext applicationContext;
applicationContext
org.springframework.boot.context.embedded.EmbeddedServletContainerCustomizer 用于自定义自动配置的嵌入式servlet容器的策略接口。任何这种类型的bean都会在容器本身启动之前得到容器工厂的回调,因此您可以设置端口、地址、错误页面等。注意:对这个接口的调用通常是由EmbeddedServletContainerCustomizerBeanPostProcessor发出的,它是一个BeanPostProcessor(在ApplicationContext生命周期的早期被调用)。在封闭的BeanFactory中懒洋洋地查找依赖项可能比使用@Autowired注入依赖项更安全。
void customize(ConfigurableEmbeddedServletContainer container);
定制化ConfigurableEmbeddedServletContainer
org.springframework.boot.context.embedded.tomcat.TomcatConnectorCustomizer 回调接口,可用于自定义Tomcat连接器。
void customize(Connector connector);
定制化connector
org.springframework.boot.context.embedded.tomcat.TomcatContextCustomizer 回调接口,可用于自定义Tomcat上下文。
void customize(Context context);
定制化context
org.springframework.boot.context.embedded.jetty.JettyServerCustomizer 回调接口,可用于自定义Jetty服务器。
void customize(Server server);
定制化server
org.springframework.boot.context.embedded.tomcat.TomcatStarter 用于触发servletcontextinitialalizer并跟踪启动错误的ServletContainerInitializer。实现了javax.servlet.ServletContainerInitializer接口
private final ServletContextInitializer[] initializers;
ServletContextInitializers
@Override public void onStartup(Set> classes, ServletContext servletContext) throws ServletException { try { for (ServletContextInitializer initializer : this.initializers) { initializer.onStartup(servletContext); } } catch (Exception ex) { this.startUpException = ex; // Prevent Tomcat from logging and re-throwing when we know we can // deal with it in the main thread, but log for information here.//当我们知道可以的时候,防止Tomcat日志记录和重新抛出//在主线程中处理它,但是在这里记录信息。 if (logger.isErrorEnabled()) { logger.error("Error starting Tomcat context. Exception: " + ex.getClass().getName() + ". Message: " + ex.getMessage()); } } }
执行org.springframework.boot.web.servlet.ServletContextInitializer#onStartup方法。
org.springframework.boot.context.embedded.JspServlet
private Map<String, String> initParameters = new HashMap<String, String>();
initParameters
private boolean registered = true;
是否应该将JSP servlet注册到嵌入式servlet容器中。
说在最后
本次解析仅代表个人观点,仅供参考。
扫码进入技术微信群
钉钉技术群qq技术群