• 查看tomcat启动文件都干点啥---server对象


         在上一章查看tomcat启动文件都干点啥---Catalina.java中说道了构造Server,,这次尝试着说一下Tomcat中Server的内容,首先看一下org.apache.catalina.Server接口中定义的方法:

      

      从这里至少可以看出Server中包含很多Service,通过实现如下接口添加一个新的Service到Services的集合中,或者从集合中删除指定的Service:  

    public void addService(Service service);
    public void removeService(Service service);

      通过实现如下接口来完成通过service的名称返回Service的操作:  

    public Service findService(String name);

      通过实现如下接口来完成获取返回Server中所有Service的操作:  

    public Service[] findServices();

      对于Server的网络内容的设置和获取通过如下方法,包括设置地址,端口:  

    public int getPort();
    public void setPort(int port);
    public String getAddress();
    public void setAddress(String address);

      获取和指定shotdown命令:

    public String getShutdown();
    public void setShutdown(String shutdown);

      获取和设置父类的加载器:  

    public ClassLoader getParentClassLoader();
    public void setParentClassLoader(ClassLoader parent);

      如果设置了Catalina,那么也提供获取和设置的方法:  

    public Catalina getCatalina();
    public void setCatalina(Catalina catalina);

      通过Server接口至少我们能够得出结论:Server中包含多个Service对象。

      结构如下:

      

      值得注意的是Server借口继承了Lifecycle接口,

    public interface Server extends Lifecycle 

      Lifecycle 接口就是来控制Server极其组件的生命周期的,组件实现Lifecycle借口,就可以提供一致化的机制来启动和停止组件。下面看一下 Lifecycle的内容:

      首先是一些常量列表,小插曲,在Tomcat7.0.53中,tomcat在此处的注释有小问题,有兴趣的人可以看一下。  

       //组件初始化之前的事件
        public static final String BEFORE_INIT_EVENT = "before_init";
       //组件初始化之后的事件
        public static final String AFTER_INIT_EVENT = "after_init";
       //组件start的事件
        public static final String START_EVENT = "start";
       //组件start之前的事件
        public static final String BEFORE_START_EVENT = "before_start";
       //组件start之后的事件
        public static final String AFTER_START_EVENT = "after_start";
       //组件stop之后的事件
        public static final String STOP_EVENT = "stop";
       //组件stop之前的事件
        public static final String BEFORE_STOP_EVENT = "before_stop";
       //组件stop之后的事件
        public static final String AFTER_STOP_EVENT = "after_stop";
       //组件destrop之后的事件
        public static final String AFTER_DESTROY_EVENT = "after_destroy";
       //组件destrop之前的事件
        public static final String BEFORE_DESTROY_EVENT = "before_destroy";
        //组件periodic的事件 
        public static final String PERIODIC_EVENT = "periodic";

      下面就是Lifecycle接口定义的方法列表:

      

      既然Server中包含的主要对象就是Service,实现了Service就是对外提供服务了,下面在看一下Service的接口定义:

      

      看了定义的方法之后,很想逐一说明一下,可能会发现问题:

      在Service中添加或移除connector的方法:    

    public void addConnector(Connector connector);
    public void removeConnector(Connector connector);

        说明在每个Service中有多个Connector。

      在Service中添加或移除Executor的方法:   

    public void addExecutor(Executor ex);
    public void removeExecutor(Executor ex);

      返回所有Connector的方法:  

    public Connector[] findConnectors();

      返回所有executor的方法:  

    public Executor[] findExecutors();

      设置和获取Container的方法:  

    public Container getContainer();
    public void setContainer(Container container);

      获取和设置关联的Server对象的方法:  

    public void setServer(Server server);
    public Server getServer();

      给Service设置获取名称的方法:  

    public void setName(String name);
    public String getName();

      以上就是Service接口定义的主要方法,得出在Service中包含一个或多个Connector,包含一个或多个Executors和一个Container对象。接着上面的Server---Service图我们可以得出如下关系图:                      

                |---------Connector 

     Server----Service----|

                 |----------Container

      

      由此可知在Tomcat中的两个重要的组件就是Connector和Container。下面我们着重看一下Connector和Container。

      Container的主要功能是执行从客户端接收的请求,然后给出回应。看一下Container接口定义的方法:

      添加,删除和获取一个子Container:  

    public void addChild(Container child);
    public void removeChild(Container child);
    public Container findChild(String name);
    public Container[] findChildren();

      对应的在Container中就应该有设置和获取父Container的方法:  

    public void setParent(Container container);
    public Container getParent();

      在Container中添加,移除和获取事件监听器:

    public void addContainerListener(ContainerListener listener);
    public void removeContainerListener(ContainerListener listener);
    public ContainerListener[] findContainerListeners();

      在Container中添加,移除和获取属性变更监听器:  

    public void addPropertyChangeListener(PropertyChangeListener listener);
    public void removePropertyChangeListener(PropertyChangeListener listener);

      触发Container事件:

    public void fireContainerEvent(String type, Object data);

      记录指向这个container的请求与响应的日志:  

    public AccessLog getAccessLog();

      设置和获取作用在该container及其子container上的方法的延迟时间,单位秒:  

    public void setBackgroundProcessorDelay(int delay);
    public int getBackgroundProcessorDelay();

      设置和获取相关的集群:  

    public void setCluster(Cluster cluster);
    public Cluster getCluster();

      设置和获取Loadeer:  

    public void setLoader(Loader loader);
    public Loader getLoader();

      设置和获取负责管理该Container对应Session pool的Manager对象:  

    public void setManager(Manager manager);
    public Manager getManager();

      设置和获取Container的名字描述:  

    public void setName(String name);
    public String getName();

      设置和获取父类的ClassLoader:  

    public void setParentClassLoader(ClassLoader parent);
    public ClassLoader getParentClassLoader();

      获取Pipeline,负责管理该Container中的相关值:  

    public Pipeline getPipeline();

      设置和获取Container的上下文资源:  

    public void setResources(DirContext resources);
    public DirContext getResources();

      设置和获取启动和停止children container的线程数,可以并行的启动和停止子container:  

    public void setStartStopThreads(int startStopThreads);
    public int getStartStopThreads();

      Connector类中的变量已经方法实现如下:

      代表一个Container的入口的变量:  

    protected Adapter adapter = null;

      实现Servlet的API规则匹配的变量:  

    protected Mapper mapper = new Mapper();

      是否允许Trace:  

    protected boolean allowTrace = false;

      异步请求的超时时间:  

    protected  long asyncTimeout = 10000;

      是否允许DNS查找的标记:  

    protected boolean enableLookups = false;

      

      Mapper监听器:  

    protected MapperListener mapperListener = new MapperListener(mapper, this);

      GET和POST方法中,Container解析的最大的参数个数限制(默认值为1000,当设置数值小于0时,表示没有限制):  

    protected int maxParameterCount = 10000;

      Container接收POST方法传递的最大数据(默认值为2M):  

    protected int maxPostSize = 2 * 1024 * 1024;

      在Container认证时候默认保存的最大数据:(默认值4K):  

      protected int maxSavePostSize = 4 * 1024;

      一系列以逗号分割的,application/x-www-form-urlencoded形式的方法请求体,以什么方式转化成方法的集合:  

    protected String parseBodyMethods = "POST";

      通过parseBodyMethods方式确定的方法集合:  

    protected HashSet<String> parseBodyMethodsSet;

      监听请求端口的数量:(默认值为-1):  

    protected int port = -1;

      connector对象将请求重定向到那个Server:  

      protected String proxyName = null;

      connector对象请求重定向到server的哪个端口:  

       protected int proxyPort = 0;

       从no-ssl到ssl重定向端口:  

    protected int redirectPort = 443;

      通过connector接收到的所有请求的请求方案:  

      protected String scheme = "http";

      是否给每个接收到的请求设置安全连接标记:  

    protected boolean secure = false;

      一个String帮助对象:  

    protected static final StringManager sm = StringManager.getManager(Constants.Package);

      关联的Service对象:  

    protected Service service = null;

      URL编码:  

    protected String URIEncoding = null;

      是否用body编码给URL编码:(不明白)  

    protected boolean useBodyEncodingForURI = false;

      是否用IP绑定虚拟主机:  

    protected boolean useIPVHosts = false;

      

      下面看一下Connector的构造函数:

      

      public Connector() {
            this(null);
        }
    
        public Connector(String protocol) {
            setProtocol(protocol);
            // Instantiate protocol handler
            try {
                Class<?> clazz = Class.forName(protocolHandlerClassName);
                this.protocolHandler = (ProtocolHandler) clazz.newInstance();
            } catch (Exception e) {
                log.error(sm.getString(
                        "coyoteConnector.protocolHandlerInstantiationFailed"), e);
            }
        }
      Connector的构造函数中第一步是根据protocol名称HTTP/1.1,AJP/1.3或者protocol handler的类的全路径名称,下面是setProtocol方法的代码实现:  
    public void setProtocol(String protocol) {
    
            if (AprLifecycleListener.isAprAvailable()) {
                if ("HTTP/1.1".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.http11.Http11AprProtocol");
                } else if ("AJP/1.3".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.ajp.AjpAprProtocol");
                } else if (protocol != null) {
                    setProtocolHandlerClassName(protocol);
                } else {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.http11.Http11AprProtocol");
                }
            } else {
                if ("HTTP/1.1".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.http11.Http11Protocol");
                } else if ("AJP/1.3".equals(protocol)) {
                    setProtocolHandlerClassName
                        ("org.apache.coyote.ajp.AjpProtocol");
                } else if (protocol != null) {
                    setProtocolHandlerClassName(protocol);
                }
            }
    View Code

      然后根据setProtocol方法设置的protocol handler进行实例化,在setProtocol方法中调用的setProtocolHandlerClassName方法,如下:

      public void setProtocolHandlerClassName(String protocolHandlerClassName) {
    
            this.protocolHandlerClassName = protocolHandlerClassName;
    
        }

      给connector的变量protocolHandlerClassName赋值,然后根据protocolHandlerClassName的值进行实例化。进而赋值给protocolHandler 变量。

      然后是方法createObjectNameKeyProperties,该方法的作用是将请求的address参数拼接成字符串,包括type,port。下面是代码实现:  

     protected String createObjectNameKeyProperties(String type) {
    
            Object addressObj = getProperty("address");
    
            StringBuilder sb = new StringBuilder("type=");
            sb.append(type);
            sb.append(",port=");
            int port = getPort();
            if (port > 0) {
                sb.append(getPort());
            } else {
                sb.append("auto-");
                sb.append(getProperty("nameIndex"));
            }
            String address = "";
            if (addressObj instanceof InetAddress) {
                address = ((InetAddress) addressObj).getHostAddress();
            } else if (addressObj != null) {
                address = addressObj.toString();
            }
            if (address.length() > 0) {
                sb.append(",address=");
                sb.append(ObjectName.quote(address));
            }
            return sb.toString();
        }
    View Code

      创建一个Request对象,Request是一个对Coyote Request的封装,Coyote 这个东西很奇怪,是狼的意思,也不知道为什么外国人喜欢用动物名来给一个技术命名,hadoop,hive,pig等,说Coyote其实是对Socket的一个封装,将Socket的请求和相应封装成一个个Request和Response,具体如何封装,都包涵什么信息等内容以后展开说明:

    public Request createRequest() {
            Request request = new Request();
            request.setConnector(this);
            return (request);
        }
    View Code

      创建一个Response对象:  

    public Response createResponse() {
            Response response = new Response();
            response.setConnector(this);
            return (response);
        }
    View Code

      这里面值得注意的地方就是在request和response中,都有setConnector方法,所有connector是request和response的一个属性。

      下面看方法destroyInternal,这个方法是在LifecycleMBeanBase类中定义的,用来销毁mapperListener,protocolHandler从Service中移除这个Connector对象,代码实现如下:  

     @Override
        protected void destroyInternal() throws LifecycleException {
            mapperListener.destroy();
    
            try {
                protocolHandler.destroy();
            } catch (Exception e) {
                throw new LifecycleException
                    (sm.getString
                     ("coyoteConnector.protocolHandlerDestroyFailed"), e);
            }
    
            if (getService() != null) {
                getService().removeConnector(this);
            }
    
            super.destroyInternal();
        }
    View Code

      设置和获取是否允许Trace方法的执行:  

    public void setAllowTrace(boolean allowTrace) {
    
            this.allowTrace = allowTrace;
            setProperty("allowTrace", String.valueOf(allowTrace));
    
        }
    
    public boolean getAllowTrace() {
    
            return (this.allowTrace);
    
        }
    View Code

      设置和获取异步请求的过期时间:  

     public void setAsyncTimeout(long asyncTimeout) {
    
            this.asyncTimeout= asyncTimeout;
            setProperty("asyncTimeout", String.valueOf(asyncTimeout));
    
        }
    public long getAsyncTimeout() {
    
            return asyncTimeout;
    
        }
    View Code

      配置和获取参数,参数这部分在前面的章节已经提到过了:

    public void setAttribute(String name, Object value) {
            setProperty(name, String.valueOf(value));
        }
     public Object getAttribute(String name) {
            return getProperty(name);
        }
    View Code

      剩下的方法都是设置和获取前面定义的变量的值。

      

      Server的主要接口已经介绍完了,下面看一下一些关键类的实现:

      Server接口的标准实现是StandardServer类,同时StandServer也继承了LifecycleMBeanBase类,看一下StandardServer中几个重要方法的实现:

      

      找几个重要的方法说明一下:

      向保存Connector的数组中添加新的Connector对象的方法addConnector,代码实现如下:  

     public void addConnector(Connector connector) {
    
            synchronized (connectors) {
                connector.setService(this);
                Connector results[] = new Connector[connectors.length + 1];
                System.arraycopy(connectors, 0, results, 0, connectors.length);
                results[connectors.length] = connector;
                connectors = results;
    
                if (getState().isAvailable()) {
                    try {
                        connector.start();
                    } catch (LifecycleException e) {
                        log.error(sm.getString(
                                "standardService.connector.startFailed",
                                connector), e);
                    }
                }
    
                // Report this property change to interested listeners
                support.firePropertyChange("connector", null, connector);
            }
    
        }
    View Code

      首先要把Connector和Serice做关联,connector.setService(this),然后将要添加的connector对象添加到保存Connector对象的数组中,此处使用数组,完全是处于效率的考虑。然后查看当前Server对象的状态,如果状态合法的话,那么启动添加的connector对象。然后在更改此Connector的状态。

      返回Connector集合:  

    @Override
        public Connector[] findConnectors() {
    
            return (connectors);
    
        }
    View Code

      在Connector集合中移除connector:  

    public void removeConnector(Connector connector) {
    
            synchronized (connectors) {
                int j = -1;
                for (int i = 0; i < connectors.length; i++) {
                    if (connector == connectors[i]) {
                        j = i;
                        break;
                    }
                }
                if (j < 0)
                    return;
                if (connectors[j].getState().isAvailable()) {
                    try {
                        connectors[j].stop();
                    } catch (LifecycleException e) {
                        log.error(sm.getString(
                                "standardService.connector.stopFailed",
                                connectors[j]), e);
                    }
                }
                connector.setService(null);
                int k = 0;
                Connector results[] = new Connector[connectors.length - 1];
                for (int i = 0; i < connectors.length; i++) {
                    if (i != j)
                        results[k++] = connectors[i];
                }
                connectors = results;
    
                // Report this property change to interested listeners
                support.firePropertyChange("connector", connector, null);
            }
    
        }
    View Code

      首先遍历Connector集合,找到要移除的connector,如果指定的connector对象状态合法,那么调用该connector的stop方法,然后将指定的connector对象关联的Server置为null,剩下的内容就是整理移除connector对象的Connector集合。

      设置Container方法,该container对象处理Service中所有connector中的请求:  

    public void setContainer(Container container) {
    
            Container oldContainer = this.container;
            if ((oldContainer != null) && (oldContainer instanceof Engine))
                ((Engine) oldContainer).setService(null);
            this.container = container;
            if ((this.container != null) && (this.container instanceof Engine))
                ((Engine) this.container).setService(this);
            if (getState().isAvailable() && (this.container != null)) {
                try {
                    this.container.start();
                } catch (LifecycleException e) {
                    // Ignore
                }
            }
            if (getState().isAvailable() && (oldContainer != null)) {
                try {
                    oldContainer.stop();
                } catch (LifecycleException e) {
                    // Ignore
                }
            }
    
            // Report this property change to interested listeners
            support.firePropertyChange("container", oldContainer, this.container);
    
        }
    View Code

      首先是处理这个Server中原有的Container,原来可能有Container也有可能没有,所以要做判断,如果存在的话,解除和Service的关联,然后要处理新的container对象。关联Service,启动Container。

      由于Service中只有一个Container,所以没有移除Container方法,在设置的时候其实是完成了删除更新的操作。

      看一下startInternal方法:  

    protected void startInternal() throws LifecycleException {
    
            if(log.isInfoEnabled())
                log.info(sm.getString("standardService.start.name", this.name));
            setState(LifecycleState.STARTING);
    
            // Start our defined Container first
            if (container != null) {
                synchronized (container) {
                    container.start();
                }
            }
    
            synchronized (executors) {
                for (Executor executor: executors) {
                    executor.start();
                }
            }
    
            // Start our defined Connectors second
            synchronized (connectors) {
                for (Connector connector: connectors) {
                    try {
                        // If it has already failed, don't try and start it
                        if (connector.getState() != LifecycleState.FAILED) {
                            connector.start();
                        }
                    } catch (Exception e) {
                        log.error(sm.getString(
                                "standardService.connector.startFailed",
                                connector), e);
                    }
                }
            }
        }
    View Code

      该方法就是逐一启动Service中的组件,Container,Executor,Connector。

      stopInternal方法:  

     protected void stopInternal() throws LifecycleException {
    
            // Pause connectors first
            synchronized (connectors) {
                for (Connector connector: connectors) {
                    try {
                        connector.pause();
                    } catch (Exception e) {
                        log.error(sm.getString(
                                "standardService.connector.pauseFailed",
                                connector), e);
                    }
                }
            }
    
            if(log.isInfoEnabled())
                log.info(sm.getString("standardService.stop.name", this.name));
            setState(LifecycleState.STOPPING);
    
            // Stop our defined Container second
            if (container != null) {
                synchronized (container) {
                    container.stop();
                }
            }
    
            // Now stop the connectors
            synchronized (connectors) {
                for (Connector connector: connectors) {
                    if (!LifecycleState.STARTED.equals(
                            connector.getState())) {
                        // Connectors only need stopping if they are currently
                        // started. They may have failed to start or may have been
                        // stopped (e.g. via a JMX call)
                        continue;
                    }
                    try {
                        connector.stop();
                    } catch (Exception e) {
                        log.error(sm.getString(
                                "standardService.connector.stopFailed",
                                connector), e);
                    }
                }
            }
    
            synchronized (executors) {
                for (Executor executor: executors) {
                    executor.stop();
                }
            }
        }
    View Code

      由这两个方法也能看出来Lifecycle对于个个组件生命周期的一致的生命周期的管理机制。

      其实最开始想用本章说一下如何构建Server,但是觉得还是有必要将Server中的内容展开说明一下,在说如果构建的话可能更好理解。所以就有了这个只是具有说明意义的一节。 

      

      

  • 相关阅读:
    安装rabbitmq以及python调用rabbitmq--暂欠
    nginx报错:No package erlang available
    zipimport.ZipImportError: can't decompress data; zlib not available 解决办法
    centos python2.6升级到2.7 还有单独的python3.5环境
    TypeError: datetime.datetime(2016, 9, 25, 21, 12, 19, 135649) is not JSON serializable解决办法(json无法序列化对象的解决办法)
    django的跨站请求访问
    django的中间件
    django缓存
    django的分页--不全也未实现
    django的cookie 和session
  • 原文地址:https://www.cnblogs.com/fantiantian/p/3653559.html
Copyright © 2020-2023  润新知