Tomcat:如何在GlobalNamingResources中以编程方式定义数据源资源并将其链接到应用程序

问题描述 投票:0回答:1

我正在使用Tomcat9部署共享相同数据源连接池的多个应用程序。我通过以下方式达到了目的:

  1. 将数据源作为资源元素添加到conf / server.xml中的GlobalNamingResources下,
  2. 使用conf / context.xml中的ResourceLink元素来链接全局JNDI资源以使其可用于所有Web应用程序,和
  3. 从Web应用程序使用JNDI访问数据源。

它正在按预期方式工作。

但是我有一个要求避免编辑任何xml(server.xml或conf / context.xml或应用程序特定的context.xml),并尝试以编程方式实现步骤1和2。如果是这样,好处是,只需修改需要添加到/ lib中的jar即可支持新的数据源,而无需对任何xml进行任何修改(或者可以在server.xml中进行最小配置)。

是否有任何方法可以满足将资源定义为GlobalNamingResources并将其通过ResourceLink(全部通过Java链接到Web应用程序)的要求?

tomcat datasource tomcat9
1个回答
0
投票

经过tomcat javadocs后,我已经达到了我的要求。下面给出详细信息:

1。将数据源添加为GlobalNamingResource

为此,创建服务器生命周期侦听器,创建数据源并将其添加到JNDI GlobalNamingContext。

public class GlobalDatasourceCreator implements LifecycleListener {
    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if (event.getSource() instanceof Server) {
            Context namingContext = ((Server) event.getSource()).getGlobalNamingContext();
            if (Lifecycle.START_EVENT.equals(event.getType())) {
                bindDatasources(namingContext);
            } else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
                unbindDatasources(namingContext);
            }
        }
    } 

    private void bindDatasources(Context namingContext) {
        if (createSubContext(namingContext)) {
            try {
                DataSource ds = getDatasource(); //TODO: Implement it 
                namingContext.rebind("jdbc/myds_global", ds);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    private boolean createSubContext(Context namingContext) {
        try {
            namingContext.createSubcontext("jdbc");
        } catch (NameAlreadyBoundException e) {
        } catch (NamingException e) {
            return false;
        }
        return true;
    }

    private void unbindDatasources(Context namingContext) {
        try {
            namingContext.unbind("jdbc/myds_global");
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

然后将此类作为侦听器添加到conf / server.xml中>]

<Listener className="com.oracle.acs.gateway.ds.GlobalDatasourceCreator" />

2。通过ResourceLink将数据源公开给所有Web应用程序

创建上下文LifecycleListener。在START事件上,创建ResourceLink并将其附加到上下文。

注意:由于这是上下文级别的侦听器,因此将为所有应用程序创建ResourceLink。我的要求是将其公开给所有应用程序,因为它是受控环境。如果仅需要为选定的应用程序创建ResourceLink,则可以应用基于上下文名称的过滤。

public class AppDatasourceLinkCreator implements LifecycleListener {

    @Override
    public void lifecycleEvent(LifecycleEvent event) {
        if (event.getSource() instanceof Context) {
            Context ctx = (Context) event.getSource();
            if (Lifecycle.START_EVENT.equals(event.getType())) {
                addResourceLink(ctx);
            } else if (Lifecycle.STOP_EVENT.equals(event.getType())) {
                removeResourceLink(ctx);
            }
        } 
    }

    private void removeResourceLink(Context ctx) {
        ctx.getNamingResources().removeResourceLink("jdbc/myds");
    }

    private void addResourceLink(Context ctx) {
        ContextResourceLink resourceLink = new ContextResourceLink();
        resourceLink.setGlobal("jdbc/myds_global");
        resourceLink.setName("jdbc/myds");
        resourceLink.setType("javax.sql.DataSource");
        ctx.getNamingResources().addResourceLink(resourceLink);
    }
}

然后将此类作为侦听器添加到conf / context.xml

中>]
<Listener className="com.oracle.acs.gateway.ds.AppDatasourceLinkCreator" />

创建包含这两个类的jar并将其放置在/ lib文件夹中。

Advantage:

不需要进一步的xml修改即可添加任何数量的数据源。只需修改Java代码以添加新的数据源,更新lib文件夹中的jar并重新启动服务器,即可完全满足我的项目要求。这也解决了将数据源凭据以xml的纯文本格式公开的问题(尽管不是100%的风险证明)。
© www.soinside.com 2019 - 2024. All rights reserved.