gpt4 book ai didi

java - @资源错误: "Naming binding already exists for foo.NewServlet/userName in namespace"

转载 作者:行者123 更新时间:2023-11-30 10:26:27 25 4
gpt4 key购买 nike

我正在考虑使用 servlet 3.0+ 容器中可用的“@Resource String ...”注入(inject)来轻松地为 servlet 提供配置参数。如果 JNDI 中不存在该 key (表示配置错误),我希望默认值起作用并失败

我在 Netbeans 8.2 和 Glassfish 4.1.1 中玩过一个简单的 servlet,我想在其中设置 userName 字段和 setFullName(String fullName) 集:

package foo;

import java.io.IOException;
import java.io.PrintWriter;
import javax.annotation.Resource;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.annotation.WebInitParam;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@WebServlet(name = "NewServlet", urlPatterns = {"/NewServlet"})
public class NewServlet extends HttpServlet {

@Resource(description="user name")
String userName;

private String fullname;

@Resource()
public void setFullName(String fullName){
this.fullname = fullName;
}

protected void processRequest(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
try (PrintWriter out = response.getWriter()) {
/* TODO output your page here. You may use following sample code. */
out.println("<!DOCTYPE html>");
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet NewServlet</title>");
out.println("</head>");
out.println("<body>");
out.println("Full name = " + fullname);
out.println("<h1>Servlet NewServlet at " + request.getContextPath() + "</h1>");
out.println("Username = " + userName);
out.println("</body>");
out.println("</html>");


}
}
// Autogenerated stuff omitted
}

如果没有“web.xml”,字段就为空(也没有失败)。然后我研究了“web.xml”以了解如何定义它。 “java:comp/env/foo:NewServlet/fullName”名称是 Glassfish 4.1.1 似乎为 fullName setter 创建的名称。

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<env-entry >
<env-entry-name>java:comp/env/foo.NewServlet/fullName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>!BAR!</env-entry-value>
</env-entry>
<env-entry >
<env-entry-name>java:comp/env/foo.NewServlet/userName</env-entry-name>
<env-entry-type>java.lang.String</env-entry-type>
<env-entry-value>!USERNAME!</env-entry-value>
</env-entry>
</web-app>

然后失败了

Severe:   Exception while deploying the app [WebApplication4] : Naming binding already exists for foo.NewServlet/userName in namespace {java:module/env/foo.NewServlet/userName=Env-Prop: java:comp/env/foo.NewServlet/userName@Non-Injectable Resource@java.lang.String@!USERNAME!@@, java:module/env/foo.NewServlet/fullName=Env-Prop: java:comp/env/foo.NewServlet/fullName@Non-Injectable Resource@java.lang.String@!BAR!@@}

项目中除了这两个文件外,没有别的了。显然我误解了一些基本的东西,但是阅读 Java EE 教程和寻找建议对我没有帮助。我真的很想要两件事:

  1. 要么不使用容器生成的默认值向@Resource-tag 提供任何提示,要么只提供像“our.application.fullName”这样的键。
  2. 如果有任何错误,包括键值不存在,请大声宣告失败。

建议?一个好的答案将给予 500 点赏金。

最佳答案

你真的只错过了两个重要的细节:

  1. 在部署描述符(例如 web.xml)中指定资源名称时,无论是 env-entry-nameresource-env- ref-nameejb-ref-name 等,JNDI 名称的 java:comp/env 部分总是隐式。因此,如果您希望由 env-entry 定义的资源出现在 JNDI 的 java:comp/env/foo 处,那么您指定它的 env-entry -名称为:

         <env-entry-name>foo</env-entry-name>
  2. Java EE 规范 (§EE.5.2.5) 修改了应用于 @Resource 注释的“默认”名称的规则:

    A field of a class may be the target of injection. The field must not be final. By default, the name of the field is combined with the fully qualified name of the class and used directly as the name in the application component’s naming context. For example, a field named myDatabase in the class MyApp in the package com.example would correspond to the JNDI name java:comp/env/ com.example.MyApp/myDatabase. The annotation also allows the JNDI name to be specified explicitly. When a deployment descriptor entry is used to specify injection, the JNDI name and the field name are both specified explicitly. Note that, by default, the JNDI name is relative to the java:comp/env naming context.

    换句话说,如果您的 servlet 的完全限定名称是 com.p45709634.NewServlet,那么 userName 字段的 JNDI 名称将是 java:comp/env/com.p45709634.NewServlet/用户名。因此它的 env-entry-name 将是:

         <env-entry-name>com.p45709634.NewServlet/userName</env-entry-name>

因此,如果您在 web.xml 文件中使用这些完全限定的名称,那么您可以愉快地按照您的要求声明带注释的字段:

    @Resource
private String userName;

private String fullname;

@Resource
public void setFullName(String fullName){
this.fullname = fullName;
}

现在规范的同一章指出:

If the container fails to find a resource needed for injection, initialization of the class must fail, and the class must not be put into service.

然而,这似乎并没有在实践中发生(至少在 GlassFish 上对你来说是这样,对我来说是 WildFly 上)。这可能是由于对注入(inject)的 CDI 规范有一些延迟,这似乎没有太多关于无法定位注入(inject)资源的说法。

因此,我们可能无法在 init 方法或 @PostConstruct 注释方法中验证这些字段。

关于java - @资源错误: "Naming binding already exists for foo.NewServlet/userName in namespace",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45709634/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com