Tomcat 總體架構(gòu)-源碼組織

開篇

?這篇文章主要是將Tomcat的架構(gòu)圖從源碼角度解析了一下庐完,基本上就是把圖和源碼串聯(lián)起來。


Tomcat 總體架構(gòu)

Tomcat 總體架構(gòu)


Catalina - 入口

? Catalina對象包含Server對象變量熔萧,在初始化過程中通過Digester注入Server來實現(xiàn)。

  • protected Server server = null
public class Catalina {

    protected boolean await = false;

    protected String configFile = "conf/server.xml";

    protected ClassLoader parentClassLoader = Catalina.class.getClassLoader();

    // Catalina包含StandardServer對象
    protected Server server = null;

    protected boolean useShutdownHook = true;

    protected Thread shutdownHook = null;

    protected boolean useNaming = true;

    protected boolean loaded = false;
}


Server - StandardServer

? StandardServer實現(xiàn)了Server接口和Lifecycle接口僚祷,核心變量如下:

  • port字段存儲<server>標簽的port屬性
  • shutdown字段存儲<server>標簽的shutdown屬性
  • Service services[]存儲Server標簽子標簽的<Service>標簽對象
  • private Service services[] = new Service[0]
public final class StandardServer extends LifecycleMBeanBase implements Server {

    public StandardServer() {

        super();
        // 省略相關(guān)代碼
    }

    // 省略相關(guān)代碼

    // 對比server.xml中<server>標簽的內(nèi)容的port
    private int port = 8005;

    // 維護Service的對象佛致,
    private Service services[] = new Service[0];

    private final Object servicesLock = new Object();
    
    // 對比server.xml中<server>標簽的內(nèi)容的shutdown
    private String shutdown = "SHUTDOWN";

    // 省略相關(guān)代碼
}


Service - StandardService

? StandardService實現(xiàn)了Server接口和Lifecycle接口,核心變量如下:

  • Connector connectors[] 變量保存監(jiān)聽的Connector對象辙谜。
  • ArrayList<Executor> executors 變量保存多線程對象Executor對象俺榆。
  • Engine engine變量保存Service標簽內(nèi)部的Engine對象。
  • Mapper mapper變量保存Mapper對象装哆。
  • MapperListener mapperListener變量保存MapperListener對象罐脊。
public class StandardService extends LifecycleMBeanBase implements Service {
    private String name = null;

    private Server server = null;

    protected final PropertyChangeSupport support = new PropertyChangeSupport(this);
    
    // 保存Service標簽下的Connector對象
    protected Connector connectors[] = new Connector[0];

    private final Object connectorsLock = new Object();
    
    // 保存Service的線程池Executor對象
    protected final ArrayList<Executor> executors = new ArrayList<>();
    
    // 保存Service的Engine對象
    private Engine engine = null;

    private ClassLoader parentClassLoader = null;

    protected final Mapper mapper = new Mapper();

    protected final MapperListener mapperListener = new MapperListener(this);


Engine - StandardEngine

? StandardEngine實現(xiàn)了Server接口和Lifecycle接口,核心變量在基類ContainerBase:

  • 基類ContainerBase的HashMap<String, Container> children保存<Host>對應(yīng)的對象蜕琴。
  • 基類ContainerBase的Realm realm對象保存<Realm>標簽對應(yīng)的對象萍桌。
  • 基類ContainerBase的Pipeline pipeline保存調(diào)用鏈并保存Valve對象。
public class StandardEngine extends ContainerBase implements Engine {
    public StandardEngine() {

        super();
        // 省略相關(guān)代碼
    }

    private String defaultHost = null;

    private Service service = null;

    private String jvmRouteId;
}


public abstract class ContainerBase extends LifecycleMBeanBase implements Container {

    // 保存Host對象
    protected final HashMap<String, Container> children = new HashMap<>();

    protected int backgroundProcessorDelay = -1;

    protected final List<ContainerListener> listeners = new CopyOnWriteArrayList<>();

    protected Cluster cluster = null;

    private final ReadWriteLock clusterLock = new ReentrantReadWriteLock();

    protected String name = null;

    protected Container parent = null;

    protected ClassLoader parentClassLoader = null;

    protected final Pipeline pipeline = new StandardPipeline(this);
    // 保存Realm對象
    private volatile Realm realm = null;

    private final ReadWriteLock realmLock = new ReentrantReadWriteLock();

    protected boolean startChildren = true;

    private Thread thread = null;

    private volatile boolean threadDone = false;

    private int startStopThreads = 1;

    protected ThreadPoolExecutor startStopExecutor;
}


Host - StandardHost

? StandardEngine實現(xiàn)了Server接口和Lifecycle接口凌简,部分變量在基類ContainerBase:

  • appBase 變量保存Host標簽的appBase上炎。
  • autoDeploy 變量保存Host標簽的autoDeploy。
  • unpackWARs 變量保存Host標簽的unpackWARs雏搂。
  • 基類ContainerBase的變量HashMap<String, Container> children保存Context變量藕施。
  • 基類ContainerBase的Pipeline pipeline保存調(diào)用鏈并保存Valve對象。
public class StandardHost extends ContainerBase implements Host {

    public StandardHost() {

        super();
        pipeline.setBasic(new StandardHostValve());

    }

    private String[] aliases = new String[0];

    private final Object aliasesLock = new Object();

    private String appBase = "webapps";

    private volatile File appBaseFile = null;

    private String xmlBase = null;

    private volatile File hostConfigBase = null;

    private boolean autoDeploy = true;

    private String configClass = "org.apache.catalina.startup.ContextConfig";

    private String contextClass = "org.apache.catalina.core.StandardContext";

    private boolean deployOnStartup = true;

    private boolean deployXML = !Globals.IS_SECURITY_ENABLED;

    private boolean copyXML = false;

    private String errorReportValveClass = "org.apache.catalina.valves.ErrorReportValve";

    private boolean unpackWARs = true;

    private String workDir = null;

    private boolean createDirs = true;

    private final Map<ClassLoader, String> childClassLoaders = new WeakHashMap<>();

    private Pattern deployIgnore = null;

    private boolean undeployOldVersions = false;

    private boolean failCtxIfServletStartFails = false;
}



public abstract class ContainerBase extends LifecycleMBeanBase implements Container {

    // 保存Context對象
    protected final HashMap<String, Container> children = new HashMap<>();

    protected int backgroundProcessorDelay = -1;

    protected final List<ContainerListener> listeners = new CopyOnWriteArrayList<>();

    protected Cluster cluster = null;

    private final ReadWriteLock clusterLock = new ReentrantReadWriteLock();

    protected String name = null;

    protected Container parent = null;

    protected ClassLoader parentClassLoader = null;

    protected final Pipeline pipeline = new StandardPipeline(this);
    // 保存Realm對象
    private volatile Realm realm = null;

    private final ReadWriteLock realmLock = new ReentrantReadWriteLock();

    protected boolean startChildren = true;

    private Thread thread = null;

    private volatile boolean threadDone = false;

    private int startStopThreads = 1;

    protected ThreadPoolExecutor startStopExecutor;
}


Context - StandardContext

? StandardEngine實現(xiàn)了Server接口和Lifecycle接口凸郑,部分變量如下:

  • 在context容器中可以定義非常多的屬性裳食,詳細內(nèi)容見官方手冊
  • wrapperClass:實現(xiàn)wrapper容器的類芙沥,wrapper用于管理該context中的servlet胞谈,該類必須實現(xiàn)org.apache.catalina.Wrapper接口尘盼,如果不指定該屬性則采用默認的標準類。
  • 基類ContainerBase的Pipeline pipeline保存調(diào)用鏈并保存Valve對象烦绳。
public class StandardContext extends ContainerBase implements Context, 
NotificationEmitter {

    // 省略相關(guān)代碼

    private String wrapperClassName = StandardWrapper.class.getName();
    private Class<?> wrapperClass = null;
}


Wrapper - StandardWrapper

?StandardWrapper實現(xiàn)了StandardWrapper接口用以處理servlet請求。

public class StandardWrapper extends ContainerBase
    implements StandardWrapper, Wrapper, NotificationEmitter {

    protected static final String[] DEFAULT_SERVLET_METHODS = 
                          new String[] {"GET", "HEAD", "POST" };


    public StandardWrapper() {

        super();
        swValve=new StandardWrapperValve();
        pipeline.setBasic(swValve);
        broadcaster = new NotificationBroadcasterSupport();

    }

    protected long available = 0L;
    protected final NotificationBroadcasterSupport broadcaster;
    protected final AtomicInteger countAllocated = new AtomicInteger(0);
    protected final StandardWrapperFacade facade = new StandardWrapperFacade(this);
    protected volatile Servlet instance = null;
    protected volatile boolean instanceInitialized = false;
    protected int loadOnStartup = -1;
    protected final ArrayList<String> mappings = new ArrayList<>();
    protected HashMap<String, String> parameters = new HashMap<>();
    protected HashMap<String, String> references = new HashMap<>();
    protected String runAs = null;
    protected long sequenceNumber = 0;
    protected String servletClass = null;
    protected volatile boolean singleThreadModel = false;
    protected volatile boolean unloading = false;
    protected int maxInstances = 20;
    protected int nInstances = 0;
    protected Stack<Servlet> instancePool = null;
    protected long unloadDelay = 2000;
    protected boolean isJspServlet;
    protected ObjectName jspMonitorON;
    protected boolean swallowOutput = false;
    protected StandardWrapperValve swValve;
    protected long loadTime=0;
    protected int classLoadTime=0;
    protected MultipartConfigElement multipartConfigElement = null;
    protected boolean asyncSupported = false;
    protected boolean enabled = true;
    private boolean overridable = false;

    protected static Class<?>[] classType = new Class[]{ServletConfig.class};

    private final ReentrantReadWriteLock parametersLock =
            new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock mappingsLock =
            new ReentrantReadWriteLock();
    private final ReentrantReadWriteLock referencesLock =
            new ReentrantReadWriteLock();
}


Executor - StandardThreadExecutor

? Tomcat自定義Executor接口配紫,繼承自juc包下的Executor接口径密,增加getName()接口。

public interface Executor extends java.util.concurrent.Executor, Lifecycle {

    public String getName();

    void execute(Runnable command, long timeout, TimeUnit unit);
}



? Tomcat自定義ThreadPoolExecutor類躺孝,繼承自juc包下的ThreadPoolExecutor接口享扔,重寫execute()方法。

public class ThreadPoolExecutor extends java.util.concurrent.ThreadPoolExecutor {

    private final AtomicInteger submittedCount = new AtomicInteger(0);
    private final AtomicLong lastContextStoppedTime = new AtomicLong(0L);
    private final AtomicLong lastTimeThreadKilledItself = new AtomicLong(0L);

    private long threadRenewalDelay = Constants.DEFAULT_THREAD_RENEWAL_DELAY;

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, handler);
        prestartAllCoreThreads();
    }

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory,
            RejectedExecutionHandler handler) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, handler);
        prestartAllCoreThreads();
    }

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, threadFactory, new RejectHandler());
        prestartAllCoreThreads();
    }

    public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue) {
        super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new RejectHandler());
        prestartAllCoreThreads();
    }

    @Override
    public void execute(Runnable command) {
        execute(command,0,TimeUnit.MILLISECONDS);
    }

    public void execute(Runnable command, long timeout, TimeUnit unit) {
        submittedCount.incrementAndGet();
        try {
            super.execute(command);
        } catch (RejectedExecutionException rx) {
            if (super.getQueue() instanceof TaskQueue) {
                final TaskQueue queue = (TaskQueue)super.getQueue();
                try {
                    if (!queue.force(command, timeout, unit)) {
                        submittedCount.decrementAndGet();
                        throw new RejectedExecutionException("Queue capacity is full.");
                    }
                } catch (InterruptedException x) {
                    submittedCount.decrementAndGet();
                    throw new RejectedExecutionException(x);
                }
            } else {
                submittedCount.decrementAndGet();
                throw rx;
            }

        }
    }
}



? Tomcat的StandardThreadExecutor實現(xiàn)Lifecycle接口并實現(xiàn)自定義的Executor接口植袍。

  • StandardThreadExecutor的executor對象是自定義的ThreadPoolExecutor對象惧眠。
  • 自定義的ThreadPoolExecutor對象是在startInternal()方法內(nèi)部初始化,自定義線程工廠以及任務(wù)隊列于个。
  • StandardThreadExecutor實現(xiàn)了自定義Executor接口并在execute()方法執(zhí)行自定義ThreadPoolExecutor的方法氛魁。
public class StandardThreadExecutor extends LifecycleMBeanBase
        implements Executor, ResizableExecutor {

    protected int threadPriority = Thread.NORM_PRIORITY;
    protected boolean daemon = true;
    protected String namePrefix = "tomcat-exec-";
    protected int maxThreads = 200;
    protected int minSpareThreads = 25;
    protected int maxIdleTime = 60000;
    protected ThreadPoolExecutor executor = null;
    protected String name;
    protected boolean prestartminSpareThreads = false;
    protected int maxQueueSize = Integer.MAX_VALUE;
    protected long threadRenewalDelay = org.apache.tomcat.util.threads.Constants.DEFAULT_THREAD_RENEWAL_DELAY;
    private TaskQueue taskqueue = null;

    public StandardThreadExecutor() {
        //empty constructor for the digester
    }


    @Override
    protected void initInternal() throws LifecycleException {
        super.initInternal();
    }

    @Override
    protected void startInternal() throws LifecycleException {

        taskqueue = new TaskQueue(maxQueueSize);
        TaskThreadFactory tf = new TaskThreadFactory(namePrefix,daemon,getThreadPriority());
        // 自定義ThreadPoolExecutor
        executor = new ThreadPoolExecutor(getMinSpareThreads(), getMaxThreads(), maxIdleTime, TimeUnit.MILLISECONDS,taskqueue, tf);
        executor.setThreadRenewalDelay(threadRenewalDelay);
        if (prestartminSpareThreads) {
            executor.prestartAllCoreThreads();
        }
        taskqueue.setParent(executor);

        setState(LifecycleState.STARTING);
    }

    @Override
    public void execute(Runnable command, long timeout, TimeUnit unit) {
        if ( executor != null ) {
            executor.execute(command,timeout,unit);
        } else {
            throw new IllegalStateException("StandardThreadExecutor not started.");
        }
    }


    @Override
    public void execute(Runnable command) {
        if ( executor != null ) {
            try {
                executor.execute(command);
            } catch (RejectedExecutionException rx) {
                //there could have been contention around the queue
                if ( !( (TaskQueue) executor.getQueue()).force(command) ) throw new RejectedExecutionException("Work queue full.");
            }
        } else throw new IllegalStateException("StandardThreadPool not started.");
    }
}


Connector & ProtocolHandler & AbstractEndpoint

? Connector的核心變量如下

  • 協(xié)議處理接口ProtocolHandler protocolHandler。
  • Coyote adapter 的 Adapter adapter厅篓。
public class Connector extends LifecycleMBeanBase  {

    public Connector() {
        this(null);
    }

    public Connector(String protocol) {
        setProtocol(protocol);

        ProtocolHandler p = null;
        try {
            Class<?> clazz = Class.forName(protocolHandlerClassName);
            p = (ProtocolHandler) clazz.getConstructor().newInstance();
        } catch (Exception e) {
            log.error(sm.getString(
                    "coyoteConnector.protocolHandlerInstantiationFailed"), e);
        } finally {
            this.protocolHandler = p;
        }

    protected Service service = null;
    protected boolean allowTrace = false;
    protected long asyncTimeout = 30000;
    protected boolean enableLookups = false;
    protected boolean xpoweredBy = false;
    protected int port = -1;
    protected String proxyName = null;
    protected int proxyPort = 0;
    protected int redirectPort = 443;
    protected String scheme = "http";
    protected boolean secure = false;
    private int maxCookieCount = 200;
    protected int maxParameterCount = 10000;
    protected int maxPostSize = 2 * 1024 * 1024;
    protected int maxSavePostSize = 4 * 1024;
    protected String parseBodyMethods = "POST";
    protected HashSet<String> parseBodyMethodsSet;
    protected boolean useIPVHosts = false;
    protected String protocolHandlerClassName =
        "org.apache.coyote.http11.Http11NioProtocol";

    // 協(xié)議處理接口 Coyote protocol handler.
    protected final ProtocolHandler protocolHandler;
    // Coyote adapter.
    protected Adapter adapter = null;

    protected String URIEncoding = null;
    protected String URIEncodingLower = null;
    private Charset uriCharset = StandardCharsets.UTF_8;
    protected boolean useBodyEncodingForURI = false;


    protected static final HashMap<String,String> replacements = new HashMap<>();
    static {
        replacements.put("acceptCount", "backlog");
        replacements.put("connectionLinger", "soLinger");
        replacements.put("connectionTimeout", "soTimeout");
        replacements.put("rootFile", "rootfile");
    }
}



? ProtocolHandler的核心變量如下

  • ProtocolHandler的內(nèi)部包含AbstractEndpoint<S> endpoint負責監(jiān)聽連接秀存。
public abstract class AbstractProtocol<S> implements ProtocolHandler,
        MBeanRegistration {

    private static final StringManager sm = StringManager.getManager(AbstractProtocol.class);

    private static final AtomicInteger nameCounter = new AtomicInteger(0);

    protected ObjectName rgOname = null;

    private int nameIndex = 0;

    private final AbstractEndpoint<S> endpoint;

    private Handler<S> handler;

    private final Set<Processor> waitingProcessors =
            Collections.newSetFromMap(new ConcurrentHashMap<Processor, Boolean>());

    private AsyncTimeout asyncTimeout = null;
}
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市羽氮,隨后出現(xiàn)的幾起案子或链,更是在濱河造成了極大的恐慌,老刑警劉巖档押,帶你破解...
    沈念sama閱讀 216,544評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件澳盐,死亡現(xiàn)場離奇詭異,居然都是意外死亡令宿,警方通過查閱死者的電腦和手機叼耙,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,430評論 3 392
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來掀淘,“玉大人旬蟋,你說我怎么就攤上這事「锫Γ” “怎么了倾贰?”我有些...
    開封第一講書人閱讀 162,764評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長拦惋。 經(jīng)常有香客問我匆浙,道長,這世上最難降的妖魔是什么厕妖? 我笑而不...
    開封第一講書人閱讀 58,193評論 1 292
  • 正文 為了忘掉前任首尼,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘软能。我一直安慰自己迎捺,他們只是感情好,可當我...
    茶點故事閱讀 67,216評論 6 388
  • 文/花漫 我一把揭開白布查排。 她就那樣靜靜地躺著凳枝,像睡著了一般。 火紅的嫁衣襯著肌膚如雪跋核。 梳的紋絲不亂的頭發(fā)上岖瑰,一...
    開封第一講書人閱讀 51,182評論 1 299
  • 那天,我揣著相機與錄音砂代,去河邊找鬼蹋订。 笑死,一個胖子當著我的面吹牛刻伊,可吹牛的內(nèi)容都是我干的露戒。 我是一名探鬼主播,決...
    沈念sama閱讀 40,063評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼娃圆,長吁一口氣:“原來是場噩夢啊……” “哼玫锋!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起讼呢,我...
    開封第一講書人閱讀 38,917評論 0 274
  • 序言:老撾萬榮一對情侶失蹤撩鹿,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后悦屏,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體节沦,經(jīng)...
    沈念sama閱讀 45,329評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,543評論 2 332
  • 正文 我和宋清朗相戀三年础爬,在試婚紗的時候發(fā)現(xiàn)自己被綠了甫贯。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,722評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡看蚜,死狀恐怖叫搁,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情供炎,我是刑警寧澤渴逻,帶...
    沈念sama閱讀 35,425評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站音诫,受9級特大地震影響惨奕,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜竭钝,卻給世界環(huán)境...
    茶點故事閱讀 41,019評論 3 326
  • 文/蒙蒙 一梨撞、第九天 我趴在偏房一處隱蔽的房頂上張望雹洗。 院中可真熱鬧,春花似錦卧波、人聲如沸时肿。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,671評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽嗜侮。三九已至,卻和暖如春啥容,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背顷霹。 一陣腳步聲響...
    開封第一講書人閱讀 32,825評論 1 269
  • 我被黑心中介騙來泰國打工咪惠, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人淋淀。 一個月前我還...
    沈念sama閱讀 47,729評論 2 368
  • 正文 我出身青樓遥昧,卻偏偏與公主長得像,于是被迫代替她去往敵國和親朵纷。 傳聞我的和親對象是個殘疾皇子炭臭,可洞房花燭夜當晚...
    茶點故事閱讀 44,614評論 2 353

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)袍辞,斷路器鞋仍,智...
    卡卡羅2017閱讀 134,652評論 18 139
  • 從三月份找實習到現(xiàn)在,面了一些公司搅吁,掛了不少威创,但最終還是拿到小米、百度谎懦、阿里肚豺、京東、新浪界拦、CVTE吸申、樂視家的研發(fā)崗...
    時芥藍閱讀 42,240評論 11 349
  • 沉默 也許是矜 卻不是金 倘若 春天已成往事 還有季末守候 因為太過眷戀土地 記憶源于開始那一秒 回憶來自那一秒的...
    Summy123閱讀 121評論 0 0
  • 每天都會在夜里凌晨三點鐘左右醒來截碴,準時的可怕,像那天一樣枪萄。然后隐岛,翻翻手機,發(fā)現(xiàn)什么都沒有瓷翻。 接著聚凹,起床讀書割坠,像往常...
    七月的小七閱讀 224評論 0 0
  • Definition of Daily Scrum Daily Scrum是什么?某君也沒有開過妒牙。 我們都開過例會...
    Janusmsj閱讀 284評論 0 0