国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

TOMCAT源碼閱讀總結(1)-TOMCAT的類加載體系

ChanceWong / 1246人閱讀

摘要:加載器之間父子關系不是通過類繼承的方式,而是通過對象變量的方式,來實現的。調用的方法,將設置為所有的獲取各個類加載器相應的資源配置文件這些是具體配置在配置文件中的。

摘要

一直以來想看一下tomcat的源碼,可以從頭到尾理解一遍在整個web請求的處理過程中,容器完成的功能,容器怎么把一個url的請求的處理遞交給了servlet,容器的pipeline是怎么設計的,容器的filter怎么實現的,如何維護session,好多好多的問題,有幸發現一篇文章Tomcat7.0源碼分析,讓我得以窺見容器的內部實現,從源碼之中能按著作者的思路來理解和閱讀。讀完之后,有了一些理解,但是不是很深刻,借著這個機會,寫了這篇總結,溫故而知新。讀源代碼,就是要反復得讀,每次讀完都會先釋然,又會產生新的疑惑,再帶著問題重讀源碼,如此反復,脈絡才會越來越清晰。
整個文章按如下幾個主題:

tomcat的類加載體系

server.xml文件的加載與解析

生命周期管理

停止與啟動服務

請求原理分析

session管理分析

TOMCAT的類加載體系

Tomcat為了webapp之間以及app和容器之間的資源(jar包)隔離,是通過自定義類加載器的方式來實現的。首先我們看一下jdk的類加載器結構樹(為了方便起見,將tomcat自定義的類加載器也放上去了)

這個粗看會有一點困惑,jdk不是父親委派加載機制嗎?為什么這里的AppClassLoader,ExtClassLoad不是繼承關系呢?其實這是一個誤解。加載器之間父子關系不是通過類繼承的方式,而是通過對象變量的方式,來實現的。

private ClassLoader(Void unused, ClassLoader parent) {
     this.parent = parent; 

然后在加載類的時候,會嘗試先讓parent來加載

protected Class loadClass(String name, boolean resolve)
    throws ClassNotFoundException
{
    synchronized (getClassLoadingLock(name)) {
        // First, check if the class has already been loaded
        Class c = findLoadedClass(name);
        if (c == null) {
            long t0 = System.nanoTime();
            try {
                if (parent != null) {
                    c = parent.loadClass(name, false);
                } else {
                    c = findBootstrapClassOrNull(name);
                }

這個就是父親委托加載機制的由來。之前找不到JDK的ExtClassLoader和AppClassLoader,后來才發現這兩個類原來是rt.jar包sum.msic.Launcher的內部類. Bootstrap加載sum.boot.class.path下的類,ExtClassPath加載java.ext.dirs下的類,AppClassLoader加載java.class.path下的類。當然也可以在運行時通過參數( -XBootclasspath , -Djava.ext.dirs , -cp)分別指定。

好了,現在讓我們回到tomcat的類加載器上來,看類樹上,tomcat自定義了WebappClassLoader和standardClassLoader,簡單的看,前者是給web應用用的,后者是給tomcat容器本身用的。我們通過原來來進行分析。

Bootstrap.java

public void init()
    throws Exception
{

      // Set Catalina path
      setCatalinaHome();
      setCatalinaBase();

      initClassLoaders();

      Thread.currentThread().setContextClassLoader(catalinaLoader);
      SecurityClassLoad.securityClassLoad(catalinaLoader);
// Load our startup class and call its process() method
if (log.isDebugEnabled())
    log.debug("Loading startup class");
//調用Catalina的setParentClassLoader方法,將sharedLoader設置為所有WebappClassLoader的parent
Class startupClass =
    catalinaLoader.loadClass
    ("org.apache.catalina.startup.Catalina");
Object startupInstance = startupClass.newInstance();

// Set the shared extensions class loader
if (log.isDebugEnabled())
    log.debug("Setting startup class properties");
String methodName = "setParentClassLoader";
Class paramTypes[] = new Class[1];
paramTypes[0] = Class.forName("java.lang.ClassLoader");
Object paramValues[] = new Object[1];
paramValues[0] = sharedLoader;
Method method =
    startupInstance.getClass().getMethod(methodName, paramTypes);
method.invoke(startupInstance, paramValues);

catalinaDaemon = startupInstance;
     
}


private void initClassLoaders() {
        try {
            commonLoader = createClassLoader("common", null);
            if( commonLoader == null ) {
                // no config file, default to this loader - we might be in a "single" env.
                commonLoader=this.getClass().getClassLoader();
            }
            catalinaLoader = createClassLoader("server", commonLoader);
            sharedLoader = createClassLoader("shared", commonLoader);
        } catch (Throwable t) {
            log.error("Class loader creation threw exception", t);
            System.exit(1);
        }
    }

private ClassLoader createClassLoader(String name, ClassLoader parent)
    throws Exception {
     //獲取各個類加載器相應的資源配置文件(common.loader,server.loader,shared.loader)
     //這些是具體配置在catalina.properties配置文件中的。以本機配置為例
     //common.loader=${catalina.base}/lib,${catalina.base}/lib/*.jar,${catalina.home}/lib,${catalina.home}/lib/*.jar
     //server.loader=
     //shared.loader=
     
    String value = CatalinaProperties.getProperty(name + ".loader");
    if ((value == null) || (value.equals("")))
        return parent;

    ArrayList repositoryLocations = new ArrayList();
    ArrayList repositoryTypes = new ArrayList();
    int i;

    StringTokenizer tokenizer = new StringTokenizer(value, ",");
    while (tokenizer.hasMoreElements()) {
        String repository = tokenizer.nextToken();

        // Local repository
        boolean replace = false;
        String before = repository;
        while ((i=repository.indexOf(CATALINA_HOME_TOKEN))>=0) {
            replace=true;
            if (i>0) {
            repository = repository.substring(0,i) + getCatalinaHome()
                + repository.substring(i+CATALINA_HOME_TOKEN.length());
            } else {
                repository = getCatalinaHome()
                    + repository.substring(CATALINA_HOME_TOKEN.length());
            }
        }
        while ((i=repository.indexOf(CATALINA_BASE_TOKEN))>=0) {
            replace=true;
            if (i>0) {
            repository = repository.substring(0,i) + getCatalinaBase()
                + repository.substring(i+CATALINA_BASE_TOKEN.length());
            } else {
                repository = getCatalinaBase()
                    + repository.substring(CATALINA_BASE_TOKEN.length());
            }
        }
        if (replace && log.isDebugEnabled())
            log.debug("Expanded " + before + " to " + repository);

        // Check for a JAR URL repository
        try {
            new URL(repository);
            repositoryLocations.add(repository);
            repositoryTypes.add(ClassLoaderFactory.IS_URL);
            continue;
        } catch (MalformedURLException e) {
            // Ignore
        }

        if (repository.endsWith("*.jar")) {
            repository = repository.substring
                (0, repository.length() - "*.jar".length());
            repositoryLocations.add(repository);
            repositoryTypes.add(ClassLoaderFactory.IS_GLOB);
        } else if (repository.endsWith(".jar")) {
            repositoryLocations.add(repository);
            repositoryTypes.add(ClassLoaderFactory.IS_JAR);
        } else {
            repositoryLocations.add(repository);
            repositoryTypes.add(ClassLoaderFactory.IS_DIR);
        }
    }

    String[] locations = repositoryLocations.toArray(new String[0]);
    Integer[] types = repositoryTypes.toArray(new Integer[0]);
     //創建ClassLoader
    ClassLoader classLoader = ClassLoaderFactory.createClassLoader
        (locations, types, parent);

    // Retrieving MBean server
    MBeanServer mBeanServer = null;
    if (MBeanServerFactory.findMBeanServer(null).size() > 0) {
        mBeanServer = MBeanServerFactory.findMBeanServer(null).get(0);
    } else {
        mBeanServer = ManagementFactory.getPlatformMBeanServer();
    }

    // Register the server classloader
    ObjectName objectName =
        new ObjectName("Catalina:type=ServerClassLoader,name=" + name);
    mBeanServer.registerMBean(classLoader, objectName);

    return classLoader;

}
//回看init方法,對應的securityClassLoad就是使用catalinaLoader完成tomcat核心類的加載的
public static void securityClassLoad(ClassLoader loader)
    throws Exception {

    if( System.getSecurityManager() == null ){
        return;
    }

    loadCorePackage(loader);
    loadLoaderPackage(loader);
    loadSessionPackage(loader);
    loadUtilPackage(loader);
    loadJavaxPackage(loader);
    loadCoyotePackage(loader);
    loadTomcatPackage(loader);
}

此處,完成了commonLoader,catalinaLoader和sharedLoader三個加載器的初始化,他們均是StandardClassLoader的實例,同時我們可以看到這三者之間的關系為

接下去,我們來看WebappLoader

StandardContext.java
protected synchronized void startInternal() throws LifecycleException {
     //省略前邊代碼
if (getLoader() == null) {
    WebappLoader webappLoader = new WebappLoader(getParentClassLoader());
    webappLoader.setDelegate(getDelegate());
    setLoader(webappLoader);
}
//省略中間代碼
     if ((loader != null) && (loader instanceof Lifecycle))
         ((Lifecycle) loader).start();
//省略后邊代碼
}

WebappLoader.java
protected void startInternal() throws LifecycleException {

    if (log.isDebugEnabled())
        log.debug(sm.getString("webappLoader.starting"));

    if (container.getResources() == null) {
        log.info("No resources for " + container);
        setState(LifecycleState.STARTING);
        return;
    }

    // Register a stream handler factory for the JNDI protocol
    URLStreamHandlerFactory streamHandlerFactory =
        new DirContextURLStreamHandlerFactory();
    if (first) {
        first = false;
        try {
            URL.setURLStreamHandlerFactory(streamHandlerFactory);
        } catch (Exception e) {
            // Log and continue anyway, this is not critical
            log.error("Error registering jndi stream handler", e);
        } catch (Throwable t) {
            // This is likely a dual registration
            log.info("Dual registration of jndi stream handler: "
                    + t.getMessage());
        }
    }

    // Construct a class loader based on our current repositories list
    try {

        classLoader = createClassLoader();
        classLoader.setResources(container.getResources());
        classLoader.setDelegate(this.delegate);
        classLoader.setSearchExternalFirst(searchExternalFirst);
        if (container instanceof StandardContext) {
            classLoader.setAntiJARLocking(
                    ((StandardContext) container).getAntiJARLocking());
            classLoader.setClearReferencesStatic(
                    ((StandardContext) container).getClearReferencesStatic());
            classLoader.setClearReferencesStopThreads(
                    ((StandardContext) container).getClearReferencesStopThreads());
            classLoader.setClearReferencesStopTimerThreads(
                    ((StandardContext) container).getClearReferencesStopTimerThreads());
            classLoader.setClearReferencesThreadLocals(
                    ((StandardContext) container).getClearReferencesThreadLocals());
        }

        for (int i = 0; i < repositories.length; i++) {
            classLoader.addRepository(repositories[i]);
        }

        // Configure our repositories
        setRepositories();
        setClassPath();

        setPermissions();

        ((Lifecycle) classLoader).start();

        // Binding the Webapp class loader to the directory context
        DirContextURLStreamHandler.bind(classLoader,
                this.container.getResources());

        StandardContext ctx=(StandardContext)container;
        String path = ctx.getPath();
        if (path.equals("")) {
            path = "/";
        }
        ObjectName cloname = new ObjectName
            (MBeanUtils.getDomain(ctx) + ":type=WebappClassLoader,path="
            + path + ",host=" + ctx.getParent().getName());
        Registry.getRegistry(null, null)
            .registerComponent(classLoader, cloname, null);

    } catch (Throwable t) {
        log.error( "LifecycleException ", t );
        throw new LifecycleException("start: ", t);
    }

    setState(LifecycleState.STARTING);
}

private WebappClassLoader createClassLoader()
    throws Exception {

    Class clazz = Class.forName(loaderClass);
    WebappClassLoader classLoader = null;

    if (parentClassLoader == null) {
        parentClassLoader = container.getParentClassLoader();
    }
    Class[] argTypes = { ClassLoader.class };
    Object[] args = { parentClassLoader };
    Constructor constr = clazz.getConstructor(argTypes);
    classLoader = (WebappClassLoader) constr.newInstance(args);

    return classLoader;

}

此處完成了WebappClassLoader的初始化,可見這個類加載器是對應一個Context的,即一個web應用。其parent應該是sharedLoader.

文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。

轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/67795.html

相關文章

  • SSH+Tomcat運行加密部署的web項目(初版)

    摘要:一般來說會在項目中的中添加一個,里面配置這個配置文件在部署時,會被復制到中去,并被重新命名為項目名。由于使用的項目中配置了來加載第三方庫,配置了我自定義加載器后,這些包都無法加載了。我往開發機上打加密補丁的時候,總是無故消失,不知道為什么 為了這個功能提了很多問題都沒能得到解答,最后終于自己搞定了,現在把大體步驟總結下,供大家參考指正 分三種情況:(1)沒有配置spring自動掃描(2...

    bergwhite 評論0 收藏0
  • 慕課網_《Spring Boot熱部署》學習總結

    時間:2017年12月01日星期五說明:本文部分內容均來自慕課網。@慕課網:http://www.imooc.com 教學源碼:無 學習源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 課程介紹 熱部署的使用場景 本地調式 線上發布 熱部署的使用優點 無論本地還是線上,都適用 無需重啟服務器:提高開發、調式效率、提升發布、運維效率、降低運維成本 前置...

    Channe 評論0 收藏0
  • java類加載相關

    摘要:標準擴展類加載器,它負責加載或由系統變量指定位置中的類庫加載到內存中。系統類加載器,它負責將類路徑中的類庫加載到內存。 類加載機制大家應該已經非常熟悉了,采取雙親委派機制,當加載一個類時,首先將加載任務委托給父類加載器,依次遞歸,如果父類加載器可以完成加載任務,就成功返回;如果父類無法加載,才由自己加載。 雙親委派機制的作用:防止內存中出現多份相同的字節碼。 其他規則:1.隱式加載:...

    el09xccxy 評論0 收藏0

發表評論

0條評論

ChanceWong

|高級講師

TA的文章

閱讀更多
最新活動
閱讀需要支付1元查看
<