Tomcat 源码分析 (设计模式) (七)

网友投稿 630 2022-10-25

Tomcat 源码分析 (设计模式) (七)

Tomcat 源码分析 (设计模式) (七)

工厂模式模板方法模式门面模式观察者模式责任链模式命令模式适配器模式

文章目录

​​1.工厂模式​​​​2.模版方法模式​​​​3.观察者模式​​​​4.责任链模式​​​​5.外观模式​​​​6.适配器模式​​​​7.命令模式​​

1.工厂模式

Tomcat 启动的时候, Connector 组件的 startInternal() 方法:

//Connector.java protocolHandler.start(); //AbstractProtocol.java endpoint.start(); //AbstractEndpoint.java bind(); //JIoEndpoint.java public void bind() throws Exception { // Initialize thread count defaults for acceptor if (acceptorThreadCount == 0) { acceptorThreadCount = 1; } // Initialize maxConnections if (getMaxConnections() == 0) { // User hasn't set a value - use the default setMaxConnections(getMaxThreadsExecutor(true)); } if (serverSocketFactory == null) { if (isSSLEnabled()) { //获取serverSocket的工厂类 serverSocketFactory = handler.getSslImplementation().getServerSocketFactory(this); } else { //获取serverSocket的工厂类 serverSocketFactory = new DefaultServerSocketFactory(this); } } if (serverSocket == null) { try { if (getAddress() == null) { //调用工厂类创建实例 serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog()); } else { //调用工厂类创建实例 serverSocket = serverSocketFactory.createSocket(getPort(), getBacklog(), getAddress()); } } catch (BindException orig) { String msg; if (getAddress() == null) msg = orig.getMessage() + " :" + getPort(); else msg = orig.getMessage() + " " + getAddress().toString() + ":" + getPort(); BindException be = new BindException(msg); be.initCause(orig); throw be; } } }

2.模版方法模式

LifecycleBase类中的start()方法:

@Override public final synchronized void start() throws LifecycleException { if (LifecycleState.STARTING_PREP.equals(state) || LifecycleState.STARTING.equals(state) || LifecycleState.STARTED.equals(state)) { if (log.isDebugEnabled()) { Exception e = new LifecycleException(); log.debug(sm.getString("lifecycleBase.alreadyStarted", toString()), e); } else if (log.isInfoEnabled()) { log.info(sm.getString("lifecycleBase.alreadyStarted", toString())); } return; } if (state.equals(LifecycleState.NEW)) { init(); } else if (state.equals(LifecycleState.FAILED)) { stop(); } else if (!state.equals(LifecycleState.INITIALIZED) && !state.equals(LifecycleState.STOPPED)) { invalidTransition(Lifecycle.BEFORE_START_EVENT); } setStateInternal(LifecycleState.STARTING_PREP, null, false); try { //抽象方法,子类具体实现 startInternal(); } catch (Throwable t) { // This is an 'uncontrolled' failure so put the component into the // FAILED state and throw an exception. ExceptionUtils.handleThrowable(t); setStateInternal(LifecycleState.FAILED, null, false); throw new LifecycleException(sm.getString("lifecycleBase.startFail", toString()), t); } if (state.equals(LifecycleState.FAILED)) { // This is a 'controlled' failure. The component put itself into the // FAILED state so call stop() to complete the clean-up. stop(); } else if (!state.equals(LifecycleState.STARTING)) { // Shouldn't be necessary but acts as a check that sub-classes are // doing what they are supposed to. invalidTransition(Lifecycle.AFTER_START_EVENT); } else { setStateInternal(LifecycleState.STARTED, null, false); } }

子类实现的方法:

protected abstract void startInternal() throws LifecycleException;

3.观察者模式

​​LifecycleListener​​​代表的是抽象观察者,它定义了一个​​lifecycleEvent​​​方法,这个方法就是当主题变化时要执行的方法。​​ServerLifecycleListener​​​代表的是具体的观察者,它实现了 ​​LifecycleListener​​接口的方法,就是这个具体的观察者具体的实现方式

​​Lifecycle​​​接口代表的是​​抽象主题​​​,它定义了管理观察者的方法和它要做的其他方法。而​​StandardServer​​​代表的是​​具体主题​​​,它实现了抽象 主题的所有方法。这里Tomcat对观察者做了扩展,增加了另外两个类:​​LifecycleSupport​​​和​​LifecycleEvent​​​,它们作为辅助 类​​扩展了观察者的功能​​​。​​LifecycleEvent​​​可以定义事件类別,对不同的半件可区别处理,更加灵活​​LifecycleSupport​​​类代理了主 题对多观察者的管理,将这个管理抽出来统一实现,以后如果修改只要修改​​LifecycleSupport​​​类就可以了,不需要去修改所有的具体主题,因为所有具体主题对观察者的操作都被代理给​​LifecycleSupport​​类了

​​LifecycleBase.java​​

setStateInternal(LifecycleState.STARTED, null, false); ... private synchronized void setStateInternal(LifecycleState state, Object data, boolean check) throws LifecycleException { if (log.isDebugEnabled()) { log.debug(sm.getString("lifecycleBase.setState", this, state)); } if (check) { // Must have been triggered by one of the abstract methods (assume // code in this class is correct) // null is never a valid state if (state == null) { invalidTransition("null"); // Unreachable code - here to stop eclipse complaining about // a possible NPE further down the method return; } // Any method can transition to failed // startInternal() permits STARTING_PREP to STARTING // stopInternal() permits STOPPING_PREP to STOPPING and FAILED to // STOPPING if (!(state == LifecycleState.FAILED || (this.state == LifecycleState.STARTING_PREP && state == LifecycleState.STARTING) || (this.state == LifecycleState.STOPPING_PREP && state == LifecycleState.STOPPING) || (this.state == LifecycleState.FAILED && state == LifecycleState.STOPPING))) { // No other transition permitted invalidTransition(state.name()); } } this.state = state; String lifecycleEvent = state.getLifecycleEvent(); if (lifecycleEvent != null) { fireLifecycleEvent(lifecycleEvent, data); } } ... protected void fireLifecycleEvent(String type, Object data) { lifecycle.fireLifecycleEvent(type, data); } ...

​​LifecycleSupport.java​​

/** * Notify all lifecycle event listeners that a particular event has * occurred for this Container. The default implementation performs * this notification synchronously using the calling thread. * * @param type Event type * @param data Event data */ public void fireLifecycleEvent(String type, Object data) { LifecycleEvent event = new LifecycleEvent(lifecycle, type, data); for (LifecycleListener listener : listeners) { listener.lifecycleEvent(event); } }

Tomcat的组件生命周期状态只要一变化,Tomcat就会通知改组件的所有的观察者,把状态变化通知到所有的观察者,看是否有观察者对相关组件的状态变化感兴趣。

4.责任链模式

​​Valve​​为阀门

通过​​getNext()​​获取到下一个阀门

实现类:

StandardWrapperValveStandardContextValveStandardHostValveStandardEngineValve

​​Tomcat​​​的容器设置就是责任链模式,从​​Engine​​​到​​Host​​​再到​​Context​​​ —直到​​Wrapper​​都通过一个链传递请求.

​​Container​​扮演抽象处理者角色具体处理者:​​StandardEngine​​​​Pipeline​​​和​​Valve​​​扩展了这个链的功能, 使得在链向下传递的过秤中,能够接收外界的干预。​​​Pipeline​​​就是连接每个子容器的管子,里面传递的​​Request​​​和​​Response​​​对象好比管子里流的水,而​​Valve​​就是在这个管子上开的一个个小孔子,让你有机会接触到里面的水,做一些额外 的事情。为了防止水被引出来而不流到下一个容器中,在每一段管子最后总有一个节点保证它一定能流到下一个子容器,所以每个容器都有一个​​StandardXXXValve​​

5.外观模式

外观模式又叫门面模式, 外观模式主要功能是封装了子系统的具体实现,提供统一的外观类给外部系统,这样当子系统内部实现发生变化的时候,不会影响到外部系统。

request,response,session等常用类都使用了外观设计模式。

​​request.getSession()​​

//RequestFacade.java @Override public HttpSession getSession() { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } return getSession(true); } //Request.java @Override public HttpSession getSession(boolean create) { if (request == null) { throw new IllegalStateException( sm.getString("requestFacade.nullRequest")); } if (SecurityUtil.isPackageProtectionEnabled()){ return AccessController. doPrivileged(new GetSessionPrivilegedAction(create)); } else { //委托给了request,而request是Request的实例 return request.getSession(create); } } /** * Return the session associated with this Request, creating one * if necessary and requested. * * @param create Create a new session if one does not exist */ @Override public HttpSession getSession(boolean create) { Session session = doGetSession(create); if (session == null) { return null; } return session.getSession(); } //StandardSession.java /** * Return the HttpSession for which this object * is the facade. */ @Override public HttpSession getSession() { if (facade == null){ if (SecurityUtil.isPackageProtectionEnabled()){ final StandardSession fsession = this; facade = AccessController.doPrivileged( new PrivilegedAction(){ @Override public StandardSessionFacade run(){ return new StandardSessionFacade(fsession); } }); } else { facade = new StandardSessionFacade(this); } } return (facade); } /** * Construct a new session facade. * * @param session The session instance to wrap */ public StandardSessionFacade(HttpSession session) { this.session = session; }

​​HttpRequestFacade​​​类封装了 ​​HttpRequest​​​接口,能够提供数据,通过​​HttpRequestFacade​​​访问到的数据都被代理到​​HttpRequest​​​中,通常被封装的对象都被设为​​Private​​​或者​​Protected​​​,以防止在​​Facade​​中被直接访问。

6.适配器模式

​​CoyoteAdapter​​

连接器调用 CoyoteAdapter 的 sevice 方法,传入的是 Tomcat Request 对象,CoyoteAdapter 负责将 Tomcat Request 转成 ServletRequest,再调用容器的 service 方法

​​Connector.java​​

@Override protected void initInternal() throws LifecycleException { super.initInternal(); if (protocolHandler == null) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInstantiationFailed")); } // Initialize adapter 初始化适配器 adapter = new CoyoteAdapter(this); protocolHandler.setAdapter(adapter); if (service != null) { protocolHandler.setUtilityExecutor(service.getServer().getUtilityExecutor()); } // Make sure parseBodyMethodsSet has a default if (null == parseBodyMethodsSet) { setParseBodyMethods(getParseBodyMethods()); } if (protocolHandler.isAprRequired() && !AprStatus.isInstanceCreated()) { throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprListener", getProtocolHandlerClassName())); } if (protocolHandler.isAprRequired() && !AprStatus.isAprAvailable()) { throw new LifecycleException(sm.getString("coyoteConnector.protocolHandlerNoAprLibrary", getProtocolHandlerClassName())); } if (AprStatus.isAprAvailable() && AprStatus.getUseOpenSSL() && protocolHandler instanceof AbstractHttp11jsseProtocol) { AbstractHttp11JsseProtocol jsseProtocolHandler = (AbstractHttp11JsseProtocol) protocolHandler; if (jsseProtocolHandler.isSSLEnabled() && jsseProtocolHandler.getSslImplementationName() == null) { // OpenSSL is compatible with the JSSE configuration, so use it if APR is available jsseProtocolHandler.setSslImplementationName(OpenSSLImplementation.class.getName()); } } try { protocolHandler.init(); } catch (Exception e) { throw new LifecycleException( sm.getString("coyoteConnector.protocolHandlerInitializationFailed"), e); } }

​​CoyoteAdapter.service()​​

@Override public void service(org.apache.coyote.Request req, org.apache.coyote.Response res) throws Exception { Request request = (Request) req.getNote(ADAPTER_NOTES); Response response = (Response) res.getNote(ADAPTER_NOTES); if (request == null) { // Create objects request = connector.createRequest(); request.setCoyoteRequest(req); response = connector.createResponse(); response.setCoyoteResponse(res); // Link objects request.setResponse(response); response.setRequest(request); // Set as notes req.setNote(ADAPTER_NOTES, request); res.setNote(ADAPTER_NOTES, response); // Set query string encoding req.getParameters().setQueryStringCharset(connector.getURICharset()); }

7.命令模式

主要是​​AJP​​​ 和 ​​HTTP​​​ 协议通过命令模式, 根据协议和IO实现的不同通过不同的​​Process​​子类去实现。

AjpProcessorAjpNioProcessorAjpAprProcessorHttp11ProcessorHttp11NioProcessorHttp11AprProcessor

每一种​​Processor​​​ 都有一种​​ProcessorHandler​​​ 而每一种协议处理类都有​​Handler​​ 。

​​Connector​​ 和 ​​Container​​ 的连接为命令模式:​​​Connector​​​ 作为抽象请求者,​​HttpConnector​​​ 作为具体请求者。​​HttpProcessor​​​ 作为命令。​​Container​​​ 作为命令的抽象接受者,​​ContainerBase​​​ 作为具体的接受者。客户端就是应用服务器 ​​Server​​​ 组件了。​​Server​​​ 首先创建命令请求者 ​​HttpConnector​​​ 对象,然后创建命令 ​​HttpProcessor​​​ 命令对象。再把命令对象交给命令接受者 ​​ContainerBase​​​ 容器来处理命令。命令的最终是被 ​​Tomcat​​​ 的 ​​Container​​​ 执行的。命令可以以队列的方式进来,​​Container​​​ 也可以以不同的方式来处理请求,如 ​​HTTP1.0​​​ 协议和 ​​HTTP1.1​​ 的处理方式就会不同。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:redis集群搭建-使用docker快速搭建一个测试redis集群
下一篇:NVDLA- 英伟达标准化推断加速框架
相关文章

 发表评论

暂时没有评论,来抢沙发吧~