探索创建InitialContext过程

在使用InitialContext去获取jboss中Ejb对象的时候,总会看到这样的语句:

Hashtable c = new Hashtable();
		c.put("java.naming.provider.url", url);
		c.put("java.naming.factory.initial",
				"org.jnp.interfaces.NamingContextFactory");
		c.put("java.naming.factory.url.pkgs",
				"org.jboss.naming:org.jnp.interfaces");
		cxt = new InitialContext(c)

我就在想,这些HashTable里面的东西有什么用,经过对jdk源码和jboss源码的阅读,发现原来

这三个都是Context接口中的三个常量

 String INITIAL_CONTEXT_FACTORY = "java.naming.factory.initial";
 String PROVIDER_URL = "java.naming.provider.url";
  String URL_PKG_PREFIXES = "java.naming.factory.url.pkgs";

INITIAL_CONTEXT_FACTORY 该常量保存用来指定要使用的初始上下文工厂的环境属性名称。该属性的值应该是将创建初始上下文的工厂类的完全限定类名称。此属性可以在传递给初始上下文构造方法的环境参数、applet 参数、系统属性或应用程序资源文件中指定。如果没有在任何这些源中指定该属性,则在需要初始上下文完成某项操作时将抛出NoInitialContextException

PROVIDER_URL该常量保存用来指定要使用的服务提供者配置信息的环境属性名称。该属性的值应该包含一个 URL 字符串(例如 "ldap://somehost:389")。此属性可以在环境、applet 参数、系统属性或资源文件中指定。如果没有在任何这些源中指定该属性,则由服务提供者确定默认配置

URL_PKG_PREFIXES该常量保存用来指定加载 URL 上下文工厂时要使用的包前缀列表的环境属性名称。该属性的值应该是工厂类名称以冒号分隔的包前缀列表,该工厂类将创建一个 URL 上下文工厂。此属性可以在环境、applet 参数、系统属性或者一个或多个资源文件中指定。前缀com.sun.jndi.url 总是被追加到可能为空的包前缀列表中


那么上下文到底是怎么初始化的呢,源码如下
    public InitialContext(Hashtable environment)
	throws NamingException
    {
	if (environment != null) {
	    environment = (Hashtable)environment.clone();
	}
	init(environment);
    }

在创建对象的时候,会去初始化上下文的环境属性


    protected void init(Hashtable environment)
	throws NamingException
    {
	myProps = ResourceManager.getInitialEnvironment(environment);

	if (myProps.get(Context.INITIAL_CONTEXT_FACTORY) != null) {
	    // user has specified initial context factory; try to get it
	    getDefaultInitCtx();
	}
    }

myProps = ResourceManager.getInitialEnvironment(environment);这一行是通过最开始的环境属性来获取新的属性,获取如果Hashtable中如果没有的话,就会从classPath中去读取


接下来就是getDefaultInitCtx方法
protected Context getDefaultInitCtx() throws NamingException{
	if (!gotDefault) {
	    defaultInitCtx = NamingManager.getInitialContext(myProps);
	    gotDefault = true;
	}
	if (defaultInitCtx == null)
	    throw new NoInitialContextException();

	return defaultInitCtx;
    }
 public static Context getInitialContext(Hashtable env)
	throws NamingException {
	InitialContextFactory factory; 


	InitialContextFactoryBuilder builder = getInitialContextFactoryBuilder();
	if (builder == null) {
	    // No factory installed, use property
	    // Get initial context factory class name


	    String className = env != null ?
	        (String)env.get(Context.INITIAL_CONTEXT_FACTORY) : null;
	    if (className == null) {
		NoInitialContextException ne = new NoInitialContextException(
		    "Need to specify class name in environment or system " +
		    "property, or as an applet parameter, or in an " +
		    "application resource file:  " + 
		    Context.INITIAL_CONTEXT_FACTORY);
		throw ne;
	    }


	    try {
		factory = (InitialContextFactory)
		    helper.loadClass(className).newInstance();
	    } catch(Exception e) {
		NoInitialContextException ne = 
		    new NoInitialContextException(
			"Cannot instantiate class: " + className);
		ne.setRootCause(e);
		throw ne;
	    }
	} else {
	    factory = builder.createInitialContextFactory(env);
	}


	return factory.getInitialContext(env);
    }
  private static InitialContextFactoryBuilder initctx_factory_builder = null;
  private static synchronized InitialContextFactoryBuilder
    getInitialContextFactoryBuilder() {
	return initctx_factory_builder;
    }

由源码可知java在创建InitialContext的时候,还会去加载一个默认的上下文,也就是这里的defaultInitCtx,而这个上下文才是真正的上下文,也就是说InitialContext中的方法其实是调用的这个默认上下文的方法。创建时根据开始设置的Hashtable中的环境属性,利用类加载和反射机制去创建一个上下文工厂的实现类,如果环境属性中没有相应的上下工厂的实现类的参数的话,就会抛出NoInitialContextException的异常。当有了这个工厂的实现类才能创建出这个真正的上下文,而这个的实现类由第三方提供实现,以jboss为例,这个工厂正是HashTable中c.put("java.naming.factory.initial",    "org.jnp.interfaces.NamingContextFactory"),也就是对应于jboss中的org.jnp.interfaces.NamingContextFactory这个工厂类,最后调用NamingContextFactory的getInitialContext方法创建出一个NamingContext的实例,其代码
 public Context getInitialContext(Hashtable env) 
      throws NamingException
    {
        String providerURL = (String) env.get(Context.PROVIDER_URL);
        Name prefix = null;
        /** This may be a comma separated list of provider urls in which
          case we do not parse the urls for the requested context prefix name
        */
        int comma = providerURL != null ? providerURL.indexOf(',') : -1;
        if( providerURL != null && comma < 0 )
        {
            Name name = new CompoundName(providerURL, NamingParser.syntax);
            String serverInfo = NamingContext.parseNameForScheme(name, env);
            if( serverInfo != null )
            {
               env = (Hashtable) env.clone();
               // Set hostname:port value for the naming server
               env.put(Context.PROVIDER_URL, serverInfo);
               // Set the context prefix to name
               Name parsedName = (Name) env.get(NamingContext.JNP_PARSED_NAME);
               if( parsedName != null )
                  prefix = parsedName;
               else
                  prefix = name;
            }
        }
        return new NamingContext(env, prefix, null);
    }
也就是说,jboss最后创建一个NamingContext对象,供InitialContext调用




你可能感兴趣的:(java,笔记)