@Resource 注释在 Tomcat 10.0.10 中不起作用
@Resource annotation doesn't work in Tomact 10.0.10
最近我尝试了 Tomcat 10.0.10 并且在尝试将连接池作为 JNDI 资源注入时发现 @Resource
注释不起作用。
然后我尝试通过创建 InitialContext
以编程方式获取它并且它起作用了。最初我认为它只适用于 java:comp/env/jdbc 所以我尝试使用如下所示的简单 bean 并尝试使用 @Resource
注释注入它它不再起作用。当我尝试通过创建 InitialContext
以编程方式获取它并且它有效时。然后我检查 @PostConstruct
或 @PreDestroy
注释是否有效,发现它们也不起作用。
package lk.ijse.test.tomcatdbcp;
public class Something {
}
<?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>
<?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>
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() {
}
}
为了重现同样的问题,我在此处创建了一个示例存储库:https://github.com/sura-boy-playground/play-with-tomcat10
(可以在那里找到完整的代码)
起初,我使用了 javax.annotation.Resource
注释,所以我认为这是因为 javax.*
到 jakarta.*
命名空间更改的原因。然后我用 jakarta.annotation.Resource
试了一下,但结果是一样的。
我用 Tomcat 9.0.41 加上 javax.*
命名空间尝试了相同的应用程序,它工作得很好。
我需要在 Tomcat 10.0.10 上做任何额外的事情来启用这些注释吗? 我找到了 Tomcat 10 文档但是我找不到与我的问题相关的任何信息。
我发现之前在Tomcat 7 中也有类似的情况,但我现在不喜欢那种解决方法。
Tomcat @Resource annotations API annotation stops working in Tomcat 7
您应该将 jakarta.annotation
依赖项的范围声明为 provided
:
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.0.0</version>
<scope>provided</scope>
</dependency>
如果您有两个 jakarta.annotation.Resource
副本(一个在 common 类加载器中,一个在您应用程序的类加载器中),这两个 类 是不同的。 InstanceManager
将查找使用 common 类加载器的 @Resource
副本注释的字段,而 something
字段使用您的 webapp 的 [=] 副本进行注释15=].
虽然添加范围不同于 provided
的 jakarta.annotation
肯定是一个错误,但这可能是一个常见错误,并且 Tomcat 具有忽略某些 类 与您的应用程序一起分发(参见 source code)。由于 jakarta.annotation.*
类 不在其中,您可以提交(愿望清单)错误报告。
备注: Tomcat 9.0 如果使用Java 11 或更高版本,您将遇到同样的问题。在 Java 11 之前,javax.annotation.*
类 包含在 JRE 中。 Servlet 容器需要在 bootstrap/JRE 类加载器 之前 查看 webapp 类加载器(覆盖 javax.*
类 违反了 Java 的许可),因此 Tomcat 永远不会找到 类.
的附加副本
最近我尝试了 Tomcat 10.0.10 并且在尝试将连接池作为 JNDI 资源注入时发现 @Resource
注释不起作用。
然后我尝试通过创建 InitialContext
以编程方式获取它并且它起作用了。最初我认为它只适用于 java:comp/env/jdbc 所以我尝试使用如下所示的简单 bean 并尝试使用 @Resource
注释注入它它不再起作用。当我尝试通过创建 InitialContext
以编程方式获取它并且它有效时。然后我检查 @PostConstruct
或 @PreDestroy
注释是否有效,发现它们也不起作用。
package lk.ijse.test.tomcatdbcp;
public class Something {
}
<?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>
<?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>
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() {
}
}
为了重现同样的问题,我在此处创建了一个示例存储库:https://github.com/sura-boy-playground/play-with-tomcat10 (可以在那里找到完整的代码)
起初,我使用了 javax.annotation.Resource
注释,所以我认为这是因为 javax.*
到 jakarta.*
命名空间更改的原因。然后我用 jakarta.annotation.Resource
试了一下,但结果是一样的。
我用 Tomcat 9.0.41 加上 javax.*
命名空间尝试了相同的应用程序,它工作得很好。
我需要在 Tomcat 10.0.10 上做任何额外的事情来启用这些注释吗? 我找到了 Tomcat 10 文档但是我找不到与我的问题相关的任何信息。
我发现之前在Tomcat 7 中也有类似的情况,但我现在不喜欢那种解决方法。 Tomcat @Resource annotations API annotation stops working in Tomcat 7
您应该将 jakarta.annotation
依赖项的范围声明为 provided
:
<dependency>
<groupId>jakarta.annotation</groupId>
<artifactId>jakarta.annotation-api</artifactId>
<version>2.0.0</version>
<scope>provided</scope>
</dependency>
如果您有两个 jakarta.annotation.Resource
副本(一个在 common 类加载器中,一个在您应用程序的类加载器中),这两个 类 是不同的。 InstanceManager
将查找使用 common 类加载器的 @Resource
副本注释的字段,而 something
字段使用您的 webapp 的 [=] 副本进行注释15=].
虽然添加范围不同于 provided
的 jakarta.annotation
肯定是一个错误,但这可能是一个常见错误,并且 Tomcat 具有忽略某些 类 与您的应用程序一起分发(参见 source code)。由于 jakarta.annotation.*
类 不在其中,您可以提交(愿望清单)错误报告。
备注: Tomcat 9.0 如果使用Java 11 或更高版本,您将遇到同样的问题。在 Java 11 之前,javax.annotation.*
类 包含在 JRE 中。 Servlet 容器需要在 bootstrap/JRE 类加载器 之前 查看 webapp 类加载器(覆盖 javax.*
类 违反了 Java 的许可),因此 Tomcat 永远不会找到 类.