java web dev知識積累

世有因果知因求果發表於2019-01-21

tomcat體系結構

可以從tomcat的server.xml檔案中元素的層次結構來理解tomcat的體系結構:

Server(可以視為tomcat本身)->經由connector可以有多個(coyote預設為Bio阻塞式io)處理socket分發->Service可以有多個(Catalina Container容器)(一般由catalina container來呼叫使用者的web app java程式碼)->一個engine->多個host虛擬主機->多個context(就是web app)

每個由host定義的虛擬主機中可以定義多個context(也就是web app或者說modules)

war打包部署:

jar cvf myapp.war webproject-directory

該命令將建立myapp.war部署檔案。

需要注意的是該檔案對於tomcat來說也是一個資料夾。只要訪問url到了/myapp,tomcat就會首先將myapp.war解壓,並且根據該war中的web.xml配置來定址url對應的class並且執行後返回結果

maven

maven是一個apache基金會開源的java構建,依賴管理的工具,類似C語言下的make,本身也是java寫的

maven的特點:

1. 約定優先,maven非常強烈地建議相應最佳實踐下的目錄結構

2. 內建提供了第三方依賴管理,支援自建自管倉庫,專案的依賴直接從這個倉庫中下載

3. 提供了一致的構建過程

4. 外掛式架構,大量的可用外掛完成我們的構建流程

5. 方便和IDE整合

maven安裝使用過程:

1. 下載http://mirror.bit.edu.cn/apache/maven/maven-3/3.6.0/binaries/apache-maven-3.6.0-bin.zip

2. 解壓,並且將對應bin目錄放到path環境變數中,配置環境變數M2_HOME=/path/to/maven

3. mvn -v確保正常輸出

由於國內訪問maven倉庫非常慢,阿里雲公益心做了對應的映象。

<mirror>
<id>nexus-aliyun</id>
<mirrorOf>*</mirrorOf>
<name>Nexus aliyun</name>
<url>http://maven.aliyun.com/nexus/content/groups/public</url>
</mirror>

maven的pom.xml(project object model)檔案

專案座標:

groupId,組織,比如com.example

artifactId,專案識別符號,比如mymodule,myproject等;

version, 版本,比如1.0.1-SNAPSHOT,這裡snapshot在maven構建時將被替換為timestamp

dependencies

這裡描述本專案的依賴

 

<dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>provided</scope>
    </dependency>
  </dependencies>

 

classpath

classpath用於連線java run time library和檔案系統。它定義編譯器和直譯器應該在何處去查詢要載入的.class檔案。其基本思想是:檔案系統的層次結構就反映了java包的層次結構,而classpath則定義了檔案系統中的哪些目錄可以作為java包層次結構的根(root)

https://www.ibm.com/developerworks/cn/java/j-classpath-windows/

請求轉發forward和重定向redirect

請求轉發是由servlet將當前的request和response交給另外的元件處理,最終由其他元件負責返回瀏覽器響應。對於瀏覽器來說,這是一次請求,一次響應。請求的轉發發生在服務端內部。瀏覽器位址列並不會改變;

RequestDispatcher(forward或者include(include是所有元件都可以輸出資訊))的獲取

通過HttpServletRequest獲取,通過ServletContext獲取

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        RequestDispatcher rd = req.getRequestDispatcher("/forwardExample");
        rd = this.getServletContext().getNamedDispatcher(
                "ServletForwardExample");
        rd = this.getServletContext().getRequestDispatcher("/forwardExample");
        rd.forward(req, resp);
    }

sendRedirect

通過response物件傳送給瀏覽器一個新的url地址,往往就是http location,瀏覽器自動跳轉

 

監聽器

監聽器分類

按照監聽器所監聽的物件可以分為:

監聽應用程式環境(ServletContext),又可以細緻分為ServletContextListener(建立和銷燬),ServletContextAttributeListener(物件屬性的CRUD),

監聽使用者請求物件(ServletRequest),也可以細緻分為:ServletRequestListener(建立和銷燬),ServletRequestAttributeListener(物件屬性的CRUD)

監聽使用者會話物件(HttpSession),也可以細緻分為HttpSessionListener(建立和銷燬),HttpSessionAttributeListener(物件屬性的CRUD),HttpSessionActivationListener監聽session持久化到磁碟,或者從磁碟恢復到記憶體的事件。

HttpSessionBindingListener: attribute方法呼叫或者removeAttribute方法呼叫時會觸發

監聽器,過濾器,Servlet的啟動順序

監聽器,過濾器或者Servlet的啟動順序首先取決於在部署描述符web.xml中定義的順序,按照其定義順序而順序建立的。

監聽器優先順序,高於過濾器,高於Servlet

servlet併發

servlet併發執行緒模型:

多個請求訪問同一個servlet時,由於被容器分別以多個worker執行緒來呼叫單例項servlet對應的service方法,因此在servlet的開發中,我們必須注意執行緒安全問題!!

servlet併發處理的特點:

1. 單例項,我們知道servlet的生命週期中只初始化建立一次,也就是單例項

2. 多執行緒,當多個使用者同時訪問同一個servlet時,對應的servlet的service方法或者get,post方法將在不同的worker thread中同時執行,也就是具有多執行緒執行模式;

3.執行緒不安全,也正是因為1,2兩個特點導致了servlet是執行緒不安全的。

如何做到servlet執行緒安全?

變數的執行緒安全:

1. 引數變數本地化,由於local變數並不暴露在不同的執行緒中,因此是執行緒安全的;

2. 對於需要同步訪問的執行緒不安全變數寫訪問時,必須加上synchronized鎖

屬性的執行緒安全:

1. ServletContext的屬性是執行緒不安全的

2. HttpSession理論上是執行緒安全的,但是如果同一個使用者在瀏覽器同一個程式中開啟多個tab也可能不安全;

3.ServletRequest是執行緒安全的,因為它是在每一次request時建立並供使用的資料

以下兩點需要注意:

1. 避免在Servlet中再建立新的執行緒,這將會導致程式異常複雜,容易出錯;

2. 多個Servlet需要訪問同一個外部物件時,必須加鎖處理

public class ConcurrentServlet extends HttpServlet {

    String name; // 儘量避免使用這類例項變數,因為這是執行緒不安全的,如果必須使用則必須加鎖

    /**
     * 
     */
    private static final long serialVersionUID = -6948878379930865229L;

    @Override
    public void init() throws ServletException {
        super.init();
    }

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp)
            throws ServletException, IOException {
        synchronized (this) {
            name = req.getParameter("username");
            PrintWriter out = resp.getWriter();
            try {
                Thread.sleep(5000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            out.println("username: " + name);
        }
    }

    @Override
    public void destroy() {
        super.destroy();
    }
}

 

相關文章