原文地址:http://blog.sina.com.cn/s/blog_605f5b4f0100qwra.html
今天跟踪代码,发现在IntialContext的构造方法中会调用System.getProperties(),竟然从中得到了在jndi.properties文件中配置的信息,于是就将InitialContext的API中内容又重新读了一遍。
API中写道:
JNDI 通过按顺序合并取自以下两个源的值来确定每个属性值:
- 构造方法的环境参数、(适当属性的)applet 参数,以及系统属性中最先出现的属性。
- 应用程序资源文件 (jndi.properties)。
对于同时存在于两个源或多个应用程序资源文件中的每个属性,用以下方式确定属性值。如果该属性是指定 JNDI 工厂列表的标准 JNDI 属性之一(参见 Context),则所有值都被串联成一个以冒号分隔的列表。对于其他属性,只使用最先找到的值。
这一定位初始上下文和 URL 上下文工厂的默认策略可以通过调用 NamingManager.setInitialContextFactoryBuilder() 重写。
资源文件
要简化设置 JNDI 应用程序所需环境的任务,可以将资源文件 与应用程序组件和服务提供程序一起发布。JNDI 资源文件是使用属性文件格式的文件(参见 java.util.Properties
),包括一个键/值对列表。键是属性的名称(例如 "java.naming.factory.object"),而值是使用为该属性定义的格式的字符串。以下是 JNDI 资源文件的一个示例:
java.naming.factory.object=com.sun.jndi.ldap.AttrsToCorba:com.wiz.from.Person java.naming.factory.state=com.sun.jndi.ldap.CorbaToAttrs:com.wiz.from.Person java.naming.factory.control=com.sun.jndi.ldap.ResponseControlFactory
JNDI 类库读取资源文件,并使属性值随意可用。因此应该认为 JNDI 资源文件是“所有人可读的”,敏感信息(比如明文密码)不应该存储在那里。
有两种 JNDI 资源文件:提供程序 和应用程序。
提供程序资源文件
每个服务提供程序都有一个可选的资源,该资源列出了特定于该提供程序的属性。此资源的名称是:
[prefix/]jndiprovider.properties
其中 prefix 是提供程序的上下文实现的包名称,其每个句点 (".") 都被转换成一个斜杠 ("/")。 例如,假设服务提供程序定义了一个带有类名称 com.sun.jndi.ldap.LdapCtx 的上下文实现。此提供程序的提供程序资源被命名为 com/sun/jndi/ldap/jndiprovider.properties。如果该类不在一个包中,则资源的名称就是jndiprovider.properties。
JNDI 类库中的某些方法使用指定 JNDI 工厂列表的标准 JNDI 属性:
- java.naming.factory.object
- java.naming.factory.state
- java.naming.factory.control
- java.naming.factory.url.pkgs
在确定这些属性的值时,JNDI 库将参考提供程序资源文件。这以外的属性可由服务提供程序在提供程序资源文件中设置。服务提供程序的文档应该明确声明哪些属性是被允许的;文件中的其他属性将被忽略。
应用程序资源文件
在部署应用程序时,该应用程序通常将在其类路径中生成若干代码基目录和 JAR。类似地,在部署 applet 时,它将有一个指定 applet 类所处地址的代码基和档案文件。JNDI 查找(使用ClassLoader.getResources()
)类路径中所有名为 jndi.properties 的应用程序资源文件。此外,如果文件 java.home/lib/jndi.properties 存在并且是可读的,则 JNDI 会将其视为一个额外的应用程序资源文件。(java.home 指示由 java.home 系统属性命名的目录。)包含在这些文件中的所有属性都被放置在初始上下文环境中。然后此环境由其他上下文继承。
对于同时出现在多个应用程序资源文件中的每个属性,JNDI 使用最先找到的值,或者在少数有意义的情况下串联所有这些值(细节在下文给出)。例如,如果在三个 jndi.properties 资源文件中存在 "java.naming.factory.object" 属性,则对象工厂列表是所有三个文件中的属性值的串联。使用此方案,每个可部署组件都要负责列出它导出的工厂。JNDI 在搜索工厂类时自动收集和使用所有这些导出列表。
从 Java 2 Platform 开始可使用应用程序资源文件,java.home/lib 中的文件除外,它在较早的 Java 平台上也可以使用。
属性的搜索算法
当 JNDI 构造一个初始上下文时,该上下文的环境是使用传递给构造方法的环境参数中定义的属性、系统属性、applet 参数和应用程序资源文件进行初始化的。有关细节请参见 InitialContext。然后此初始环境由其他上下文实例继承。
如果 JNDI 类库需要确定某一属性的值,它将通过按顺序合并取自以下两个源的值来实现这一点:
- 将在其上执行操作的上下文的环境。
- 将在其上执行操作的上下文的提供程序资源文件 (jndiprovider.properties)。
对于每个同时存在于这两个源中的属性,JNDI 用以下方式确定属性的值。如果该属性是指定 JNDI 工厂列表的标准 JNDI 属性之一(如上文所列),则这些值被串联成一个以冒号分隔的列表。对于其他属性,只使用最先找到的值。
当服务提供程序需要确定某一属性的值时,它通常将直接从环境中获取该值。服务提供程序可以定义将置于其本身提供程序资源文件中的特定于提供程序的属性。在这种情况下,它应该根据上文所述合并这些值。
这样,每个服务提供程序开发人员便可以指定与该服务提供程序一起使用的工厂列表。这可以由应用程序或 applet 的部署方指定的应用程序资源修改,而这些资源又可以由用户修改。
如上即为所查API关于jndi.properties文件的全部说明。总结起来即为:
jndi.properties是jndi初始化文件。通常我们有两种方式来创建一个初始上下文:
1.通过创建一个Properties对象,设置Context.PROVIDER_UR,Context.InitialContextFactroy等等属性,创建InitialContext,例如:
Properties p = new Properties();
p.put(Cotnext.PROVIDER_URL, "localhost:1099 ");//主机名和端口号
//InitialContext的创建工厂类(类名是我乱写的)
p.put(Context.InitialContextFactroy, "com.sun.InitialContextFactory ");
InitialContext ctx = new InitialContext(p);
2.通过jndi.properties文件创建初始上下文
java.naming.factory.initial=com.sun.NamingContextFactory
java.naming.provider.url=localhost:1099
如果直接创建初始上下文,如下:
InitialContext ctx = new InitialContext();
InitialContext的构造器会在类路径中找jndi.properties文件,如果找到,通过里面的属性,创建初始上下文。
所以从上面可以看出,两种方式完成的目标是相同的。
因此,对于本地测试(并且JNDI资源没有设置安全属性)可以不添加properties属性,但是如果要访问远程的JNDI资源,就必须用饱含JNDI环境参数Hashtable初始化InitialContext。
必要的环境参数如:
Context.INITIAL_CONTEXT_FACTORY//连接工厂
Context.PROVIDER_URL//访问连接
Context.SECURITY_PRINCIPAL//安全用户
Context.SECURITY_CREDENTIALS//用户密码
有时会出现如NoInitialContextException是因为无法从System.properties中获得必要的JNDI参数中获得必要的JNDI参数,在服务器环境下,服务器启动时就把这些参数放到System.properties中了,于是直接new InitialContext()就搞定了,不要搞env那么麻烦,搞了env你的代码还无法移植,弄不好管理员设置服务器用的不是标准端口还照样抛异常。
但是在单机环境下,可没有JNDI服务在运行,那就手动启动一个JNDI服务。我在JDK 5的rt.jar中一共找到了4种SUN自带的JNDI实现:LDAP,CORBA,RMI,DNS。
这4种JNDI要正常运行还需要底层的相应服务。一般我们没有LDAP或CORBA服务器,也就无法启动这两种JNDI服务,DNS用于查域名的,以后再研究,唯一可以在main()中启动的就是基于RMI的JNDI服务。
现在我们就在main()中启动基于RMI的JNDI服务并且绑一个Date对象到JNDI上:
LocateRegistry.createRegistry(1099);
System.setProperty(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.rmi.registry.RegistryContextFactory");
System.setProperty(Context.PROVIDER_URL, "rmi://localhost:1099");
InitialContext ctx = new InitialContext();
class RemoteDate extends Date implements Remote {};
ctx.bind("java:comp/env/systemStartTime", new RemoteDate());
ctx.close();
注意,我直接把JNDI的相关参数放入了System.properties中,这样,后面的代码如果要查JNDI,直接new InitialContext()就可以了,否则,你又得写Hashtable env = ...
这段话里提到了system.properties属性,这就是调用system.getProperties的来由,猜想应该是先找到jndi.properties文件,之后通过System.setProperties(),而后通过System.getProperties()来得到。
相关推荐
hibernate.properties # # Hibernate, Relational Persistence for Idiomatic Java # # License: GNU Lesser General Public License (LGPL), version 2.1 or later. # See the lgpl.txt file in the root directory...
首先配置Tomcat服务器文件 ... <Resource name="jdbc/jndidemo" auth="Container" type="javax.sql.DataSource" maxActive="100" maxIdle="30" maxWait="10000" username="sa" password="1" driverClassName=...
主要参照网上的将打包了
jndi获取数据库连接,当前软件版本...Tomcat 为每个在其上运行的 Web 应用都提供了一个 JNDI 的 InitialContext 实现实例 Tomcat中的默认数据源支持基于Commons 项目中的DBCP 1.x连接池,也可以使用实现任何其他连接池
InitialContext jndiContext = new InitialContext(properties); //取得Home对象的引用 Object ref = jndiContext.lookup("HelloWorldHome"); HelloWorldHome home = (HelloWorldHome) ...
JNDI连接数据库配置,Context initCtx = new InitialContext(); Context envCtx = (Context) initCtx.lookup("java:comp/env"); DataSource ds = (DataSource) envCtx.lookup("jdbc/DevDB"); Connection conn = ...
JNDI 注简单来说就是在 JNDI 接在初始化时,如: InitialContext.lookup(URI) ,如果URI 可控,那么客户端就可能会被攻击通过
* 获得与数据库的连接 * * @param path * @return Connection */ public static Connection getConn(String classDriver, String url, String user, String pwd) { try { Class.forName(class...
InitialContext . doLookup( " ldap://your_server.com:1389/o=reference " ); 它将启动从易受攻击的客户端到本地LDAP服务器的连接。 然后,本地服务器使用包含有效载荷之一的恶意条目进行响应,这对于实现远程...
Context ctx = (Context) new InitialContext().lookup("java:comp/env"); DataSource ds = (DataSource) ctx.lookup(jndi); Connection cn = ds.getConnection(); 3>.执行sql语句(Execute the SQL) <1>.用...
使用反射,简单工厂模式实现jdbc数据库操作,支持三种数据库oracle10g,mysql,sqlsever,作了简单的jndi操作,以及xml读取的应用,喜欢反射的同学可以看看
Properties props = new Properties(); props.setProperty("java.naming.factory.initial", "org.jnp.interfaces.NamingContextFactory"); props.setProperty("java.naming.provider.url", "localhost:1099"); ...
数据库操作 采用JNDI 连接 ====================================================== --> <%<br> Context ctx=new InitialContext(); if(ctx==null) {throw new Exception("没有匹配的...
} } } 5、在classPath下增加“jboss-ejb-client.properties”文件,内容如下 remote.connectionprovider.create.options.org.xnio.Options.SSL_ENABLED=false remote.connections=default remote.connection....
initialcontext_general.m,。/ demo_salmatch_cuhk01.m中将“ /”替换为“ ## Demo当前提供了一个演示 demo_salmatch_cuhk01.m:对CUHK01数据集进行评估 ##评论 在CUHK01数据集上,运行demo_salmatch_cuhk01.m...
Java连接数据库相关文档和软件 包括MySQL Front v5.0.Build.1.127特别中文绿色版 mysql-connector-java-5.0.8-bin.jar SQL SERVER jdbc驱动
//JNDI有两个核心接口Context和DirContext, //Context中包含了基本的名字操作,而DirContext则将这些操作扩展到目录服务。 import javax.naming.Context; import javax.naming.InitialContext; //数据库资源的连接...
介绍osgi 轻量级容器,KARAF 。使用
InitialContext ic = new InitialContext(); //动态装入CATALOG_DAO_CLASS //可以定义自己的CATALOG_DAO_CLASS,从而在无需变更太多代码 //的前提下,完成系统的巨大变更。 String className =(String) ...
要知道软件还有一个与建筑截然相反的责任和用途,那就是:现代社会中,计划感不上变化,竞争激烈,所有一切变幻莫测,要应 付所有这些变化,首推信息技术中的软件,只有软件能够帮助人类去应付各种变化.而这点正好与建筑想反...