mybatis 连接JNDI源码解析

public class JndiDataSourceFactory implements DataSourceFactory {
    /**
     * initial_context: 服务器的JNDI目录,不同的服务器该值不同,因此需要在mybatis-config的配置文件中传入该值
     * data_source:对应着META-INF/context.xml中注册的服务名称(name属性值),即键值对中的键值
     */
    public static final String INITIAL_CONTEXT = "initial_context";
    public static final String DATA_SOURCE = "data_source";
    public static final String ENV_PREFIX = "env.";
    private DataSource dataSource;
    /**
     * 该方法在初始化Mybatis的时候被调用,会将mybatis-config.xml中配置的属性注入进来
     * 主要注入的是initial_context和data_source的值
     */
    public void setProperties(Properties properties) {
        /**
         * 参照tomcat直接获取JNDI服务
         * -------------------------
         * 第一步:Context initContext = new InitialContext();
         * 第二步:Context envContext = (Context) initContext.lookup("java:/comp/env");
         * 第三步:DataSource ds = (DataSource) envContext.lookup("jdbc/mybatis-jndi");
         */
        try {
            //第一步:声明JAVA命名和目录接口的上下文类
            InitialContext initCtx = null;
            // properties在SqlSessionFactoryBuilder创建SqlSessionFactory的过程中收集标签下属性建立
            // env不为null的条件是在mybatis-config.xml中配置的JNDI属性以"env."开头
            // 其实不必要以"env."开头,在getEnvProperties方法中最终也会去掉"env."
            Properties env = getEnvProperties(properties);
            if (env == null) {
                // 进入到这个流程,默认使用SqlSessionFactoryBuilder流程中的properties
                initCtx = new InitialContext();
            } else {
                // 如果配置文件中配置的JNDI属性以"env."开头,则进入这个步骤
                // 实际上有些冗余,鸡肋没有必要
                initCtx = new InitialContext(env);
            }
            /**
             * mybatis-config.xml中有两种方式可以进行JNDI数据源的配置
             * 1. 第一种方式需要配置initial_context和data_source的值,本例中
             *      initial_context="java:/comp/env"
             *      data_source="jdbc/mybatis-jndi"
             * 2. 第二种方式只需要配置data_source的值
             *      data_source="java:/comp/env/jdbc/mybatis-jndi"
             * 
             * 结论:其实是一样的,请结合context.xml配置文件内容查看此处
             */
            if (properties.containsKey(INITIAL_CONTEXT)
                    && properties.containsKey(DATA_SOURCE)) {
                //第一种方式
                Context ctx = (Context) initCtx.lookup(properties
                        .getProperty(INITIAL_CONTEXT));
                dataSource = (DataSource) ctx.lookup(properties
                        .getProperty(DATA_SOURCE));
            } else if (properties.containsKey(DATA_SOURCE)) {
                //第二种方式
                dataSource = (DataSource) initCtx.lookup(properties
                        .getProperty(DATA_SOURCE));
            }

        } catch (NamingException e) {
            throw new DataSourceException(
                    "There was an error configuring JndiDataSourceTransactionPool. Cause: " + e, e);
        }
    }
    /**
     * 直接返回数据源
     *      因为数据源交由服务器托管,因此mybatis不需要再像pooled类型那样自己实现连接池并通过动态代理增强java.sql.Connection
     */
    public DataSource getDataSource() {
        return dataSource;
    }

    // 如果配置文件中配置的JNDI属性以"env."开头,那么就新建一个properties
    // 最后再把"evn."去掉放入properties中
    // 现在两个properties一模一样了,只是构造InitalContext的时候不同
    // 这个感觉是比较鸡肋的方法,也许是javax.naming中有优化吧
    private static Properties getEnvProperties(Properties allProps) {
        final String PREFIX = ENV_PREFIX;
        Properties contextProperties = null;
        for (Entry entry : allProps.entrySet()) {
            String key = (String) entry.getKey();
            String value = (String) entry.getValue();
            if (key.startsWith(PREFIX)) {
                if (contextProperties == null) {
                    contextProperties = new Properties();
                }
                contextProperties.put(key.substring(PREFIX.length()), value);
            }
        }
        return contextProperties;
    }

}

 

你可能感兴趣的:(Mybatis)