Java面試——Tomcat

優質博文:IT_BLOG_CN

一、Tomcat 頂層架構

img

Tomcat中最頂層的容器是Server,代表著整個服務器,從上圖中可以看出,一個Server可以包含至少一個Service,用于具體提供服務。Service主要包含兩個部分:ConnectorContainer。從上圖中可以看出Tomcat的心臟就是這兩個組件,他們的作用如下:
【1】Connector用于處理連接相關的事情,并提供SocketRequestResponse相關的轉化;
【2】Container用于封裝和管理Servlet,以及具體處理Request請求;

一個Tomcat中只有一個Server,一個Server可以包含多個Service,一個 Service只有一個Container,但是可以有多個Connectors,這是因為一個服務可以有多個連接,如同時提供HttpHttps鏈接,也可以提供向相同協議不同端口的連接,示意圖如下(EngineHostContext下邊會說到):
img

多個Connector和一個Container就形成了一個Service,有了Service就可以對外提供服務了,但是Service還要一個生存的環境,必須要有人能夠給她生命、掌握其生死大權,那就非Server莫屬了!所以整個Tomcat的生命周期由 Server控制。另外,上述的包含關系或者說是父子關系,都可以在tomcatconf目錄下的 server.xml 配置文件中看出。

二、簡要解釋下 server.xml 配置文件的信息

server.xmlTomcat中最重要的配置文件,server.xml的每個元素都對應了 Tomcat中的一個組件;通過對xml文件中元素的配置,可以實現對Tomcat中各個組件的控制。

<?xml version="1.0" encoding="UTF-8"?>
<Server port="8005" shutdown="SHUTDOWN"><Listener className="org.apache.catalina.startup.VersionLoggerListener"/><Listener SSLEngine="on" className="org.apache.catalina.core.AprLifecycleListener"/><Listener className="org.apache.catalina.core.JasperListener"/><Listener className="org.apache.catalina.core.JreMemoryLeakPreventionListener"/><Listener className="org.apache.catalina.mbeans.GlobalResourcesLifecycleListener"/><Listener className="org.apache.catalina.core.ThreadLocalLeakPreventionListener"/><GlobalNamingResources><Resource auth="Container" description="User database that can be updated and saved"  factory="org.apache.catalina.users.MemoryUserDatabaseFactory" name="UserDatabase" pathname="conf/tomcat-users.xml" type="org.apache.catalina.UserDatabase"/></GlobalNamingResources><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeOut="20000" redirectPort="8443"/><Connector port="8009" protocol="AJP/1.3" redirectPort="8443"/><Engine defaultHost="localhost" name="Catalina"><Realm className="org.apache.catalina.realm.LockOutRealm"><Realm className="org.apache.catalina.realm.UserDatabaseRealm" resourceName="UserDatabase"/></Realm><Host appBase="webapps" autoDeploy="true" name="localhost" unpackWARs="true"><Valve className="org.apache.catalina.valves.AccessLogValve" directory="logs" pattern="%h %l %u %t &quot;%r&quot; %s %b" prefix="localhost_access_log." suffix=".txt"/><Context docBase="cas-server-webapp" path="/cas" reloadable="true" source="org.eclipse.jst.j2ee.server:cas-server-webapp"/><Context docBase="portal" path="/portal" reloadable="true" source="org.eclipse.jst.jee.server:portal"/></Host></Engine></Service>
</Server>

server.xml的整體架構(簡潔版):

<Server><Service><Connector /><Connector /><Engine><Host><Context /><!-- 現在常常使用自動部署,不推薦配置Context元素,Context小節有詳細說明 --></Host></Engine></Service>
</Server>

【1】**頂層元素:**元素是整個配置文件的根元素,元素代表一個Engine元素以及一組與之相連的Connector元素。
【2】連接器: 代表了外部客戶端發送請求到特定Service的接口;同時也是外部客戶端從特定Service接收響應的接口。
【3】**容器:**容器的功能是處理Connector接收進來的請求,并產生對應的響應。Engine包含HostHost包含Context。一個 Engine組件可以處理Service中的所有請求,一個Host組件可以處理發向一個特定虛擬主機的所有請求,一個Context組件可以處理一個特定Web應用的所有請求。

三、Tomcat 都有哪些核心組件

【1】ServerServer元素在最頂層,代表整個 Tomcat容器,因此他必須是server.xml中唯一一個最外層的元素。一個Server元素可以有一個或多個Service元素。

<Server port="8005" shutdown="SHUTDOWN">
</Server>

可以看到,最外層有一個 元素,shutdown屬性表示關閉Server的指令;port屬性表示Server接收shutdown指令的端口號,設置為-1可以禁掉該端口。Server 的主要任務,就是提供一個接口讓客戶端能夠訪問到這個 Service集合,同時維護它所包含的所有的 Service的生命周期,包含如何初始化,如何結束服務,如何找到客戶端要訪問的 Service。
【2】**Service:**在ConnectorEngine外面包一層,把它們組合在一起,對外提供服務。一個Service可以包含多個Connector,但是只能包含一個Engine;其中Connector的作用是從客戶端接收請求,Engine的作用是處理接收進來的請求。

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"></Service>
</Server>

如上圖,Server中包含一個名稱為CatalinaService。實際上,Tomcat可以提供多個Service,不同的Service監聽不同的端口。
【3】**Connector:**接收連接請求,創建RequestResponse對象用于和請求端交換數據;然后分配線程讓Engine來處理這個請求,并把產生的RequestResponse對象傳給Engine。通過配置 Connector,可以控制請求 Service的協議及端口號。

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /></Service>
</Server>

通過配置第一個Connector,客戶端可以通過8080端口號協議訪問Tomcat。其中,protocol屬性規定了請求的協議,port規定了請求的端口號,redirectPort表示當強制要求https而請求是 http時,重定向至端口號為8443ConnectorconnectionTimeout表示連接的超時時間。

在這個例子中,Tomcat監聽Http請求,使用的是8080端口,而不是正式的 80端口;實際上,在正式的生產環境中,Tomcat也常常監聽8080端口。而不是80端口。這是因為在生產環境中,很少講Tomcat直接對外開放接收請求,而是在Tomcat和客戶端之間加一層代理服務器(如Nginx),用于請求的轉發、負載均衡、處理靜態文件等;通過代理服務器訪問Tomcat時,是在局域網中,因為一般仍使用8080端口。

第二個配置Connector,客戶端可以通過8009端口使用AJP協議訪問 TomcatAJP協議負責和其他的Http服務器(如Apache)建立連接;在把 Tomcat與其他服務器集成時,就需要用到這個連接器,之所以使用 Tomcat和其他服務器集成,是因為Tomcat可以用作Servlet/JSP容器,但是對靜態資源處理速度較慢,不如ApacheIISHTTP服務器;因此常常將 TomcatApache等集成,前者做Servlet容器,后者處理靜態資源,而AJP協議便負責TomcatApache的連接。TomcatApache等集成的原理如下圖:
img
【4】**Engine:**Engine 組件在Service組件有且只有一個;EngineService組件中的請求處理組件。Engine組件從一個或多個Connector中接收并處理,并將完成的響應返回給Connector,最終傳遞給客戶端。前面說到,EngineHostContext都是容器,但是它們不是平行關系,而是父子關系:Engine包含HostHost包含Context

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><Engine name="Catalina" defaultHost="localhost"></Engine></Service>
</Server>

其中name屬性用于日志和錯誤信息,在整個Server中應該是唯一的。defalutHost屬性指定了默認的host名稱,當發往本機的請求指定的host名稱不存在時,一律使用defaultHost指定的host進行處理;因此defaulthost的值,必須與Engine中的一個Host組件的name屬性值匹配。
【5】EngineHostHostEngine的子容器。Engine組件中可以內嵌1個或者多個Host組件,每個Host組件代表Engine中的一個虛擬主機。Host組件至少有一個,且其中一個的name必須與 Engine組件中的defaultHost屬性相匹配。
【6】Host的作用:Host虛擬主機的作用,是運行多個Web應用(一個Context代表一個Web應用),并負責安裝、展開、啟動、結束每個Web應用。Host組件代表的虛擬主機,對應服務器中一個網絡名實體(如www.test.com](https://links.jianshu.com/go?to=http%3A%2F%2Fwww.test.com)"或IP地址"116.25.25.25);為了使用戶可以通過網絡名連接Tomcat服務器,這個名字應該在DNS服務器上注冊。

客戶端通常使用主機名來標識它們希望連接的服務器,該主機名也會包含在 HTTP請求頭中,TomcatHTTP頭中提取出主機名,尋找名字匹配的主機。如果沒有匹配,請求會發送至默認的主機。因此默認主機不需要再DNS服務器中注冊網絡名,因為任何與所有Host名稱不匹配的請求,都會路由至默認主機。
【7】Host的配置:name屬性指定虛擬主機的主機名,一個Engine有且只有一個Host組件的name屬性和Engine組件的 defaultHost屬性相匹配;一般情況下,主機名需要是在DNS服務器中注冊網絡名,但是Engine指定的defaultHost不需要。

<Server port="8005" shutdown="SHUTDOWN"><Service name="Catalina"><Connector port="8080" protocol="HTTP/1.1" connectionTimeout="20000" redirectPort="8443" /><Connector port="8009" protocol="AJP/1.3" redirectPort="8443" /><Engine name="Catalina" defaultHost="localhost"><Host name="localhost" appBase="webapps" unpackWARs="true" autoDeploy="true"></Host></Engine></Service>
</Server>

unpackWARs指定了是否將代表Web應用的WAR文件解壓;如果是true,通過解壓后的文件結構運行該Web應用,如果是false,直接使用WAR文件運行Web應用。
【8】ContextContext元素代表在虛擬主機上運行的一個Web應用。在后文中,提到Context、應用或Web應用,他們都代指Web應用,每個Web應用基于WAR文件,或WAR文件解壓后對應的目錄(這里稱為應用目錄)ContextHost的子容器,每個Host都可以定義任意多的Context元素。元素的配置:Context元素最重要的屬性是 docBasepath,此外reloadable屬性也比較常用。

docBase指定了該Web應用使用war包路徑,或應用目錄。需要注意的是:在自動部署場景下(配置文件位于xmlBase中),docBase不在appBase目錄中,才需要指定;如果docBase指定的war包或應用目錄就在appBase中,則不需要指定。因為Tomcat會自動掃描appBase中的war包和應用目錄,制定了反而造成問題。

path指定了訪問該Web應用上下文路徑,當請求到來時,Tomcat根據Web應用的path屬性與 URL匹配程度來選擇Web應用處理相應請求。例如:Web 應用app1path屬性是/app1Web應用app2path屬性是"/app2",那么請求/app1/index.html會交由app1來處理;而請求/app2/index.html會交由 app2來處理。如果一個Context元素的path屬性為"",那么這個Context是虛擬主機的默認的Web應用;當請求的uri與所有的path都不匹配時,使用該默認Web應用來處理。

但是,需要注意的是,在自動部署場景(配置文件位于xmlBase中),不能指定path屬性,path屬性由配置的文件的文件名,WAR文件的文件名或應用目錄的名稱自動推導出來。如掃描Web應該時,發現xmlBase目錄下的app1.xml,或appBase目錄下的app1.WARapp1應用目錄,則該Web用于的path屬性是app1。如果名稱不是app1而是ROOT,則該Web應用時虛擬主機默認的Web應用,此時path屬性推導為""。

reloadable屬性指示tomcat是否在運行時監控在WEB-INF/classesWEB-INF/lib目錄下class文件的改動。如果值為true,那么當class文件改動時,會重新web應用的重新加載。在開發環境下,reloadable設置為ture便于調試;但是在生產環境中設置為true會給服務器帶來性能壓力,因此reloadable參數的默認值為false。在該例子中,docBase位于HostappBase目錄之外;path屬性沒有指定,而是根據app1.xml自動推導為app1

<Context docBase="D:Program Filesapp1.war" reloadable="true"></Context>

若是自動部署(即autoDeploy="true"),那么server.xml配置文件中沒有Context元素的配置。這是因為Tomcat開啟了自動部署,Web應用沒有在 server.xml中配置靜態部署,而是由Tomcat通過特定的規則自動部署。

四、Web 的自動部署

要開啟Web應用的自動部署,需要配置所在的虛擬主機;配置的方式就是在配置Host元素的 deployOnStartupautoDeploy屬性。如果deployOnStartupautoDeploy設置為true,則tomcat啟動自動部署:當檢測到新的Web應用或Web應用更新時,會觸發應用的部署(或重新部署)。

二者的主要區別在于
【1】deployeOnStartuptrue時,Tomcat在啟動時檢查Web應用,且檢測到所有的Web應用都試做新應用;
【2】autoDeploytrue時,Tomcat在運行時定期檢查新的Web應用或Web應用的更新;

通過配置deployOnStartupautoDeploy可以開啟虛擬主機自動部署Web應用;實際上,自動部署依賴于檢查是否有新的或更改過的Web應用,而Host元素中的appBasexml配置設置了檢查Web應用更新的目錄。

其中,appBase屬性指定Web應用所在的目錄,默認值是webapps,這是一個相對路徑,代表 Tomcat根目錄下的webapps文件夾。xmlBase屬性指定Web應用的XML配置文件所在的目錄,默認值為conf/<engine_name><engine_name>,例如上面例子中,主機localhostxmlBase的默認值是$TOMCAT_HOME/conf/Catalina/localhost

五、appBase 和 docBase的區別

【1】**appBase這個目錄下面的子目錄將自動被部署為應用,且war文件將被自動解壓縮并部署為應用,默認為tomcatwebapps目錄。
【2】
docBase:**指定需要關聯的項目自動解壓并部署到appBase目錄下。項目的名稱由path屬性決定。
先部署 需要注意,docBase所在的文件或者war包必須存在。否則項目啟動找不到對應的目錄。此時文件解壓到appBase目錄下,根據path屬性,決定解壓后的文件名。
若采用了<Host name="localhost" appBase="webapp" autoDeploy="true"> 配置,那么appBase目錄下的應用目錄將會再次部署。此時項目是部署了兩遍。解決辦法,設置autoDeploy="false"

六、Tomcat 頂層架構小結

【1】Tomcat中只有一個Server,一個Server可以有多個Service,一個Service可以有多個 Connector和一個Container
【2】Server掌管著整個Tomcat的生死大權;
【3】Service是對外提供服務的;
【4】Connector用于接受請求并將請求封裝成RequestResponse來具體處理;
【5】Container用于封裝和管理Servlet,以及具體處理Request請求;

知道了整個Tomcat頂層的分層架構和各個組件之間的關系以及作用,對于絕大多數的開發人員來說 ServerService對我們來說確實很遠,而我們開發中絕大部分進行配置的內容是屬于ConnectorContainer的,所以接下來介紹一下ConnectorContainer

七、Connector 和 Container的微妙關系

由上述內容我們大致可以知道一個請求發送到Tomcat之后,首先經過Service然后會交給我們的 ConnectorConnector用于接收請求并將接收的請求封裝為RequestResponse來具體處理,RequestResponse封裝完之后再交由Container進行處理,Container處理完請求之后再返回給 Connector,最后在由Connector通過Socket將處理的結果返回給客戶端,這樣整個請求的就處理完了!

Connector最底層使用的是Socket來進行連接的,RequestResponse是按照HTTP協議來封裝的,所以Connector同時需要實現TCP/IP協議和HTTP協議。Tomcat既然處理請求,那么肯定需要先接收到這個請求,接收請求這個東西我們首先就需要看一下Connector

八、Container 架構分析

Container用于封裝和管理Servlet,以及具體處理Request請求,在Connector內部包含了4個子容器,結構圖如下:
img
4個子容器的作用分別是:
【1】Engine:引擎,用來管理多個站點,一個Service最多只能有一個Engine
【2】Host:代表一個站點,也可以叫虛擬主機,通過配置Host就可以添加站點;
【3】Context:代表一個應用程序,對應著平時開發的一套程序,或者一個WEB-INF目錄以及下面的web.xml文件;
【4】Wrapper:每一Wrapper封裝著一個Servlet

下面找一個Tomcat的文件目錄對照一下,如下圖所示:
img

ContextHost的區別是Context表示一個應用,我們的Tomcat中默認的配置下webapps下的每一個文件夾目錄都是一個Context,其中ROOT目錄中存放著主應用,其他目錄存放著子應用,而整個 webapps就是一個 Host站點。我們訪問應用Context的時候,如果是ROOT下的則直接使用域名就可以訪問,例如:www.ledouit.com,如果是Host(webapps)下的其他應用,則可以使用 www.ledouit.com/docs 進行訪問,當然默認指定的根應用ROOT是可以進行設定的,只不過Host站點下默認的主營用是ROOT目錄下的。

看到這里我們知道Container是什么,但是還是不知道Container是如何進行處理的以及處理完之后是如何將處理完的結果返回給Connector的。

十、Container 如何處理請求的

Container處理請求是使用Pipeline-Valve管道來處理的!(Valve是閥門之意)Pipeline-Valve是責任鏈模式,責任鏈模式是指在一個請求處理的過程中有很多處理者依次對請求進行處理,每個處理者負責做自己相應的處理,處理完之后將處理后的請求返回,再讓下一個處理著繼續處理。
img

但是!Pipeline-Valve使用的責任鏈模式和普通的責任鏈模式有些不同!區別主要有以下兩點:
【1】每個Pipeline都有特定的Valve,而且是在管道的最后一個執行,這個Valve叫做BaseValveBaseValve是不可刪除的;
【2】在上層容器的管道的BaseValve中會調用下層容器的管道。

我們知道Container包含四個子容器,而這四個子容器對應的BaseValve分別在:StandardEngineValveStandardHostValveStandardContextValveStandardWrapperValvePipeline的處理流程圖如下:
img

【1】Connector在接收到請求后會首先調用最頂層容器的Pipeline來處理,這里的最頂層容器的 Pipeline就是EnginePipelineEngine的管道);
【2】在Engine的管道中依次會執行EngineValve1EngineValve2等等,最后會執行 StandardEngineValve,在StandardEngineValve中會調用Host管道,然后再依次執行HostHostValve1HostValve2等,最后在執行StandardHostValve,然后再依次調用Context的管道和 Wrapper的管道,最后執行到StandardWrapperValve
【3】當執行到StandardWrapperValve的時候,會在StandardWrapperValve中創建FilterChain,并調用其 doFilter方法來處理請求,這個FilterChain包含著我們配置的與請求相匹配的FilterServlet,其 doFilter方法會依次調用所有的FilterdoFilter方法和Servletservice方法,這樣請求就得到了處理!
【4】當所有的Pipeline-Valve都執行完之后,并且處理完了具體的請求,這個時候就可以將返回的結果交給Connector了,Connector在通過Socket的方式將結果返回給客戶端。

十一、tomcat 容器是如何創建 servlet類實例?用到了什么原理?

當容器啟動時,會讀取在webapps目錄下所有的web應用中的web.xml文件,然后對xml文件進行解析,并讀取servlet注冊信息。然后,將每個應用中注冊的servlet類都進行加載,并通過反射的方式實例化。(有時候也是在第一次請求時實例化)在servlet注冊時加上如果為正數,則在一開始就實例化,如果不寫或為負數,則第一次請求實例化。

十二、共享 session處理

目前的處理方式有如下幾種:
【1】使用Tomcat本身的Session復制功能。參考http://ajita.iteye.com/blog/1715312Session復制的配置)方案的有點是配置簡單,缺點是當集群數量較多時,Session復制的時間會比較長,影響響應的效率;
【2】使用第三方來存放共享Session:目前用的較多的是使用memcached來管理共享Session,借助于memcached-sesson-manager來進行TomcatSession管理。參考http://ajita.iteye.com/blog/1716320(使用MSM管理Tomcat集群session
【3】使用黏性session的策略:對于會話要求不太強(不涉及到計費,失敗了允許重新請求下等)的場合,同一個用戶的session可以由nginx或者apache交給同一個Tomcat來處理,這就是所謂的 session sticky策略,目前應用也比較多。參考:http://ajita.iteye.com/blog/1848665(tomcat session sticky)Nginx默認不包含session sticky模塊,需要重新編譯才行(windows下我也不知道怎么重新編譯)優點是處理效率高多了,缺點是強會話要求的場合不合適。

十三、關于 Tomcat 的 session數目

這個可以直接從Tomcatweb管理界面去查看即可,或者借助于第三方工具Lambda Probe來查看,它相對于Tomcat自帶的管理稍微多了點功能,但也不多 ;

十四、Tomcat 一個請求的完整過程

首先DNS解析機器,一般是ng服務器ip地址,然后ng根據server的配置,尋找路徑為yy/的機器列表,ip和端口。最后 選擇其中一臺機器進行訪問。下面為詳細過程:
【1】請求被發送到本機端口8080,被在那里偵聽的Coyote HTTP/1.1 Connector獲得;
【2】Connector把該請求交給它所在的ServiceEngine來處理,并等待來自Engine的回應;
【3】Engine獲得請求localhost/yy/index.jsp,匹配它所擁有的所有虛擬主機Host
【4】Engine匹配到名為 localhost 的 Host(即使匹配不到也把請求交給該 Host處理,因為該Host被定義為該 Engine的默認主機);
【5】localhost Host獲得請求/yy/index.jsp,匹配它所擁有的所有Context
【6】Host匹配到路徑為/yyContext(如果匹配不到就把該請求交給路徑名為”“的Context去處理);
【7】path=”/yy”Context獲得請求/index.jsp,在它的mapping table中尋找對應的servlet
【8】Context匹配到URL PATTERN*.jspservlet,對應于JspServlet類;
【9】構造HttpServletRequest對象和HttpServletResponse對象,作為參數調用JspServletdoGetdoPost方法;
【10】Context把執行完了之后的HttpServletResponse對象返回給Host
【11】HostHttpServletResponse對象返回給Engine
【12】EngineHttpServletResponse對象返回給Connector
【13】ConnectorHttpServletResponse對象返回給客戶browser

十五、Tomcat 工作模式

Tomcat是一個JSP/Servlet容器。其作為Servlet容器,有三種工作模式:獨立的Servlet容器、進程內的Servlet容器和進程外的Servlet容器。進入Tomcat的請求可以根據Tomcat的工作模式分為如下兩類:
【1】Tomcat作為應用程序服務器:請求來自于前端的web服務器,這可能是Apache, IIS, Nginx等;
【2】Tomcat作為獨立服務器:請求來自于web瀏覽器;

Tomcat的工作一般分為三種:
【1】bio 傳統的Java I/O操作,同步且阻塞I/O,一個線程處理一個請求,并發量高時,線程數較多,浪費資源;(已經很少有人在使用)
【2】nio JDK1.4開始支持,同步阻塞或同步非阻塞IO,可以通過少量的線程來處理大量的請求;(從Tomcat 8版本開始默認就是這種模式)
【3】aprJNI的形式調用Apache HTTP服務器的核心動態鏈接庫來處理文件讀取或網絡傳輸操作,從而大大地提高Tomcat對靜態文件的處理性能;(企業中使用較多)

十六、如何對 Tomcat 進行優化

【1】關閉Manager管理頁面;(默認已經關閉)
【2】關閉host-mangent管理頁面;(默認已經關閉)
【3】對Tomcat日志進行分割;
【4】定義Tomcat 404錯誤返回的頁面;
【5】對JVM進行優化;
【6】對Tomcat線程池進行優化;

十七、如何對 Tomcat 進行優化

【1】關閉Manager管理頁面;(默認已經關閉)
【2】關閉host-mangent管理頁面;(默認已經關閉)
【3】對Tomcat日志進行分割;
【4】定義Tomcat 404錯誤返回的頁面;
【5】對JVM進行優化;
【6】對Tomcat線程池進行優化;
【7】更改Tomcat的工作的模式;

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/diannao/70545.shtml
繁體地址,請注明出處:http://hk.pswp.cn/diannao/70545.shtml
英文地址,請注明出處:http://en.pswp.cn/diannao/70545.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

第4章 信息系統架構(三)

4.3 應用架構 應用架構的主要內容是規劃出目標應用分層分域架構&#xff0c;根據業務架構規劃目標應用域、應用組和目標應用組件&#xff0c;形成目標應用架構邏輯視圖和系統視圖。從功能視角出發&#xff0c;闡述應用組件各自及應用架構整體上&#xff0c;如何實現組織的高階…

python小項目編程-中級(1、圖像處理)

目錄 圖像處理 實現 測試 unittest pytest 圖像處理 實現界面化操作&#xff0c;使用PIL庫實現簡單的圖像處理功能&#xff0c;如縮放&#xff08;設置縮放比例&#xff09;、旋轉和濾鏡、對比度調整、亮度調整、灰度圖、二值化圖&#xff08;二值圖如果使用的是彩色圖片需…

【Leetcode 每日一題】2209. 用地毯覆蓋后的最少白色磚塊

問題背景 給你一個下標從 0 0 0 開始的 二進制 字符串 f l o o r floor floor&#xff0c;它表示地板上磚塊的顏色。 f l o o r [ i ] floor[i] floor[i] 為 ‘0’ 表示地板上第 i i i 塊磚塊的顏色是 黑色 。 f l o o r [ i ] floor[i] floor[i] 為’1’ 表示地板上第 i …

Docker 性能優化指南

Docker 提供了強大的容器化功能&#xff0c;能夠幫助開發者在不同的環境中構建、測試和部署應用。然而&#xff0c;隨著容器化應用的不斷增長&#xff0c;Docker 容器可能會面臨一些性能瓶頸&#xff0c;影響其運行效率、資源占用和擴展能力。為了確保容器在生產環境中的高效運…

2025 WE DAY品牌日| 天璇II WE X7 Pro充電樁震撼發布,能效電氣開啟充電革命

隨著新能源產業的迅猛發展,充電樁作為電動汽車能量補給的重要基礎設施,正在成為市場關注的焦點。能效電氣作為充電樁領域的佼佼者,專注于研發高效、智能的充電解決方案,為電動汽車的普及與可持續發展鋪設了堅實的基礎。 2025年2月21日,能效電氣在深圳盛大舉辦了以“以創新 引未…

< OS 有關 > Ubuntu 24 SSH 服務器更換端口 in jp/us VPSs

原因&#xff1a; 兩臺 VPS 的 ssh 端口一直被密碼重試&#xff0c; us 這臺已經封了 632, jp 這臺兩周前清過一次 sqlite3 數據&#xff0c;現在贊到 1008 Fail2Ban 是使用 sqlite3 來記錄&#xff0c;數據量大后&#xff0c;硬盤的 I/O 會飆升&#xff0c;我有寫過一個 app…

MATLAB學習之旅:數據插值與曲線擬合

在MATLAB的奇妙世界里,我們已經走過了一段又一段的學習旅程。從基礎的語法和數據處理,到如今,我們即將踏入數據插值與曲線擬合這片充滿魅力的領域。這個領域就像是魔法中的藝術創作,能夠讓我們根據現有的數據點,構建出更加豐富的曲線和曲面,從而更好地理解和描述數據背后…

若依-@Excel新增注解numberFormat

Excel注解中原本的scale會四舍五入小數&#xff0c;導致進度丟失 想要的效果 顯示的時候保留兩個小數真正的數值是保留之前的數值 還原過程 若以中有一個專門的工具類&#xff0c;用來處理excel的 找到EXCEL導出方法exportExcel()找到writeSheet,寫表格的方法找到填充數據的方法…

LeetCode 熱題 100_搜索二維矩陣(64_74_中等_C++)(二分查找)(暴力破解法;Z字形查找;一次二分查找)

LeetCode 熱題 100_搜索二維矩陣&#xff08;64_74&#xff09; 題目描述&#xff1a;輸入輸出樣例&#xff1a;題解&#xff1a;解題思路&#xff1a;思路一&#xff08;暴力破解法&#xff09;&#xff1a;思路二&#xff08;Z字形查找&#xff09;&#xff1a;思路三&#x…

從CNN到Transformer:遙感影像目標檢測的技術演進(礦產勘探、精準農業、城市規劃、林業測量、軍事目標識別和災害評估等)

在遙感影像分析領域&#xff0c;目標檢測一直是研究熱點之一。隨著高分辨率對地觀測系統的不斷發展&#xff0c;遙感影像的分辨率和數據量呈爆發式增長&#xff0c;如何高效、準確地從海量數據中提取有用信息&#xff0c;成為了一個亟待解決的問題。近年來&#xff0c;深度學習…

【rt-thread】rt-thread 控制 led 的兩種方式

1. pin設備 #define LED_PIN 3int led(void) {rt_uint8_t count;rt_pin_mode(LED_PIN, PIN_MODE_OUTPUT); for(count 0 ; count < 10 ;count){ rt_pin_write(LED_PIN, PIN_HIGH);rt_kprintf("led on, count : %d %d\r\n", count, rt_pin_read(LED_PIN));…

Excell 代碼處理

文章目錄 Excell 代碼處理cvc格式xlsl格式小結 Excell 代碼處理 有時候要對excell進行分析&#xff0c;或者數據的導入導出&#xff0c;這個時候如果可以用代碼讀寫分析操作那么會方便很多 cvc格式 CSV&#xff08;Comma-Separated Values&#xff0c;逗號分隔值&#xff09;是…

新手小白如何挖掘cnvd通用漏洞之存儲xss漏洞(利用xss釣魚)

視頻教程和更多福利在我主頁簡介或專欄里 &#xff08;不懂都可以來問我 專欄找我哦&#xff09; 如果對你有幫助你可以來專欄找我&#xff0c;我可以無償分享給你對你更有幫助的一些經驗和資料哦 目錄&#xff1a; 一、XSS的三種類型&#xff1a; 二、XSS攻擊的危害&#x…

代碼隨想錄算法【Day52】

Day51 101. 孤島的總面積 思路 從周邊找到陸地然后 通過 dfs或者bfs 將周邊靠陸地且相鄰的陸地都變成海洋&#xff0c;然后再去重新遍歷地圖 統計此時還剩下的陸地 代碼 #include <iostream> #include <vector> using namespace std; int dir[4][2] {-1, 0, …

Python開源項目月排行 2024年12月

#2024年12月2025年1月21日1DeepSeek-Coder-V2一個開源的專家混合&#xff08;MoE&#xff09;代碼語言模型&#xff0c;其在代碼特定任務中的性能可與GPT4-Turbo相媲美。具體而言&#xff0c;DeepSeek-Coder-V2是在DeepSeek-V2的一個中間檢查點上進一步預訓練的&#xff0c;增加…

Resource not found: roslaunchROS path [0]=/opt/ros/noetic/share/ros

解決辦法&#xff1b; cd ~/catkin_ws rm -rf build/ devel/ catkin_make source devel/setup.bash sudo apt-get install ros-noetic-roslaunch 輸入roscore后

.NET + Vue3 的前后端項目在IIS的發布

目錄 一、發布準備 1、安裝 IIS 2、安裝 Windows Hosting Bundle&#xff08;.NET Core 托管捆綁包&#xff09; 3、安裝 IIS URL Rewrite 二、項目發布 1、后端項目發布 2、前端項目發布 3、將項目部署到 IIS中 三、網站配置 1、IP配置 2、防火墻配置 3、跨域配置…

指定定網卡名稱

一、PCIe網卡名稱指定 原理&#xff1a;利用udev規則匹配PCIe設備的硬件特征&#xff08;如總線位置、MAC地址等&#xff09;&#xff0c;覆蓋默認命名規則 4 。 步驟&#xff1a; 獲取設備信息&#xff1a; Bash udevadm info -a -p /sys/class/net/<原設備名> # 如e…

【python】解析自動化腳本文件并按照=測試周期=存儲記錄

【python】連接Jira獲取token以及jira對象 【python】解析自動化腳本文件并按照測試周期存儲記錄 【python】向Jira推送自動化用例執行成功 【python】向Jira測試計劃下&#xff0c;附件中增加html測試報告 將已編寫的自動化測試用例按照jira號解析出來&#xff0c;并按照測試計…

Linux驅動開發之音頻驅動與基礎應用編程

目錄 CODEC芯片 音頻編碼 I2S總線接口 數字音頻接口(DAI) 設備樹配置 ALSA 音頻相關概念 應用程序編寫 運行測試 CODEC芯片 音頻若想被CPU“聽到”&#xff0c;就必須轉換為CPU能夠“聽懂”的語言&#xff0c;即二進制數據的0和1。在信號處理領域&#xff0c;聲音是模…