【问题标题】:How to inject Tomcat Data Source using @Resource in Jakarta-EE project?如何在 Jakarta-EE 项目中使用 @Resource 注入 Tomcat 数据源?
【发布时间】:2020-10-08 19:29:12
【问题描述】:

我正在尝试使用 @Resource 注释从 Tomcat 8.5.56 注入 DataSource,但是当我运行代码时,我得到 NullPointerException。

注意:使用InitialContext 获取DataSource 仍然可以正常工作。

context.xml中的资源定义:

<?xml version="1.0" encoding="UTF-8"?>
<Context>
    <Resource name="jdbc/postgres" auth="Container"
              type="javax.sql.DataSource" driverClassName="org.postgresql.Driver"
              url="jdbc:postgresql://localhost:5432/contact_directory"
              username="username" password="password" maxTotal="20" maxIdle="10"
              maxWaitMillis="-1"/>
</Context>

用于测试的 servlet:

@WebServlet(name = "TestController", urlPatterns = "/test")
public class TestController extends HttpServlet {

//this also doesn't work
//@Resource(lookup="java:/comp/env/jdbc/postgres")

    @Resource(name="jdbc/postgres")
    private DataSource dataSource;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

           String query = "SELECT ... FROM ..."; //here goes the query text

            try(Connection connection= dataSource.getConnection();
                Statement statement=connection.createStatement();
                ResultSet resultSet= statement.executeQuery(query)) {

               //some actions with resultSet

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

错误代码(错误行为Connection connection= dataSource.getConnection()):

java.lang.NullPointerException
    at com.nevermind.controller.TestController.doGet(TestController.java:41)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:543)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
    at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:690)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)
    at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:615)
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65)
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:818)
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1627)
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1130)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:630)
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
    at java.base/java.lang.Thread.run(Thread.java:832)

使用InitialContext 的类可以正常工作:

public class DatabaseUtil {

    public static DataSource getDataSource() {
        DataSource ds=null;
        try {
            InitialContext cxt = new InitialContext();
            ds = (DataSource) cxt.lookup( "java:/comp/env/jdbc/postgres" );

        } catch (NamingException e) {
            e.printStackTrace();
        }
        return ds;
    }

}

注意: 我看过很多指南和类似的问题,但没有具体的解决方案。

一些答案​​有类似的解决方案 (Tomcat 7 Datasource injection mechanism),但在我的情况下,它仍然不起作用。

有人说Tomcat>6不支持@Resource注解(Getting null pointer exception @Resource annotation in tomcat 7),但是下一个回答说支持。

我很困惑可能是什么问题?

【问题讨论】:

  • 你可以使用spring boot吗?是否可以打印您的 InitialContext 示例的 ds 以验证它是否为空?
  • 我成功地使用了@Resource(name = "jdbc/MyDbName") 的Tomcat 8.5.56(在$CATALINA_BASE/conf/context.xml 中有&lt;Resource&gt; 条目)。但是,设置似乎与问题中的设置没有任何不同(除了我使用的是 MySQL)。第 41 行 (TestController.java:41) 的 null 是什么?
  • @AndreiYusupau 经过 2 天的研究,我找到了解决方案。添加我的答案。
  • @AndreiYusupau 添加了我的答案。请检查。
  • 在 context.xml 中拥有资源是不够的。您需要在您的web.xml 中有一个resource-ref

标签: java postgresql tomcat jakarta-ee


【解决方案1】:

我也遇到了同样的问题。

经过两天的严格研究,我终于得到了解决方案。

我尝试使用 Tomcat 7.0.104PostgresSQL 12JDK 8


注意: 您可以使用任何tomcat版本,注入与tomcat版本无关,您需要对特定的DI框架进行适当的配置,以便它可以注入外部数据源,如 tomcat 数据源。

@Bozho 在这个问题上是对的:Getting null pointer exception @Resource annotation in tomcat 7

你需要依赖注入框架来进行注入。为了使依赖注入能够正常工作,您需要配置框架以使其能够找到该特定资源。


现在,来回答:

你需要在 tomcat 中更新的东西。

context.xml:

<?xml version="1.0" encoding="UTF-8"?>
<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor 
    license agreements. See the NOTICE file distributed with this work for additional 
    information regarding copyright ownership. The ASF licenses this file to 
    You under the Apache License, Version 2.0 (the "License"); you may not use 
    this file except in compliance with the License. You may obtain a copy of 
    the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required 
    by applicable law or agreed to in writing, software distributed under the 
    License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS 
    OF ANY KIND, either express or implied. See the License for the specific 
    language governing permissions and limitations under the License. --><!-- The contents of this file will be loaded for each web application -->
<Context>

    <!-- Default set of monitored resources -->
    <WatchedResource>WEB-INF/web.xml</WatchedResource>
    
    <Resource auth="Container"
            driverClassName="org.postgresql.Driver" maxActive="20" maxIdle="10"
            maxWait="-1" name="jdbc/postgres" password="" type="javax.sql.DataSource"
            url="jdbc:postgresql://localhost:5432/demo" username="anish" />

    <!-- Uncomment this to disable session persistence across Tomcat restarts -->
    <!-- <Manager pathname="" /> -->

    <!-- Uncomment this to enable Comet connection tacking (provides events 
        on session expiration as well as webapp lifecycle) -->
    <!-- <Valve className="org.apache.catalina.valves.CometConnectionManagerValve" 
        /> -->

</Context>

您需要更新项目的 web.xml(通过引用您在 context.xml 中创建的数据源):

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd"
    version="3.1">
    <display-name>Archetype Created Web Application</display-name>
    <resource-ref>
        <description>Test</description>
        <res-ref-name>jdbc/postgres</res-ref-name>
        <res-type>javax.sql.DataSource</res-type>
        <res-auth>Container</res-auth>
    </resource-ref>
</web-app>
    

TestController 类:

package com.example;

import java.io.IOException;
import java.sql.Connection;
import java.sql.SQLException;

import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sql.DataSource;

    @WebServlet(name = "TestController", urlPatterns = "/test")
    public class TestController extends HttpServlet {
    
        private static final long serialVersionUID = 1L;
    
        @Resource(name = "jdbc/postgres")
        private DataSource dataSource;
    
        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
    
            try (Connection connection = dataSource.getConnection();) {
                System.out.println(connection.getAutoCommit());
            } catch (SQLException e) {
                e.printStackTrace();
            }
    
        }
    
    }

成功日志:

Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server version name:   Apache Tomcat/7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server built:          May 7 2020 19:31:18 UTC
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Server version number: 7.0.104.0
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Name:               Mac OS X
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: OS Version:            10.15.4
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Architecture:          x86_64
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Java Home:             /Library/Java/JavaVirtualMachines/jdk1.8.0_231.jdk/Contents/Home/jre
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Version:           1.8.0_231-b11
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: JVM Vendor:            Oracle Corporation
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: CATALINA_BASE:         /Volumes/Local Disk/STS-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: CATALINA_HOME:         /Users/anish/Downloads/apache-tomcat-7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcatalina.base=/Volumes/Local Disk/STS-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dcatalina.home=/Users/anish/Downloads/apache-tomcat-7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dwtp.deploy=/Volumes/Local Disk/STS-workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Djava.endorsed.dirs=/Users/anish/Downloads/apache-tomcat-7.0.104/endorsed
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.VersionLoggerListener log
INFO: Command line argument: -Dfile.encoding=UTF-8
Jun 26, 2020 10:10:19 AM org.apache.catalina.core.AprLifecycleListener lifecycleEvent
INFO: The Apache Tomcat Native library which allows using OpenSSL was not found on the java.library.path: [/Users/anish/Library/Java/Extensions:/Library/Java/Extensions:/Network/Library/Java/Extensions:/System/Library/Java/Extensions:/usr/lib/java:.]
Jun 26, 2020 10:10:19 AM org.apache.coyote.AbstractProtocol init
INFO: Initializing ProtocolHandler ["http-bio-8080"]
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.Catalina load
INFO: Initialization processed in 413 ms
Jun 26, 2020 10:10:19 AM org.apache.catalina.core.StandardService startInternal
INFO: Starting service [Catalina]
Jun 26, 2020 10:10:19 AM org.apache.catalina.core.StandardEngine startInternal
INFO: Starting Servlet Engine: Apache Tomcat/7.0.104
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jun 26, 2020 10:10:19 AM org.apache.catalina.deploy.WebXml setVersion
WARNING: Unknown version string [3.1]. Default version will be used.
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.TldConfig execute
INFO: At least one JAR was scanned for TLDs yet contained no TLDs. Enable debug logging for this logger for a complete list of JARs that were scanned but no TLDs were found in them. Skipping unneeded JARs during scanning can improve startup time and JSP compilation time.
Jun 26, 2020 10:10:19 AM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-bio-8080"]
Jun 26, 2020 10:10:19 AM org.apache.catalina.startup.Catalina start
INFO: Server startup in 341 ms

当您访问此http://localhost:8080/sample-ds-test/test url 时,它会给出消息true,这将表明数据源已正确加载。

这将为您顺利工作。

我用于测试的 Github 存储库:

(只需更改数据库名称,用户名,密码)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-03-02
    • 2021-01-19
    • 2021-03-03
    • 1970-01-01
    • 2023-02-23
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多