设为首页 收藏本站
查看: 582|回复: 0

[经验分享] 3、tomcat中的设计模式。

[复制链接]

尚未签到

发表于 2017-1-24 11:02:48 | 显示全部楼层 |阅读模式
这是我主要要写的内容,其中的模式主要是以GOF四人帮的教材作为参考,然后对tomcat中的源码做分析,从而从中分析一些设计模式出来。
1、Jmx的应用。
也即MBean的应用,用来处理对象的生存问题。
在tomcat里主要是要实现javax.management.MBeanRegistration这个接口,这就成为一个可注册组件。
abstract public interface MBeanRegistration{
public ObjectName preRegister(MBeanServer server,
ObjectName name) throws Exception ;
public void postRegister(Boolean registrationDone);
public void preDeregister() throws Exception ;
public void postDeregister();
}

通过注册这个组件,就可以在需要的时候取来用。
public void initialize()
throws LifecycleException
{
oname=new ObjectName( "Catalina:type=Server");
Registry.getRegistry(null, null).registerComponent(this, oname, null );
}

通过如下方法来读取文件的信息,来注册组件。
public class StandardEngine extends ContainerBase
implements Engine {
public void init() {        
if( mbeansFile == null ) {
String defaultMBeansFile=getBaseDir() + "/conf/tomcat5-mbeans.xml";
File f=new File( defaultMBeansFile );
if( f.exists() ) mbeansFile=f.getAbsolutePath();
}
if( mbeansFile != null ) {
readEngineMbeans();
}
if( mbeans != null ) {
try {
Registry.getRegistry(null, null).invoke(mbeans, "init", false);
} catch (Exception e) {
log.error("Error in init() for " + mbeansFile, e);
}
}
}
private void readEngineMbeans() {
try {
MbeansSource mbeansMB=new MbeansSource();
File mbeansF=new File( mbeansFile );
mbeansMB.setSource(mbeansF);
Registry.getRegistry(null, null).registerComponent
(mbeansMB, domain + ":type=MbeansFile", null);
mbeansMB.load();
mbeansMB.init();
mbeansMB.setRegistry(Registry.getRegistry(null, null));
mbeans=mbeansMB.getMBeans();
} catch( Throwable t ) {
log.error( "Error loading " + mbeansFile, t );
}        
}
}

可以通过如下方法来进行注册组件方法的调用。这个方法主要有两个功能,其一就是确保其父引用不为空,如为空,就调用注册组件的addChild()方法来设置父引用;其二就是注册自己。
public class StandardHost extends ContainerBase
implements Deployer, Host{
public void init() {
if( initialized ) return;
initialized=true;
// already registered.
if( getParent() == null ) {
try {
// Register with the Engine
ObjectName serviceName=new ObjectName(domain +
":type=Engine");
if( mserver.isRegistered( serviceName )) {
log.debug("Registering with the Engine");
mserver.invoke( serviceName, "addChild",
new Object[] { this },
new String[] {"org.apache.catalina.Container" } );
}
} catch( Exception ex ) {
ex.printStackTrace();
}
}
if( oname==null ) {
// not registered in JMX yet - standalone mode
try {
StandardEngine engine=(StandardEngine)parent;
domain=engine.getName();
log.debug( "Register " + domain );
oname=new ObjectName(domain + ":type=Host,host=" +
this.getName());
Registry.getRegistry(null, null)
.registerComponent(this, oname, null);
} catch( Throwable t ) {
log.info("Error registering ", t );
}
}
}
}

2、Listener的应用。主要为java中的事件处理,在java中事件处理从java1.1开始就用的是这种方式,Swing、AWT,SWT都是应用的这种事件模型。这里我举一些事例来说明tomcat中Listener的应用。
LifecycleListener接口处理:Lifecycle、LifecycleListener、LifecycleSupport、LifecycleEvent。
ContainerListener接口处理:Container,ContainerListener、ContainerEvent。
PropertyChangeListener接口处理:PropertyChangeListener、PropertyChangeSupport、PropertyChangeEvent、PropertyChangeListenerProxy。
这里以LifecycleListener接口处理为例:
public interface Lifecycle {
public static final String START_EVENT = "start";
public static final String BEFORE_START_EVENT = "before_start";
public static final String AFTER_START_EVENT = "after_start";
public static final String STOP_EVENT = "stop";
public static final String BEFORE_STOP_EVENT = "before_stop";
public static final String AFTER_STOP_EVENT = "after_stop";
public void addLifecycleListener(LifecycleListener listener);
public LifecycleListener[] findLifecycleListeners();
public void removeLifecycleListener(LifecycleListener listener);
public void start() throws LifecycleException;
public void stop() throws LifecycleException;
}
public final class LifecycleSupport{
public LifecycleSupport(Lifecycle lifecycle) ;
private Lifecycle lifecycle = null;
private LifecycleListener listeners[] = new LifecycleListener[0];
public void addLifecycleListener(LifecycleListener listener) ;
public LifecycleListener[] findLifecycleListeners() ;
public void fireLifecycleEvent(String type, Object data) ;
public void removeLifecycleListener(LifecycleListener listener);
}

public interface LifecycleListener {
public void lifecycleEvent(LifecycleEvent event);
}

public final class LifecycleEvent extends EventObject {
public LifecycleEvent(Lifecycle lifecycle, String type) ;
public LifecycleEvent(Lifecycle lifecycle, String type, Object data) ;
private Object data = null;
private Lifecycle lifecycle = null;
private String type = null;
public Object getData() ;
public Lifecycle getLifecycle() ;
public String getType();
}

Lifecycle为事件源,即事件发生时将触发具体的事件。其中的addLifecycleListener(),和removeLifecycleListener(),负责对监听器进行注册和取消注册。start()和stop()为具体事件的触发源,当然也可以在其它地方触发事件,但这个地方为Lifecycle的接口,这地方最好。当调用start()后,将触发BEFORE_START_EVENT,START_EVENT,AFTER_START_EVENT事件。而stop()将调用BEFORE_STOP_EVENT,STOP_EVENT,AFTER_STOP_EVENT事件。
LifecycleListener为事件监听器,主要负责对事件源进行注册监听器,并监听事件源的触发事件。
LifecycleSupport为监听器LifecycleListener的保持者,也是具体的事件的最终触发者。其中包含一个LifecycleListener列表,当事件触发时,LifecycleSupport.fireLifecycleEvent()负责对LifecycleListener[]进行遍历,找出对应的监听器来触发具体的事件。
LifecycleEvent为具体的事件对象,也是事件触发后生成的事件对象,包含有事件源、事件类型、事件数据等信息。LifecycleListener.lifecycleEvent()运行时就是依靠LifecycleEvent来进行工作的。
3、Wrapper的应用。
tomcat中使用Wrapper对我们的servlet进行包装,使容器能够对我们自己写的servlet进行控制,也就是说用Wrapper来进行容器和我们的应用进行通信。
这个模式我还没有搞得清楚,具体情况见Wrapper接口和其具体实现StandardWrapper。

4、Facade的应用。
这里要谈的主要是servlet中消息的载体Request和Response中用Facade模式来处理sun规范中javax.servlet.Request和org.apache.catalina.Request之间的区别、javax.servlet.Response和org.apache.cataina.Response之间的区别。RequestFacade和ResponseFacde在这里起到了桥梁的作用。他既实现了javax.servlet.*的接口,又对org.apache.cataina.*进行包装,使*Facade对外就像javax.servlet.*一样。而其内部的实现又是通过org.apache.catanila.*来进行具体实现的,其对*Facade的任何请求都实际交给java.apahce.cataina.*来处理的。
public class ResponseFacade implements ServletResponse {
public ResponseFacade(Response response) {
this.resp = response;
this.response = (ServletResponse) response;
}
protected ServletResponse response = null;
protected Response resp = null;
public String getCharacterEncoding() {
return response.getCharacterEncoding();
}
......
}
public final class HttpResponseFacade
extends ResponseFacade
implements HttpServletResponse {
public HttpResponseFacade(HttpResponse response) {
super(response);
}
public void addCookie(Cookie cookie) {
if (isCommitted())
return;
((HttpServletResponse) response).addCookie(cookie);
}
......
}

从这上面可以看出,在tomcat中数据流都是以http协议来进行传输的,不管是ResponseFacade还是HttpResponseFacade中每个方法的实际执行者都是HttpServletResponse。

5、StringManager管理信息,处理国际化问题。
在tomcat中提示消息和输出错误消息都是通过StringManager来管理的,而且还实现了模式的匹配问题,具体如下:
public class StringManager {
private ResourceBundle bundle;  
private StringManager(String packageName) ;
public String getString(String key);
protected String getStringInternal(String key) ;
public String getString(String key, Object[] args);
public String getString(String key, Object arg) ;
public String getString(String key, Object arg1, Object arg2);
public String getString(String key, Object arg1, Object arg2,
Object arg3);
public String getString(String key, Object arg1, Object arg2,
Object arg3, Object arg4) ;
private static Hashtable managers = new Hashtable();
public synchronized static StringManager getManager(String packageName);
}

6、Jndi的应用,处理资源问题。
这部分我还没有搞的清楚。
7、tomcat的启动框架。
这部分我只能说个大概,主要参考tomcat文档。
<Server>
<Listener/>
<GlobalNamingResources/>
<Service>
<Connector/>
<Engine/>
<Logger/>
<Realm/>
<Host>
<Logger/>
<Context>
<Logger/>
</Context>
</Host>
</Service>
</Server>

8、Notification模式
这个模式主要是在import javax.management.*中实现的,其具体的实现在mx4j中实现他的具体实现应该和上面的Listener差不多。
其中主要用到的类为:import javax.management.NotificationBroadcasterSupport和import javax.management.Notification。
NotificationBroadcasterSupport是支持类,Notification为封装了具体信息的事件类。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-332900-1-1.html 上篇帖子: tomcat 设置管理员账号和密码 下篇帖子: Tomcat 配置多数据源
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表