mybatis 连接JNDI源码解析

本文深入解析了MyBatis中JNDI数据源工厂的配置与实现原理,介绍了如何通过mybatis-config.xml配置文件设置initial_context和data_source属性,以实现与服务器JNDI目录的连接,并探讨了两种配置方式的区别。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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的过程中收集<dataSource>标签下属性建立
            // 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<Object, Object> 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;
    }

}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值