从ApacheTomcat架构谈面试到源码编译环境v10.0.12
概述
开启博客分享已近三个月,感谢所有花时间精力和小编一路学习和成长的伙伴们,有你们的支持,我们继续再接再厉
**本人博客网站 **IT小神 www.itxiaoshen.com
定义
Tomcat官网 http://tomcat.apache.org/
Apache Tomcat软件是Jakarta Servlet、Jakarta Server Pages、Jakarta Expression Language、Jakarta WebSocket、Jakarta annotation和Jakarta Authentication规范的开源实现。简单来说也是一个基于Servlet、JSP规范的轻量级Web应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,也是大部分Java技术栈开发和调试Web程序的首选,目前官方最新版本为10.0.12 Released,而10.1.0-M6 Released还是alpha阶段。
Tomcat最初是由Sun的软件架构师詹姆斯·邓肯·戴维森开发的,后来他帮助将其变为开源项目,并由Sun贡献给Apache软件基金会,成为Apache的定级项目
Tomcat、Jetty、Undertow这几个都是非常有名实现Servlet规范的应用服务器,Tomcat本身也是业界上非常优秀的中间件,简单可可以将Tomcat看成是一个Http服务器+Servlet容器,Servlet 容器是管理和运行 Servlet 的;相信大家对这只三脚猫Logo都是非常熟悉了,不管是在学校和还是工作都经常使用它,特别是Java程序员最初学习编程都经历过在Idea或Eclipse中配置Tomcat启动Web项目,当然还可以通过基于tomcat maven插件或者SpringBoot内嵌web容器(我们在前面《Spring Boot浅聊入门v2.5.3文章》说到Spring Boot内嵌Tomcat容器其实就是New 创建Tomcat的实例)方式调试运行。
Servlet简介
大家都非常了解Java Web的三大组件Servlet,Filter,Listener,但我们本篇决定不展开聊Servlet规范部分,当前面试官也会让你谈谈对于Servlet的理解,我们这里只是简单提下后续有时间再针对Servlet相关知道再来深入研究分析,这里主要为了学习tomcat架构实现而简单说下Servlet容器工作流程:
- Web客户向Servlet容器(比如tomcat)发出Http请求;
- Servlet容器解析Web客户的Http请求;
- Servlet容器创建一个HttpRequest对象,在这个对象中封装Http请求信息;
- Servlet容器创建一个HttpResponse对象;
- Servlet容器调用HttpServlet的service方法,把HttpRequest和HttpResponse对象作为service方法的参数传给HttpServlet对象;
- HttpServlet事实上是servlet的一种子类实例也是最一般的实例。当编写一个servlet时,必须直接或间接实现servlet接口,最可能实现的方法就是扩展javax.servlet.genericservlet或javax.servlet.http.httpservlet,其中genericservlet类提供了servlet接口的基本实现,httpservlet类扩展了genericservlet并且提供了servlet接口中具体于http的实现。
- HttpServlet调用HttpRequest的有关方法,获取HTTP请求信息;
- HttpServlet调用HttpResponse的有关方法,生成响应数据;
- 一般通过HttpServletRequest和HttpServletResponse获取HTTP请求信息和返回响应。事实上servlet理论上可以处理多种形式的请求响应形式 http只是其中之一 所以HttpServletRequest HttpServletResponse分别是ServletRequest和ServletResponse的子类。一般,HttpServlet对应HttpServletRequest和HttpServletResponse。
- Servlet容器把HttpServlet的响应结果传给Web客户。
官方用户指南
Tomcat10.0官方用户指南 https://tomcat.apache.org/tomcat-10.0-doc/index.html
简单安装
#安装Tomcat需要先保证有安装JDK环境,建议JDK版本为8以上,JDK17现在都已可用了
#解压文件
unzip apache-tomcat-10.0.12.zip
#进入目录
cd apache-tomcat-10.0.12/bin
#启动tomcat
./startup.sh
#查看默认配置8080端口服务是否启动
netstat -lntp | grep 8080
架构源码剖析
整体架构
Tomcat源码中大量使用模板方法和适配器的设计模式,封装很多的组件,组件之间呈现出明显的层级关系,一层套着一层,这就是经典的套娃式架构设计;个人推荐从tomca配置文件开始理解其架构这个也是基于套娃式架构设计的优点得来。Tomcat 模块分层结构及相关模块的功能说明如下图:
Tomcat 核心组件架构图如下所示:
上面有些功能我们可以通过上面的1.3章节提供的官方用户指南查阅到相关信息,这里简单罗列几条说明
- Listener 组件
- 可以在 Tomcat 生命周期中完成某些容器相关的监听器。
- JNDI
- JNDI是 Java 命名与目录接口,是属于 J2EE 规范的,Tomcat 对其进行了实现。JNDI 在 J2EE 中的角色就是“交换机”,即 J2EE 组件在运行时间接地查找其他组件、资源或服务的通用机制(你可以简单理解为给资源取个名字,再根据名字来找资源)。
- Cluster 组件
- 提供了集群功能,可以将对应容器需要共享的数据同步到集群中的其他 Tomcat 实例中。
- Realm 组件
- 提供了容器级别的用户-密码-权限的数据对象,配合资源认证模块使用。
- Loader 组件
- Web 应用加载器,用于加载 Web 应用的资源,它要保证不同 Web 应用之间的资源隔离。
- Manager 组件
- Servlet 映射器,它属于 Context 内部的路由映射器,只负责该 Context 容器的路由导航。
Catalina 是 Tomcat 中的一个重要组件,它负责的是解析 Tomcat 的配置文件(server.xml),以此来创建服务器 Server 组件并进行管理。下面是Tomcat的conf目录下大名鼎鼎server.xml核心配置的内容结构,Server-Service-(Connector+Engine),在GlobalNamingResouce 域中可以定义全局资源 tomcat-user.xml,在web.xml文件中也有常见如session-config配置session超时时间默认是30分钟。
<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN">
<Listener className="org.apache.catalina.startup.VersionLoggerListener" />
<GlobalNamingResources>
<Resource name="UserDatabase" auth="Container"
type="org.apache.catalina.UserDatabase"
description="User database that can be updated and saved"
factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
pathname="conf/tomcat-users.xml" />
</GlobalNamingResources>
<Service name="Catalina">
<Executor name="tomcatThreadPool" namePrefix="catalina-exec-"
maxThreads="150" minSpareThreads="4"/>
<Connector executor="tomcatThreadPool"
port="8080" protocol="HTTP/1.1"
connectionTimeout="20000"
redirectPort="8443" />
</Connector>
<Engine name="Catalina" defaultHost="localhost">
<Realm className="org.apache.catalina.realm.LockOutRealm">
<Realm className="org.apache.catalina.realm.UserDatabaseRealm"
resourceName="UserDatabase"/>
</Realm>
<Host name="localhost" appBase="webapps"
unpackWARs="true" autoDeploy="true">
<Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs"
prefix="localhost_access_log" suffix=".txt"
pattern="%h %l %u %t "%r" %s %b" />
</Host>
</Engine>
</Service>
</Server>
- Server :代表了一个 Tomcat 实例,包含了 Servlet 容器以及其他组件,负责组装并启动 Servlet 引擎、Tomcat 连接器。每个Tomcat都只有一个Server,表示整个服务环境。一个Server中可以有多个Service。Server就管理多个Service。tomcat源码中服务继承自LifeCycle,tomcat服务组件顶层接口,有唯一实现StandardServer。
- Service:服务是 Server 内部的组件,一个Server中可以有多个Service,它将若干个 Connector 组件绑定到一个 Container,每一个Service中可以有多个Connector和一个Container(Engine)。
- Connector主要用来接收请求,解析请求内容,封装request和response,然后将准备好的数据交给Container处理。
- Container就是我们常说的容器,里面可以有多个Host,一个host表示一个虚拟主机,就是一个对应一个WebApps. 最后Container处理完请求之后会将响应内容返回给Connecter,再由Connecter返回给客户端。
- Executor 执行器:tomcat线程池的配置,提供给Connector。
- Connecter:负责处理用户的 servlet 请求,并返回对象给 web 用户的模块
我们知道tomcat是处理http的请求,意味着tomcat使用的是 HTTP 协议进行数据传输,而HTTP 协议是一种应用层协议,其本质就是一种浏览器与服务器之间约定好的通信格式,因此tomcat作为一个Http服务器需要包含接受连接、解析请求数据、处理请求和发送响应这几大块功能。在这里我们再分析tomcat最核心的两个功能:
- 处理 Socket 连接,负责网络字节流与 Request 和 Response 对象的转化。
- 加载和管理 Servlet,由 Servlet 具体负责处理 Request 请求。
Tomcat 最底层使用的是Socket进行连接的,所以这里也涉及网络IO模型,通过socket监听本机端口,接收和处理监听端口的网络请求,Request和Response是按照Http协议来封装的,所以Connector同时需要实现TCP/IP协议和Http协议;基于核心功能Tomcat 设计了两个核心组件连接器(Connector)和容器(Container)来分别实现,连接器复杂对外接收和解析请求,封装request和response,最后把数据交给Containner,容器负责内部处理。
- 网络通信。
- 应用层协议解析。
- Tomcat Request/Response 与 ServletRequest/ServletResponse 的转化。
连接器
连接器主要需要完成以下三个核心功能:
- socket 通信,也就是网络通信。
- 应用层协议解析,解析处理应用层协议,封装成一个 Request 对象。
- 将 Request 转换为 ServletRequest,将 Response 转换为 ServletResponse。
Tomcat 通过 EndPoint、Processor 和 Adapter这 3 个组件来实现连接器,这三个组件之间通过抽象接口进行交互。从一个请求的正向流程来看, Endpoint 负责提供请求字节流给 Processor,Processor 负责提供 Tomcat 定义的 Request 对象给 Adapter,Adapter 负责提供标准的 ServletRequest 对象给 Servlet 容器:
- Endpoint 和 Processor 可以自由组合,放在一起抽象成了 ProtocolHandler 组件,连接器用 ProtocolHandler 来处理网络连接和应用层协议。Connector中具体用事件处理器来处理请求【ProtocoHandler】;不同的ProtocoHandler代表不同的连接类型【所以一个Service中可以有多个Connector】 例如:Http11Protocol使用普通的Socket来连接的,Http11NioProtocol使用NioSocket连接。
- EndPoint:对接 I/O 模型,提供字节流给Processor,监听通信端口,是对传输层的抽象,处理底层Socket的网络连接,用来实现 TCP/IP 协议的。 是一个接口,对应的抽象类为AbstractEndPoint,有很多实现类,比如NioEndPoint,JIoEndPoint等。在其中有两个组件,一个 是Acceptor,另外一个是SocketProcessor。 Acceptor用于监听Socket连接请求,SocketProcessor用于处理接收到的Socket请求。EndPoint 接收到 Socket 连接后,生成一个 SocketProcessor 任务提交到线程池去处理,SocketProcessor 的 Run 方法会调用 Processor 组件去解析应用层协议,Processor 通过解析生成 Request 对象后,会调用 Adapter 的 Service 方法。
- Processor:对接应用层协议,提供Tomcat Request对象给Adapter,Processor是用于实现HTTP协议的,也就是说Processor是针对应用层协议的抽象。 Processor接受来自EndPoint的Socket,然后解析成Tomcat Request和Tomcat Response对象,最后通过Adapter 提交给容器。 对应的抽象类为AbstractProcessor,有很多实现类,比如AjpProcessor、Http11Processor等。
- Adapter:遵循 Servlet 规范,提供ServletRequest给容器,ProtocolHandler接口负责解析请求并生成 Tomcat Request 类。 需要把这个 Request 对象转换成 ServletRequest。 Tomcat 引入CoyoteAdapter,这是适配器模式的经典运用,连接器调用 CoyoteAdapter 的 sevice 方法,传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方 法,将请求适配到Servlet容器 Container 架构。
容器
容器主要用于封装和管理Servlet以及具体处理Request请求。Tomcat 中设计四大Servlet容器组件,分别是Engine、Host、Context、Wrapper--->Servlet,这 4 种容器不是平行关系,而是父子关系。在tomcat源码org.apache.catalina.core.StandardEngine四个都有其标准实现,每一个容器都有一个 Pipeline 对象。
- Engine:整个 Catalina 的 Servlet 容器引擎,用来管理多个虚拟站点,一个Service最多只能有一个Engine,但是一个引擎可包含多个 Host。
- Host:代表的是一个虚拟主机,或者说一个站点,可以给 Tomcat 配置多个虚拟主机地址,而一个虚拟主机下可包含多个 Context。
- Context:表示一个 Web 应用程序,相当于我们在webapp下的应用,一个 Web 应用通常有多个 Servlet,一个Web应用可包含多个 Wrapper子容器。
- Wrapper:servlet包装类,包装Servlet负责管理整个 Servlet 的生命周期,包括装载、初始化、资源回收等,每一个Wraper都包装着Servlet。
PipeLine和Valve(管道和阀门)
Engine、Host、Context、Wrapper容器都继承ContainerBase,而ContainerBase有StandardPipeLine对象,每个容器构造方法setBasic设置默认Valve(StandardEngineValve),PipeLine和Valve组件的init、start。
Connector使用容器Container处理请求时,connector.getService().getContainer().getPipeLine().getFirst().invoke(request,response);
启动流程
整个 Tomcat 其实就是一个 Catalina 实例,Tomcat 启动的时候会初始化这个实例,Catalina 实例通过加载server.xml 完成其他实例的创建,创建并管理一个 Server,Server 创建并管理多个服务, 每个服务又可以有多个Connector 和一个 Container。
我们知道启动tomcat是执行startup.sh脚本文件,这个脚本文件里又执行catalina.sh最终是执行org.apache.catalina.startup.Bootstrap类。
因此得知Tomcat从Bootstrap类main方法开始,以链的方式逐级调用各模块的init方法进行初始化, 待各个模块都初始化后, 又会逐级调用各个模块的start()方法启动各个模块;commonLoader、catalinaLoader、sharedLoader这三个类加载器打破双亲委派。下面是tomcat启动流程时序图:
内嵌示例
接下来我们演示内嵌tomcat运行示例,创建maven项目,pom文件
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>spring-extend</artifactId>
<groupId>com.itxs</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>tomcat-test</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.apache.tomcat.embed</groupId>
<artifactId>tomcat-embed-core</artifactId>
<version>8.5.28</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jasper</artifactId>
<version>8.5.28</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.3.9</version>
<scope>compile</scope>
</dependency>
</dependencies>
</project>
创建一个可以测试Servlet,MyFirstServlet.java
package com.itxs;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
public class MyFirstServlet extends HttpServlet {
private static final long serialVersionUID = 1L;
@Override
protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws IOException {
doPost(req, resp);
}
@Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws IOException {
resp.getWriter().print("hello tomcat servlet,access success!!!");
}
}
TomcatApplication.java文件
package com.itxs;
import org.apache.catalina.LifecycleException;
import org.apache.catalina.core.AprLifecycleListener;
import org.apache.catalina.core.StandardContext;
import org.apache.catalina.startup.Tomcat;
import javax.servlet.ServletException;
import java.io.File;
public class TomcatApplication {
public static int TOMCAT_PORT = 8080;
public static String TOMCAT_HOSTNAME = "127.0.0.1";
public static String WEBAPP_PATH = "src/main";
public static void main(String[] args) throws LifecycleException {
TomcatApplication.run();
}
public static void run() throws LifecycleException {
Tomcat tomcat = new Tomcat();
tomcat.setPort(TomcatApplication.TOMCAT_PORT);
tomcat.setHostname(TomcatApplication.TOMCAT_HOSTNAME);
tomcat.setBaseDir("."); // tomcat 信息保存在项目下
StandardContext myContext = null;
try {
myContext = (StandardContext) tomcat.addWebapp("/itxs", System.getProperty("user.dir") + File.separator + TomcatApplication.WEBAPP_PATH);
myContext.setReloadable(false);
// 上下文监听器
myContext.addLifecycleListener(new AprLifecycleListener());
// 注册servlet
tomcat.addServlet("/itxs", "myFirstServlet",new MyFirstServlet());
// servlet mapping
myContext.addServletMappingDecoded("/first.do", "myFirstServlet");
tomcat.start();
tomcat.getServer().await();
} catch (ServletException e) {
e.printStackTrace();
}
}
}
运行main方法
并访问http://127.0.0.1:8080/itxs/first.do,收到结果页面
源码编译
官方下载tomcat源码,目前最新稳定版本为10.0.12
#由于tomcat源码依赖jakartaee-migration模块,而jakartaee-migration未发布到maven repository,我们需要git clone到本地,再mvn install来部署解决tomcat源码的编译问题,https://github.com/apache/tomcat-jakartaee-migration
#解压文件,进入到tomcat-jakartaee-migration-main目录,地址栏上输入cmd进入命令行窗口并且自动进入当前目录
#执行maven安装到本地仓库
mvn clean install
#加压apache-tomcat-10.0.12-src.zip的文件,Tomcat源码并非maven项目结构,但可以通过pom指定java代码目录(无需按照src/main结构来),项目目录下创建pom.xml文件,内容如下:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.github.sources</groupId>
<artifactId>source-tomcat</artifactId>
<version>10.0-SNAPSHOT</version>
<name>source-tomcat</name>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.5.1</version>
</dependency>
<dependency>
<groupId>org.apache.ant</groupId>
<artifactId>ant</artifactId>
<version>1.10.1</version>
</dependency>
<dependency>
<groupId>wsdl4j</groupId>
<artifactId>wsdl4j</artifactId>
<version>1.6.2</version>
</dependency>
<dependency>
<groupId>javax.xml</groupId>
<artifactId>jaxrpc</artifactId>
<version>1.1</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt</groupId>
<artifactId>org.eclipse.jdt.core</artifactId>
<version>3.25.0</version>
</dependency>
<dependency>
<groupId>org.eclipse.jdt.core.compiler</groupId>
<artifactId>ecj</artifactId>
<version>4.6.1</version>
</dependency>
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>jakartaee-migration</artifactId>
<version>0.2.1-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>biz.aQute.bnd</groupId>
<artifactId>biz.aQute.bndlib</artifactId>
<version>5.2.0</version>
<scope>provided</scope>
</dependency>
</dependencies>
<build>
<finalName>Tomcat10.0</finalName>
<sourceDirectory>java</sourceDirectory>
<testSourceDirectory>test</testSourceDirectory>
<resources>
<resource>
<directory>java</directory>
</resource>
</resources>
<testResources>
<testResource>
<directory>test</directory>
</testResource>
</testResources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.6.1</version>
<configuration>
<encoding>UTF-8</encoding>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
#由于源码apache-tomcat-10.0.12的pom文件里的jakartaee-migration的版本为0.2.1-SNAPSHOT,我们改为上面tomcat-jakartaee-migration-main的项目的版本1.0.1-SNAPSHOT
#我们在JDTCompiler里注释下面三行源码, 不能会报没有 CompilerOptions.VERSION_16
// settings.put(CompilerOptions.OPTION_Source, CompilerOptions.VERSION_16);
// settings.put(CompilerOptions.OPTION_TargetPlatform, CompilerOptions.VERSION_16);
// settings.put(CompilerOptions.OPTION_Compliance, CompilerOptions.VERSION_16);
前面章节我们已提到tomcat main函数的入口在org.apache.catalina.startup.Bootstrap里,知道main函数
会遇到测试类的报错如下,可以尝试运行忽略测试类,或者直接删除maven compile时产生的test文件夹,我们这里直接删除test文件夹
由于目前tomcat启动找不到配置文件,因此我们在源码根目录下创建source文件夹,并将conf和webapps这两个目录转移到source文件夹中
然后在运行设置里添加如下vm参数
-Dcatalina.home=F:\develop\apache-tomcat-10.0.12-src\source
-Dcatalina.base=F:\develop\apache-tomcat-10.0.12-src\source
-Djava.util.logging.manager=org.apache.juli.ClassLoaderLogManager
-Djava.util.logging.config.file=F:\develop\apache-tomcat-10.0.12-src\source\conf\logging.properties
配置好指定的catalina.home和catalina.base以及日志相关jvm参数后,启动Tomcat,到这里,我们是可以启动tomcat程序,但是访问http://localhost:8080/ 会报500错误,启动Tomcat BootStrap时未加载JSP编译器JasperInitializer
#在org.apache.catalina.startup.ContextConfig#configureStart中
webConfig(); // 这句下面添加如下初始化语句
context.addServletContainerInitializer(new JasperInitializer(), null);
重新启动Tomcat,查看http://localhost:8080,出现tomcat的页面
性能调优
关于性能调优方面可以考虑一下几个:
- 内存:jvm参数,这个是实际生产中用的较多的。
- 并发优化:connector开启线程池及线程池优化;
- 缓存优化:connector 压缩和客户端连接超时;
- IO优化:protocol 选择BIO NIO NIO2(AIO);
- 组件优化:APR sendfile epoll openssl Tomcat native;
我们本篇只是简单理解tomcat架构和搭建tomcat源码调试环境,后续有时间我们再对tomcat源码和设计模式做进一步剖析和分享
从ApacheTomcat架构谈面试到源码编译环境v10.0.12的更多相关文章
- 源码编译安装MySQL8.0
源码编译安装MySQL8.0 0.前期准备条件 查看linux的版本 [root@mysql etc]# cat /etc/redhat-release CentOS Linux release 7. ...
- 【Android开发】构建Android源码编译环境
原文:http://android.eoe.cn/topic/android_sdk 构建Android源码编译环境 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 ...
- Spark记录-源码编译spark2.2.0(结合Hive on Spark/Hive on MR2/Spark on Yarn)
#spark2.2.0源码编译 #组件:mvn-3.3.9 jdk-1.8 #wget http://mirror.bit.edu.cn/apache/spark/spark-2.2.0/spark- ...
- ffmpeg源码编译环境搭建
ffmpeg是视频开发最常用到的开源软件,FFmpeg功能强大,用途广泛,提供几乎所有你能够想到的与视频开发相关的操作,许多商业软件都以ffmpeg为基础进行开发定制. FFmpeg: FFmpeg ...
- 源码编译安装MySQL8.0.20
1 概述 本文章主要讲述了如何从源码编译安装MySQL社区版8.0.20,首先会介绍一些编译安装的相关知识,然后开始编译安装 2 源码编译安装的相关知识 2.1 make与configure make ...
- hadoop源码编译——2.5.0版本
强迫症必治: WARN util.NativeCodeLoader: Unable to load native-hadoop library for your platform... using b ...
- android 5.0 (lollipop)源码编译环境搭建(Mac OS X)
硬件环境:MacBook Pro Retina, 13-inch, Late 2013 处理器 2.4 GHz Intel Core i5 内存 8 GB 1600 MHz DDR3 硬盘60G以 ...
- android源码编译环境的准备及编译之后使用emulator运行的方法 - 官方版
http://source.android.com/source/initializing.html http://blog.csdn.net/ithomer/article/details/6977 ...
- Android 源码编译环境搭建(64位Ubuntu)各种依赖包安装
1.准备: 普通PC(要求能上网), PC的操作系统Ubuntu 10.04 LTS(64位的),已经下载好的Android 1.6_r1的源代码. 2.Linux的依赖package安装: 为了更快 ...
随机推荐
- 更好的 java 重试框架 sisyphus 的 3 种使用方式
回顾 我们前面学习了 更好的 java 重试框架 sisyphus 入门简介 更好的 java 重试框架 sisyphus 配置的 2 种方式介绍 更好的 java 重试框架 sisyphus 背后的 ...
- I-Base62
I - Base62 PS:一个任意进制转换的大数问题 传送门:Base62 短除法原理: 20(10进制) => 202(3进制) 20 = (2 * 3 ^ 2 + 0 * 3 ^ 1 + ...
- k8s replicaset controller 分析(3)-expectations 机制分析
replicaset controller分析 replicaset controller简介 replicaset controller是kube-controller-manager组件中众多控制 ...
- Typora 快捷方式
1.标题编写 方法一:几个#号 代表几级标题 (共6级) 方法二:ctrl +1 .2.3.4.5.6 2.如何编写子标题 第一种:无序子标题(无序列表) *号 + 空格书写标题文本 (输入 ...
- docker+nginx搭建tomcat集群(附录)——nginx.conf文件
附录:nginx.conf修改后的文件内容 user root;worker_processes 2; #error_log logs/error.log;#error_log logs/error. ...
- SpringCloud微服务实战——搭建企业级开发框架(十五):集成Sentinel高可用流量管理框架【熔断降级】
Sentinel除了流量控制以外,对调用链路中不稳定的资源进行熔断降级也是保障高可用的重要措施之一.由于调用关系的复杂性,如果调用链路中的某个资源不稳定,最终会导致请求发生堆积.Sentinel ...
- ES6-变量的解构赋值复习+学习
ES6------变量的解构赋值 由于之前学过ES6的解构赋值,但是只是略看了一点网上的视频,所以今天就看了看ES6对这一部分的详细介绍,然后做一个总结的笔记. 首先,先大概说一下什么是变量的解构赋值 ...
- Web实时通信,SignalR真香,不用愁了
前言 对于B/S模式的项目,基础的场景都是客户端发起请求,服务端返回响应结果就结束了一次连接:但在很多实际应用场景中,这种简单的请求和响应模式就显得很吃力,比如消息通知.监控看板信息自动刷新等实时通信 ...
- Django 中间件 详细总结
一.什么是中间件 中间件顾名思义,是介于request与response处理之间的一道处理过程,相对比较轻量级,并且在全局上改变django的输入与输出.因为改变的是全局,所以需要谨慎实用,用不好会影 ...
- idea Mark Directory as 的几种文件类型
1. Source roots (or source folders) 源文件夹 通过为该类别分配文件夹,可以告诉IntelliJ IDEA该文件夹及其子文件夹包含应在构建过程中进行编译的源代码. 2 ...