前面讲解到Tomcat中使用Digester框架进行server.xml到javaBean对象的映射,这篇文章以Connector的SSL通道为例,来讲解Connector的属性是如何注入的。
先看一下SSL的配置:
1.Connector的Digester配置
前面已经源码分析过,在启动包中Bootstrape类会首先反射到Catalina类进行Digester的装配:
回顾前面的Digester学过的内容,addRule方法是为Digester解析到xml对应位置时,如何进行操作的规则定义。
ConnectorCreateRule源自于CreateRule,是Connector对象初始化的时候,进行什么操作。
SetAllPropertiesRule源自于SetPropertiesRule,是Connector对象创建完成,设置什么属性时,进行什么操作。
上面的两条rule,是Connector基于Digester默认的Rule自定义实现的,所以需要通过addRule方法进行加入。
最后一个rule是setNext,这条规则是Digester默认的规则,将当前的Connector对象加到整个解析树中,相当于addChild。
下面重点分析ConnectorCreateRule,和SetAllPropertiesRule这两个Rule。
2.ConnectorCreateRule
如果需要实现Rule,那么就需要了解Rule的生命周期:
ConnectorCreateRule对于begin方法进行了定制,如果没有定制,那么默认初始化Connector的时候,调用Connector的无参的构造方法。
但是对于连接器的结构来讲,其Tomcat的实现逻辑是,根据不同的http协议给Connector传入不同的参数,这个需要在对象构造的时候就应该确定,也就是说我们应该调用的是下面的构造方法:
对于Http/1.1协议来讲,应该反射出来的就是Http11Protocol类,然后实例化这个类并设置到Connector属性中去。
如果想完成上述的动作,那么默认的ObjectCreateRule就不好使了,需要进行自定义,这就是ConnectorCreateRule的实现了:
3.SetAllPropertiesRule
Connector的属性定义非常的多,但是SSL的属性却没有定义在Connector类中:
这是因为很多的属性和对应的协议和通道相关,属性全部设置在Connector中是不合适的,Tomcat将协议抽象为HttpxxxProtocol这样的类,通道抽象成xxxEndpoint这样的类,这些属性应该设置到这些类中去。
要想满足上述的需求,又需要对Digester的默认的Rule进行修改了,这回修改的是SetPropertiesRule,默认的SetPropertiesRule,遇到xxx属性,会自动反射调用setXxx()方法,进行设置属性。
看看Connector的SetAllPropertiesRule,这个Rule是自定义的,还是来看看begin方法:
当Connector实例构造完毕之后,遍历server.xml中配置的Connector的属性集合,代理给IntroSpectionUtil类的setProperties方法进行设置属性。
对于这个IntroSpectionUtil类是一个工具类,其实现思路还是反射,但是这个类的好处是放出了一个回调,也就是在代理设置属性的过程中,如果Connector类定义了setProperty方法,会尝试的调用Conector的setProperty,如果没有定义setProperty方法的话,默认还事对Connector对象的属性进行设置。
而从代码中可以看到,Conector的setProperty实际上把最终设置的属性转给了协议Handler:
这样,我们就不难发现,其这些SSL属性最终都是设置在Http11Protocol中:
4.xxxEndpoint
比较有意思的是,对于Http1.1协议,SSL这些属性最终也并没有设置到这个Http11Protocol类中,而是继续进行委托,将这些属性最终设置到协议关联的通道中,xxxEndPoint就是所谓的通道,对于NIO来将,就是NIOEndPoint,对于BIO来讲,就是JIOEndpoint。
整体的类图为:
相当于关于SSL的属性设置到了,上面的Endpoint中了。
总结:
本节以一个Connector实例表明,Digester如何进行扩展默认的Rule,来定制server.xml中的配置到javaBean的这样的一个过程,可以看到整个过程中,将Tomcat容器的逻辑加入了进来,这样在容器点火和初始化之前,很多属性就已经设置成功了。