@Resource 注释在 Tomact 10.0.10 中不起作用

Ran*_*nga 6 java tomcat servlets jakarta-ee

最近我尝试了 Tomcat 10.0.10,当尝试将连接池作为 JNDI 资源注入时,发现注释@Resource不起作用。

然后我尝试通过创建 a 以编程方式获取它InitialContext并且它起作用了。最初我认为它仅适用于 java:comp/env/jdbc 所以我尝试使用如下所示的简单 bean 并尝试使用注释注入它,但@Resource它再次不起作用。当我尝试通过创建 a 以编程方式获取它时InitialContext,它起作用了。然后我检查@PostConstruct@PreDestroy注释是否有效,发现它们也不起作用。

package lk.ijse.test.tomcatdbcp;
    
public class Something {
}
Run Code Online (Sandbox Code Playgroud)
<?xml version="1.0" encoding="UTF-8"?>
<Context>

    <Resource name="bean/Something" auth="Container"
              type="lk.ijse.test.tomcatdbcp.Something"
              factory="org.apache.naming.factory.BeanFactory"
              />

</Context>
Run Code Online (Sandbox Code Playgroud)
<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="false" xmlns="https://jakarta.ee/xml/ns/jakartaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_5_0.xsd"
         version="5.0">

    <resource-env-ref>
        <resource-env-ref-name>bean/Something</resource-env-ref-name>
        <resource-env-ref-type>lk.ijse.test.tomcatdbcp.Something</resource-env-ref-type>
    </resource-env-ref>
</web-app>
Run Code Online (Sandbox Code Playgroud)
package lk.ijse.test.tomcatdbcp;

import java.io.*;

import jakarta.annotation.PostConstruct;
import jakarta.annotation.Resource;
import jakarta.servlet.http.*;
import jakarta.servlet.annotation.*;

import javax.naming.InitialContext;
import javax.naming.NamingException;

@WebServlet(name = "helloServlet", value = "/hello", loadOnStartup = 1)
public class HelloServlet extends HttpServlet {
    private String message;

    @Resource(name= "java:comp/env/bean/Something")
    private Something something;

    @PostConstruct
    public void doSomething(){
        System.out.println("Does it work?");
    }

    public void init() {
        message = "Hello World!";
        try {
            InitialContext ctx = new InitialContext();
            Something lookup = (Something) ctx.lookup("java:comp/env/bean/Something");
            System.out.println(lookup);
            System.out.println(something); // null
        } catch (NamingException e) {
            e.printStackTrace();
        }
    }

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
        response.setContentType("text/html");

        // Hello
        PrintWriter out = response.getWriter();
        out.println("<html><body>");
        out.println("<h1>" + message + "</h1>");
        out.println("</body></html>");
    }

    public void destroy() {
    }
}
Run Code Online (Sandbox Code Playgroud)

为了重现相同的问题,我在这里创建了一个示例存储库: https: //github.com/sura-boy-playground/play-with-tomcat10 (可以在那里找到完整的代码)

起初,我使用了javax.annotation.Resource注释,所以我认为这是因为javax.*tojakarta.*命名空间更改的原因。然后我尝试了一下,jakarta.annotation.Resource但结果是一样的。

我尝试使用 Tomcat 9.0.41 加命名空间来执行相同的应用程序javax.*,它运行得很好。

我需要在 Tomcat 10.0.10 上执行任何额外操作才能启用这些注释吗?我翻阅了 Tomcat 10 文档,但无法找到与我的问题相关的任何内容。

我发现之前 Tomcat 7 中也有类似的情况,但我现在不喜欢这种解决方法。 Tomcat @Resource 注释 API 注释在 Tomcat 7 中停止工作

Pio*_*asz 4

您应该将依赖范围声明jakarta.annotationprovided

<dependency>
    <groupId>jakarta.annotation</groupId>
    <artifactId>jakarta.annotation-api</artifactId>
    <version>2.0.0</version>
    <scope>provided</scope>
</dependency>
Run Code Online (Sandbox Code Playgroud)

如果您有两份副本jakarta.annotation.Resource(一份在公共类加载器中,一份在应用程序的类加载器中),则这两个类是不同的。将InstanceManager查找用公共类加载器的 副本注释的字段@Resource,而该something字段用您的 web 应用程序的 副本注释@Resource

编辑:此问题已在 Tomcat 10.0.17(参见变更日志)、9.0.59 和 10.1.0-M11中修复。

备注:如果使用 Java 11 或更高版本,在 Tomcat 9.0 中也会遇到同样的问题。在 Java 11 之前,这些javax.annotation.*类包含在 JRE 中。Servlet 容器需要在查看webapp 类加载器之前先查看bootstrap/JRE类加载器(覆盖类违反了 Java 的许可),因此 Tomcat 永远不会找到这些类的附加副本。javax.*