我使用Tomcat 6.0.26-6.0.35已经使用了JSF 2 Mojarra多年,各种版本高达2.1.2,我已经使用了几个月。我有几个请求范围和会话范围的bean,代码如下:
private @Resource(name="jdbc/cLabs", mappedName="jdbc/cLabs") DataSource cLabs;
已在我使用的每个Tomcat 6版本中正确注入。我也有其他类型的@Resource
也不起作用,所以它不仅仅是DataSource resources.
我尝试过切换到Tomcat 7.0.27而且突然间这些构造都不再有效。资源未注入。我还有其他类型的@Resource
也不起作用,所以它不仅仅是DataSource
资源。但是,在每种情况下,名为的资源确实存在,并且可以通过例如查找。
new InitialContext().lookup("java:comp/env/jdbc/cLabs");
[它们由context.xml中的元素定义]
这当然是皇家PITA,因为我花了一两年时间用前者替换后者。是否还有其他魔法咒语我必须与Tomcat 7编织才能让它再次运作?
请注意,资源 正确地注入到Servlet中,所以它并没有完全被破坏。 Tomcat和JSF之间的一些交互。
答案 0 :(得分:2)
我的猜测是导致org.apache.catalina.core.DefaultInstanceManager忽略注释,因为faces要求@PostConstruct方法与@Resource字段分开处理。我创建了一个适用于使用@Resource注释的字段的解决方法。
将以下内容添加到web.xml:
<context-param>
<param-name>com.sun.faces.injectionProvider</param-name>
<param-value>com.example.faces.Tomcat7InjectionProvider</param-value>
</context-param>
并将该类添加到您的来源:
package com.example.faces;
import java.lang.reflect.Field;
import javax.annotation.Resource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.servlet.ServletContext;
import org.apache.catalina.util.Introspection;
import com.sun.faces.spi.InjectionProviderException;
import com.sun.faces.vendor.WebContainerInjectionProvider;
public class Tomcat7InjectionProvider extends WebContainerInjectionProvider {
public Tomcat7InjectionProvider(ServletContext servletContext) {
}
@Override
public void inject(Object managedBean) throws InjectionProviderException {
if (managedBean != null) {
// see org.apache.catalina.core.DefaultInstanceManager
Field[] fields = Introspection.getDeclaredFields(managedBean.getClass());
for (Field field : fields) {
// field may be private
field.setAccessible(true);
if (field.isAnnotationPresent(Resource.class)) {
Resource annotation = null;
try {
annotation = field.getAnnotation(Resource.class);
Context ctx = new InitialContext();
Object resource = ctx.lookup("java:comp/env/" + annotation.name());
field.set(managedBean, resource);
} catch (Exception e) {
throw new InjectionProviderException("cannot find resource " + annotation.name(), e);
}
}
}
}
}
}
答案 1 :(得分:1)
回答我自己的问题,@ JeffE答案的改进版本。基本问题是:
Tomcat6InjectionProvider
随JSF 2.0提供,但在某些时候删除了。WebContainerInjectionProvider
不处理@Resource注释,正如JeffE指出的那样。您可以在没有web.xml
上下文条目的情况下解决此问题,如下所示:
创建一个名为META-INF/services/com.sun.faces.spi.injectionprovider
的文件,并在其中添加以下行:
com.sun.faces.vendor.Tomcat7InjectionProvider:org.apache.catalina.core.DefaultInstanceManager
这一行的含义是,如果部署中存在第二个类,则第一个类用作注入提供者。上面的第二节是Tomcat 7的一部分。
编译以下课程。
此版本包含对JeffE版本的众多改进。具体做法是:
@Resource
和@Resources
Javadoc @Resource
和@Resources
注释@Resource
Javadoc @Resource
注释的方法
name
Javadoc @Resource
个@Resource
个空的Field
属性
package com.sun.faces.vendor;
import com.sun.faces.spi.DiscoverableInjectionProvider;
import com.sun.faces.spi.InjectionProviderException;
import java.lang.reflect.Field;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Resource;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.servlet.ServletContext;
/**
* @author Jeff E
* @author Esmond Pitt Improvements named above.
*
* @see javax.annotation.Resource
*
* @see <a href="http://stackoverflow.com/a/21978577/207421">This StackOverflow
* answer, although what org.apache.catalina.util.Introspection may be and where
* it lives remains a mystery.</a>
*/
public class Tomcat7InjectionProvider
extends DiscoverableInjectionProvider
{
private Logger logger = Logger.getLogger(this.getClass().getName());
private ServletContext servletContext;
private WebContainerInjectionProvider delegate = new WebContainerInjectionProvider();
public Tomcat7InjectionProvider(ServletContext servletContext)
{
logger.config("constructed");
this.servletContext = servletContext;
}
@Override
public void inject(Object managedBean) throws InjectionProviderException
{
logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean.getClass().getName()});
Class<?> clazz = managedBean.getClass();
do
{
List<Resource> classResources = new LinkedList<>();
// Process class-level @Resources and @Resource
if (clazz.isAnnotationPresent(Resources.class))
{
Resources annotation = clazz.getAnnotation(Resources.class);
for (Resource resource : annotation.value())
{
classResources.add(resource);
}
}
if (clazz.isAnnotationPresent(Resource.class))
{
Resource annotation = clazz.getAnnotation(Resource.class);
classResources.add(annotation);
}
for (Resource annotation : classResources)
{
String name = annotation.name();
// Make sure the resource exists.
try
{
Context ctx = new InitialContext();
Object resource = ctx.lookup("java:comp/env/" + name);
}
catch (NamingException exc)
{
throw new InjectionProviderException("checking class resource " + annotation.name()+" of "+clazz.getName(), exc);
}
}
// Process fields with @Resource
// see org.apache.catalina.core.DefaultInstanceManager
// Field[] fields = Introspection.getDeclaredFields(managedBean.getClass());
Field[] fields = managedBean.getClass().getDeclaredFields();
for (Field field : fields)
{
if (field.isAnnotationPresent(Resource.class))
{
Resource annotation = field.getAnnotation(Resource.class);
String name = annotation.name();
logger.log(Level.CONFIG, "injecting @Resource(name=\"{2}\") into {0}.{1}", new Object[]
{
managedBean.getClass().getName(), field.getName(), name
});
try
{
Context ctx = new InitialContext();
Object resource;
if (name != null && name.length() > 0)
{
resource = ctx.lookup("java:comp/env/" + name);
}
else
{
resource = ctx.lookup(clazz.getName() + "/" + field.getName());
}
// field may be private
boolean accessibility = field.isAccessible();
try
{
field.setAccessible(true);
field.set(managedBean, resource);
}
finally
{
field.setAccessible(accessibility);
}
}
catch (NamingException | IllegalAccessException exc)
{
throw new InjectionProviderException("injecting resource " + annotation.name()+" into "+clazz.getName()+"."+field.getName(), exc);
}
}
}
// Process methods with @Resource
for (Method method : clazz.getDeclaredMethods())
{
if (method.isAnnotationPresent(Resource.class)
&& method.getName().startsWith("set")
&& method.getName().length() > 3
&& method.getReturnType() == void.class
&& method.getParameterTypes().length == 1)
{
// It's a setter with @Resource
Resource annotation = method.getAnnotation(Resource.class);
String name = annotation.name();
logger.log(Level.CONFIG, "injecting @Resource(name=\"{2}\") via {0}.{1}", new Object[]
{
managedBean.getClass().getName(), method.getName(), name
});
try
{
Context ctx = new InitialContext();
Object resource;
if (name != null && name.length() > 0)
{
resource = ctx.lookup("java:comp/env/" + name);
}
else
{
name = method.getName().substring(3);
name = name.substring(0,1).toLowerCase()+name.substring(1);
resource = ctx.lookup(clazz.getName() + "/" + name);
}
// method may be private
boolean accessibility = method.isAccessible();
try
{
method.setAccessible(true);
method.invoke(managedBean, resource);
}
finally
{
method.setAccessible(accessibility);
}
}
catch (NamingException | IllegalAccessException | InvocationTargetException exc)
{
throw new InjectionProviderException("injecting resource " + annotation.name()+" via "+clazz.getName()+"."+method.getName(), exc);
}
}
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
}
@Override
public void invokePostConstruct(Object managedBean) throws InjectionProviderException
{
logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean});
delegate.invokePostConstruct(managedBean);
}
@Override
public void invokePreDestroy(Object managedBean) throws InjectionProviderException
{
logger.log(Level.CONFIG, "managedBean={0}", new Object[]{managedBean});
delegate.invokePreDestroy(managedBean);
}
}
的原始访问权限如果更改其包名,请调整上面的包名称。
{{1}}
E&安培; OE
答案 2 :(得分:0)
另一种可能性,但我认为不太可能;你在web.xml或web-fragment.xml文件中使用metadata-complete="true"
。
定义的元数据完整: metadata-complete属性定义此部署描述符和其他相关部署 该模块的描述符(例如,Web服务描述符)是完整的,或者类文件是否可用 对于此模块并与此应用程序打包应检查指定的注释 部署信息。如果将metadata-complete设置为&#34; true&#34;,则部署工具必须忽略any 指定部署信息的注释,可能存在于该类文件中 应用。如果未指定metadata-complete或设置为&#34; false&#34;,则部署工具必须检查 注释应用程序的类文件,由规范指定。
示例web.xml:
<?xml version="1.0" encoding="UTF-8"?>
<web-app metadata-complete="true" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd" id="WebApp_ID" version="3.0">
<display-name>ResourceTest</display-name>
<welcome-file-list>
<welcome-file>index.html</welcome-file>
<welcome-file>index.htm</welcome-file>
<welcome-file>index.jsp</welcome-file>
<welcome-file>default.html</welcome-file>
<welcome-file>default.htm</welcome-file>
<welcome-file>default.jsp</welcome-file>
</welcome-file-list>
</web-app>
答案 3 :(得分:-1)
抱歉,由于代表我无法发表评论,或者我会要求您更清楚地了解您所看到的错误/等。话虽如此,我已经用Tom完整版“1.6.0_51-b11-457”测试了Tomcat 7.0.27和Tomcat 7.0.41,并且能够使用@Resource。
context.xml中
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Resource name="jdbc/Sample" auth="Container"
type="javax.sql.DataSource" username="nbuser" password="nbuser"
driverClassName="org.apache.derby.jdbc.ClientDriver"
url="jdbc:derby://localhost/Sample"
maxActive="8" maxIdle="4"/>
</Context>
ResourceTest.java
import java.io.IOException;
import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.Statement;
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("/ResourceTest")
public class ResourceTest extends HttpServlet {
private static final long serialVersionUID = 1L;
@Resource(name="jdbc/Sample")
private DataSource ds;
public ResourceTest() {
// TODO Auto-generated constructor stub
}
protected void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
PrintWriter out = response.getWriter();
out.println("<body>");
try {
//Context initCtx = new InitialContext();
//Context envCtx = (Context) initCtx.lookup("java:comp/env");
//DataSource ds = (DataSource) envCtx.lookup("jdbc/Sample");
Connection conn = ds.getConnection();
Statement s = conn.createStatement();
s.execute("Select * From \"NBUSER\".\"Friends\"");
ResultSet rs = s.getResultSet();
while (rs.next()) {
out.println(rs.getString("NAME") + " is my friend.");
}
conn.close();
} catch (Exception ex) {
ex.printStackTrace();
}
out.println("</body>");
}
/**
* @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
* response)
*/
protected void doPost(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
// TODO Auto-generated method stub
}
}