几年来,我一直在JSF 2 Mojarra中使用Tomcat 6.0.26-6.0.35,直到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资源。但是,在每种情况下,确实存在命名的资源,并且可以通过例如
@Resource
DataSource resources.
DataSource
new InitialContext().lookup("java:comp/env/jdbc/cLabs");
[它们由context.xml中的元素定义]
这当然是皇家的PITA,因为我在一两年前花了一些时间用前者代替后者。我还必须使用Tomcat 7编织其他魔术才能使其再次正常工作吗?
请注意,资源 已 正确注入到Servlet中,因此并没有完全损坏。Tomcat和JSF之间的一些交互。
回答我自己的问题,@ JeffE答案的改进版本。基本问题是:
Tomcat6InjectionProvider
WebContainerInjectionProvider
您可以在没有web.xml上下文输入的情况下克服此问题,如下所示:
web.xml
META-INF/services/com.sun.faces.spi.injectionprovider
com.sun.faces.vendor.Tomcat7InjectionProvider:org.apache.catalina.core.DefaultInstanceManager
该行的含义是,如果部署中存在第二个类,则将第一个类用作注入提供程序。上面的第二个类是Tomcat 7的一部分。
该版本比JeffE的版本包含许多改进。特别:
@Resources
name
@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); } }
E&OE