在tomcat服务器中,我们可以通过配置文件%CATALINA_HOME%/conf/server.xml来对所用到的资源进行配置,如代码:
在这段配置中,指定了两个资源,一个是UserDatabase,另一个是jdbc/wroxTC6。本文主要讲述了,在tomcat是怎样通过JNDI来找到这些资源的。
1.JNDI基础和Tomcat中的JNDI
JNDI的全称是Java Naming and Directory Interface, JNDI的整体架构包含有JNDI API和JNDI SPI。利用前者可以访问各种 Naming Services和Directory Services。
Service Providers利用JNDI SPI来编写这些服务。因此这些服务可以被Java应用灵活的插拔。
在JNDI中,用名字来标识一个服务对象,name和object之间建立的关联称为一个binding,binding的集合称作context。
javax. naming.Context是 Naming Services所在的上下文接口;javax. naming.directory.DirContext是Directory Services所在的上下文接口。
在tomcat中类NamingContext实现了接口Context,在该类中保存有多个binding,每一个binding是一个NamingEntry实例。对于NamingEntry分为4种类型:ENTRY、LINK_REF、REFERENCE和CONTEXT。
在tomcat中的配置文件service.xml中,可以为tomcat服务器配置全局的 Naming Resource,也可以单独为某一个web应用配置局部的 Naming Resource。
2.寻找被绑定的资源
在tomcat启动时,采用了责任链模式来进行。在启动StandardServer时,调用与之相关的监听器。在监听器NamingContextListener中,对全局的 Naming Resources建立Context,绑定资源,查找资源等等。在启动StandardContext时,监听器NamingContextListener负责完成对局部 Naming Resources相关操作。本文讲述对全局的 Naming Resources的处理。
(1)首先是建立NamingContext类的实例:根Context(名字为:"/")。
(2)将资源对象从NamingResources中取出,形成Reference,绑定到根Context中。
因为在加载配置文件时,利用tomcat中的Digester,已经将配置文件形成了类NamingResources的实例,也就是配置文件的信息已经形成了相应的NamingResources对象。从NamingResources实例中取出资源,建立ResourceRef实例。
ResourceRef继承了java. naming.Reference,该类并不是具体的Resource,也不做为binding中的object加入到Context中。但是通过该对象,可以找到待绑定的Service,例如在UserDatabase所形成的ResourceRef实例中,指定的Reference的className是org.apache.catalina.UserDatabase;而配置文件的factory属性对应于一个StringRefAddr对象,加入到了Reference中。
将该Reference对象,形成REFERENCE类型的NamingEntry对象,并以资源的name属性为名称,加入根Context中。例如:以UserDatabase为名称,将该Resource对应的REFERENCE类型的NamingEntry对象,加入到了根Context中。
(3)从根Context查找资源,利用Reference找到资源。
当利用资源名称查找资源时,调用的是NamingContext.lookup方法。该方法中利用JNDI的方法NamingManager.getObjectInstance来调用Service Provider所提供的Service。
在方法NamingManager.getObjectInstance中,若传递的Reference不为空,则调用Reference的getFactoryClassName来获得具体的factory类(该factory类由Service Provider来实现,所以能够找到具体的资源。在Tomcat中,ResourceRef覆盖了getFactoryClassName方法,得到的是ResourceFactory实例)
调用ResourceFactory.getObjectInstance方法,从Reference的RefAddr中得到org.apache.catalina.users.MemoryUserDatabaseFactory实例,通过MemoryUserDatabaseFactory.getObjectInstance得到具体的资源MemoryUserDatabase对象。
(4)将真实的对象赋给NamingEntry的object属性,更改NamingEntry的类型为ENTRY。
此时根Context中存在有对真实的资源的绑定,名称为该资源的名称。
3.建立子Context
如果资源的名称中包含"/",则将REFERENCE类型的NamingEntry对象加入到Context前,要建立子Context。例如资源"jdbc/wroxTC6",需要建立子Context。
(1)建立子Context
建立子Context,并将该Context以CONTEXT类型的NamingEntry加入到根Context中。
(2)将资源对象从NamingResources中取出,形成Reference,绑定到子Context中。
在调用根Context对象的bind方法时,将资源的绑定委派到子Context中,将Reference绑定到子Context中。例如将资源"wroxTC6"绑定到以"jdbc"为名字的子Context中。
(3)查找资源,绑定真实的资源到子Context中。
在进行资源查找和找真实资源时,原理同2,只不过是首先找到子Context,然后再进行。
- <GlobalNamingResources>
- <Resource name="UserDatabase" auth="Container"
- type="org.apache.catalina.UserDatabase"
- description="User database that can be updated and saved"
- factory="org.apache.catalina.users.MemoryUserDatabaseFactory"
- pathname="conf/tomcat-users.xml" />
- <Resource name="jdbc/wroxTC6" auth="Container"
- type="javax.sql.DataSource" maxActive="20" maxIdle="30"
- maxWait="10000" username="root" password="1234"
- driverClassName="com.mysql.jdbc.Driver"
- url="jdbc:mysql://localhost:3306/test?autoReconnect=true" />
- </GlobalNamingResources>
<GlobalNamingResources> <Resource name="UserDatabase" auth="Container" type="org.apache.catalina.UserDatabase" description="User database that can be updated and saved" factory="org.apache.catalina.users.MemoryUserDatabaseFactory" pathname="conf/tomcat-users.xml" /> <Resource name="jdbc/wroxTC6" auth="Container" type="javax.sql.DataSource" maxActive="20" maxIdle="30" maxWait="10000" username="root" password="1234" driverClassName="com.mysql.jdbc.Driver" url="jdbc:mysql://localhost:3306/test?autoReconnect=true" /> </GlobalNamingResources>
在这段配置中,指定了两个资源,一个是UserDatabase,另一个是jdbc/wroxTC6。本文主要讲述了,在tomcat是怎样通过JNDI来找到这些资源的。
1.JNDI基础和Tomcat中的JNDI
JNDI的全称是Java Naming and Directory Interface, JNDI的整体架构包含有JNDI API和JNDI SPI。利用前者可以访问各种 Naming Services和Directory Services。
Service Providers利用JNDI SPI来编写这些服务。因此这些服务可以被Java应用灵活的插拔。
在JNDI中,用名字来标识一个服务对象,name和object之间建立的关联称为一个binding,binding的集合称作context。
javax. naming.Context是 Naming Services所在的上下文接口;javax. naming.directory.DirContext是Directory Services所在的上下文接口。
在tomcat中类NamingContext实现了接口Context,在该类中保存有多个binding,每一个binding是一个NamingEntry实例。对于NamingEntry分为4种类型:ENTRY、LINK_REF、REFERENCE和CONTEXT。
在tomcat中的配置文件service.xml中,可以为tomcat服务器配置全局的 Naming Resource,也可以单独为某一个web应用配置局部的 Naming Resource。
2.寻找被绑定的资源
在tomcat启动时,采用了责任链模式来进行。在启动StandardServer时,调用与之相关的监听器。在监听器NamingContextListener中,对全局的 Naming Resources建立Context,绑定资源,查找资源等等。在启动StandardContext时,监听器NamingContextListener负责完成对局部 Naming Resources相关操作。本文讲述对全局的 Naming Resources的处理。
(1)首先是建立NamingContext类的实例:根Context(名字为:"/")。
(2)将资源对象从NamingResources中取出,形成Reference,绑定到根Context中。
因为在加载配置文件时,利用tomcat中的Digester,已经将配置文件形成了类NamingResources的实例,也就是配置文件的信息已经形成了相应的NamingResources对象。从NamingResources实例中取出资源,建立ResourceRef实例。
ResourceRef继承了java. naming.Reference,该类并不是具体的Resource,也不做为binding中的object加入到Context中。但是通过该对象,可以找到待绑定的Service,例如在UserDatabase所形成的ResourceRef实例中,指定的Reference的className是org.apache.catalina.UserDatabase;而配置文件的factory属性对应于一个StringRefAddr对象,加入到了Reference中。
将该Reference对象,形成REFERENCE类型的NamingEntry对象,并以资源的name属性为名称,加入根Context中。例如:以UserDatabase为名称,将该Resource对应的REFERENCE类型的NamingEntry对象,加入到了根Context中。
(3)从根Context查找资源,利用Reference找到资源。
当利用资源名称查找资源时,调用的是NamingContext.lookup方法。该方法中利用JNDI的方法NamingManager.getObjectInstance来调用Service Provider所提供的Service。
在方法NamingManager.getObjectInstance中,若传递的Reference不为空,则调用Reference的getFactoryClassName来获得具体的factory类(该factory类由Service Provider来实现,所以能够找到具体的资源。在Tomcat中,ResourceRef覆盖了getFactoryClassName方法,得到的是ResourceFactory实例)
调用ResourceFactory.getObjectInstance方法,从Reference的RefAddr中得到org.apache.catalina.users.MemoryUserDatabaseFactory实例,通过MemoryUserDatabaseFactory.getObjectInstance得到具体的资源MemoryUserDatabase对象。
(4)将真实的对象赋给NamingEntry的object属性,更改NamingEntry的类型为ENTRY。
此时根Context中存在有对真实的资源的绑定,名称为该资源的名称。
3.建立子Context
如果资源的名称中包含"/",则将REFERENCE类型的NamingEntry对象加入到Context前,要建立子Context。例如资源"jdbc/wroxTC6",需要建立子Context。
(1)建立子Context
建立子Context,并将该Context以CONTEXT类型的NamingEntry加入到根Context中。
(2)将资源对象从NamingResources中取出,形成Reference,绑定到子Context中。
在调用根Context对象的bind方法时,将资源的绑定委派到子Context中,将Reference绑定到子Context中。例如将资源"wroxTC6"绑定到以"jdbc"为名字的子Context中。
(3)查找资源,绑定真实的资源到子Context中。
在进行资源查找和找真实资源时,原理同2,只不过是首先找到子Context,然后再进行。