Как внедрить источник данных Tomcat с помощью @Resource в проекте Jakarta-EE? - PullRequest
5 голосов
/ 18 июня 2020

Я пытаюсь ввести DataSource из Tomcat 8.5.56 с помощью аннотации @Resource, но когда я запускаю код, я получаю NullPointerException.

Примечание : Получение DataSource с InitialContext по-прежнему работает нормально.

Определение ресурса в 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>

Сервлет для тестирования:

@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 инъекционный механизм ), но в в моем случае он все еще не работает.

Кто-то сказал, что Tomcat> 6 не поддерживает аннотацию @Resource ( Получение исключения нулевого указателя @Resource аннотации в tomcat 7 ), но следующий ответ говорит, что поддерживает.

Я не понимаю, в чем может быть проблема?

1 Ответ

0 голосов
/ 26 июня 2020

Я тоже столкнулся с той же проблемой.

Наконец, я получил решение после двух дней тщательных исследований.

Я пробовал с Tomcat 7.0.104 , PostgresSQL 12 и JDK 8 .

Примечание: Вы можете использовать любую версию tomcat, и инъекция не имеет ничего общего с версией tomcat, вам необходимо выполнить правильную конфигурацию для конкретной структуры DI, чтобы она могла ввести внешний источник данных, такой как источник данных tomcat.

@ Bozho был прав на этот вопрос: Получение исключения нулевого указателя @Resource аннотации в 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>

Вам необходимо обновить веб-сайт проекта. xml (со ссылкой на источник данных, который вы создали в контексте. 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, которое будет означать, что источник данных загружен правильно.

enter image description here

This will work for you smoothly.

My Github repo for testing :

(просто измените имя базы данных, имя пользователя, пароль)

...