首先,我想指出的是,从时间上来讲,这是我职业生涯中最大的难题。(现在已经连续两天,进度基本上为0。)我尝试的每个“解决方法”或“解决方案”都没有奏效,所以我很受阻,非常渴望获得一些帮助。
简而言之,问题是Jersey / HK2似乎总是在Spring实例化之后立即实例化我的Spring管理的bean,这告诉我jersey-spring3并没有完成工作,或者至少没有使用我当前的设置(或到目前为止我尝试过的约50种设置)。
请注意,当我使用空的构造函数时,这些资源字段在运行时为null。
我不明白为什么当前的设置不起作用,因为我实际上是在复制此在线示例
任何帮助都超过赞赏!
Configuration
-----pom.xml-----
<!-- ... --> <dependencies> <!-- Spring Dependencies --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-instrument</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-instrument-tomcat</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-orm</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-core</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-ldap</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-parent</artifactId> <version>${spring.version}</version> <classifier>tests</classifier> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-config</artifactId> <version>${spring.version}</version> <classifier>tests</classifier> </dependency> <dependency> <groupId>org.springframework.security</groupId> <artifactId>spring-security-acl</artifactId> <version>${spring.version}</version> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-support</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-dao</artifactId> </exclusion> </exclusions> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>${spring.version}</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>${spring.version}</version> <scope>test</scope> </dependency> <!-- / Spring Dependencies --> <!-- API dependencies --> <dependency> <groupId>org.glassfish.jersey.core</groupId> <artifactId>jersey-client</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.containers</groupId> <artifactId>jersey-container-servlet</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.media</groupId> <artifactId>jersey-media-json-processing</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>org.glassfish.jersey.test-framework.providers</groupId> <artifactId>jersey-test-framework-provider-grizzly2</artifactId> <version>2.4</version> <scope>test</scope> </dependency> <dependency> <groupId>org.glassfish.jersey.ext</groupId> <artifactId>jersey-spring3</artifactId> <version>${jersey.version}</version> </dependency> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>${gson.version}</version> </dependency> <!-- / API dependencies --> <!-- ... --> </dependencies> <!-- ... --> <properties> <!-- ... --> <spring.version>3.0.5.RELEASE</spring.version> <jersey.version>2.4.1</jersey.version> <gson.version>2.2.4</gson.version> <!-- ... --> </properties> <!-- ... -->
-----web.xml-----
<web-app> <context-param> <param-name>contextConfigLocation</param-name> <param-value>classpath:/beans.xml</param-value> </context-param> <!-- ... --> <servlet> <servlet-name>Jersey REST Service</servlet-name> <servlet-class>org.glassfish.jersey.servlet.ServletContainer</servlet-class> <init-param> <param-name>javax.ws.rs.Application</param-name> <param-value>fubar.rest.FubarJerseyApplication</param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>Jersey REST Service</servlet-name> <url-pattern>/api/*</url-pattern> </servlet-mapping> <!-- ... --> </web-app>
-----beans.xml(Context Configuration)-----
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd"> <!-- ... --> <!-- beans-outbound-api has configuration for spring-jersey3 to work properly --> <import resource="beans-api.xml" /> </beans>
-----beans-api.xml-----
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> <!-- Services --> <bean id="locationServiceV1" class="fubar.rest.v1.services.location.impl.LocationServiceV1" /> <bean id="locationServiceV2" class="fubar.rest.v2.services.location.impl.LocationServiceV2" /> <bean id="viewServiceV1" class="fubar.rest.v1.services.view.impl.ViewServiceV1" /> <bean id="viewServiceV2" class="fubar.rest.v2.services.view.impl.ViewServiceV2" /> <!-- Resources --> <bean class="fubar.rest.resources.location.impl.LocationResource"> <constructor-arg index="0" ref="locationServiceV1" /> <constructor-arg index="1" ref="locationServiceV2" /> </bean> <bean class="fubar.rest.resources.view.impl.ViewResource"> <constructor-arg index="0" ref="viewServiceV1" /> <constructor-arg index="1" ref="viewServiceV2" /> </bean> </beans>
Code
-----Resource(JAX-RS)-----
@Path(RESTLocationResourceV1.PathFields.PATH_ROOT) @Produces({V1_JSON, APPLICATION_JSON}) public class LocationResource extends ResourceBase {
private static final Logger logger = Logger.getLogger(LocationResource.class);
@Inject public LocationResource(final LocationServiceV1 v1Loc, final LocationServiceV2 v2Loc) { super(v1Loc, v2Loc); logger.info(format(Messages.INF_INSTANTIATED, “LocationResource”)); }
@GET @Path(PathFields.SUBPATH_LIST) public LocationListV1 listV1(@HeaderParam(HEADER_API_KEY) String apiKey) throws ApplicationException { // Implementation }
@GET @Path(PathFields.SUBPATH_SEARCH) public LocationListV1 searchV1(@HeaderParam(HEADER_API_KEY) String apiKey, @QueryParam(QueryFields.QUERY) String likeText) throws ApplicationException { // Implementation } }
-----Service(Spring Bean)-----
public class LocationServiceV1 extends ServiceBaseV1<LocationBean, LocationV1, LocationListV1> implements ILocationServiceV1 { @Autowired private LocationDao daoLoc; public LocationServiceV1() { super(new LocationBeanToJsonTranslatorV1()); } @Override public LocationListV1 listV1() throws ApplicationException { // Implementation } @Override public LocationListV1 searchV1(String likeText) throws ApplicationException { // Implementation } }
(与版本2基本上相同)
public class FubarJerseyApplication extends ResourceConfig { private static final class Messages { static final String INF_STARTING_APPLICATION = "Starting %s!"; } private static final Logger logger = Logger.getLogger(FubarJerseyApplication.class); public FubarJerseyApplication() { packages("fubar.rest"); logger.info(format(Messages.INF_STARTING_APPLICATION, this.getClass().getName())); } }
Invocation (Client)
curl http://my-ip-address/fubar/api/location/list
(500内部服务器错误)
Error (Server)
org.glassfish.hk2.api.UnsatisfiedDependencyException: There was no object available for injection at Injectee(requiredType=LocationServiceV1,parent= LocationResource,qualifiers={}),position=0,optional=false,self=false, unqualified=null,344016971) at org.jvnet.hk2.internal.ThreeThirtyResolver.resolve(ThreeThirtyResolver.java:74) at org.jvnet.hk2.internal.ClazzCreator.resolve(ClazzCreator.java:208) at org.jvnet.hk2.internal.ClazzCreator.resolveAllDependencies(ClazzCreator.java:225) at org.jvnet.hk2.internal.ClazzCreator.create(ClazzCreator.java:329) at org.jvnet.hk2.internal.SystemDescriptor.create(SystemDescriptor.java:456) at org.glassfish.jersey.process.internal.RequestScope.findOrCreate(RequestScope.java:158) at org.jvnet.hk2.internal.Utilities.createService(Utilities.java:2350) at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:612) at org.jvnet.hk2.internal.ServiceLocatorImpl.getService(ServiceLocatorImpl.java:597) at org.glassfish.jersey.internal.inject.Injections.getOrCreate(Injections.java:173) at org.glassfish.jersey.server.model.MethodHandler$ClassBasedMethodHandler.getInstance(MethodHandler.java:185) at org.glassfish.jersey.server.internal.routing.PushMethodHandlerRouter.apply(PushMethodHandlerRouter.java:103) at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:128) at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131) at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131) at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131) at org.glassfish.jersey.server.internal.routing.RoutingStage._apply(RoutingStage.java:131) at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:110) at org.glassfish.jersey.server.internal.routing.RoutingStage.apply(RoutingStage.java:65) at org.glassfish.jersey.process.internal.Stages.process(Stages.java:197) at org.glassfish.jersey.server.ServerRuntime$1.run(ServerRuntime.java:250) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:271) at org.glassfish.jersey.internal.Errors$1.call(Errors.java:267) at org.glassfish.jersey.internal.Errors.process(Errors.java:315) at org.glassfish.jersey.internal.Errors.process(Errors.java:297) at org.glassfish.jersey.internal.Errors.process(Errors.java:267) at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:318) at org.glassfish.jersey.server.ServerRuntime.process(ServerRuntime.java:236) at org.glassfish.jersey.server.ApplicationHandler.handle(ApplicationHandler.java:983) at org.glassfish.jersey.servlet.WebComponent.service(WebComponent.java:361) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:372) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:335) at org.glassfish.jersey.servlet.ServletContainer.service(ServletContainer.java:218) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:290) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at fubar.server.springframework.SessionFilter.doFilter(SessionFilter.java:44) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at fubar.server.springframework.loader.ContextLoaderHttpInterceptor$LoaderState.filter(ContextLoaderHttpInterceptor.java:75) at fubar.server.springframework.loader.ContextLoaderHttpInterceptor$StartedState.filter(ContextLoaderHttpInterceptor.java:120) at fubar.server.springframework.loader.ContextLoaderHttpInterceptor.doFilter(ContextLoaderHttpInterceptor.java:62) at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235) at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206) at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233) at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191) at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:127) at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:103) at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109) at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293) at org.apache.jk.server.JkCoyoteHandler.invoke(JkCoyoteHandler.java:190) at org.apache.jk.common.HandlerRequest.invoke(HandlerRequest.java:311) at org.apache.jk.common.ChannelSocket.invoke(ChannelSocket.java:776) at org.apache.jk.common.ChannelSocket.processConnection(ChannelSocket.java:705) at org.apache.jk.common.ChannelSocket$SocketConnection.runIt(ChannelSocket.java:898) at org.apache.tomcat.util.threads.ThreadPool$ControlRunnable.run(ThreadPool.java:690) at java.lang.Thread.run(Thread.java:662)
API Log
Dec 10, 2013 13:36:28 INFO [main] fubar.rest.FubarJerseyApplication - Starting fubar.rest.FubarJerseyApplication! Dec 10, 2013 13:38:06 INFO [pool-1-thread-1] resources.location.impl.LocationResource - LocationResource has been instantiated Dec 10, 2013 13:38:06 INFO [pool-1-thread-1] resources.view.impl.ViewResource - ViewResource has been instantiated
-
更新-找到了这个:
Catalina Log
Dec 10, 2013 1:36:42 PM org.glassfish.jersey.server.ApplicationHandler initialize INFO: Initiating Jersey application, version Jersey: 2.4.1 2013-11-08 12:08:47... Dec 10, 2013 1:36:43 PM org.glassfish.jersey.server.spring.SpringComponentProvider initialize SEVERE: Spring context lookup failed, skipping spring component provider initialization. Dec 10, 2013 1:38:00 PM com.sun.xml.bind.v2.runtime.reflect.opt.Injector inject
…所以在SpringComponentProvider#initialize中找不到ApplicationContext 。
我们有一个自定义的异步ContextLoader,因此临时解决方案需要在Jersey-Spring3源中放置一个完全hack,以在自定义组件提供程序初始化之前等待应用程序初始化。
PS对于任何发现自己必须执行此类操作的可怜人,请确保META-INF / settings包含SpringComponentProvider配置。
请注意,这是一个可怕的骇客,只有在所有其他尝试都失败的情况下,我才尝试尝试最后的手段,例如我的情况。另外,在尝试此类操作之前,我会咨询泽西岛邮寄小组有关你的问题的信息。
就是说…这就是我为解决我的问题所做的:
从字面上将spring-jersey3的源代码复制到我的应用程序/服务器中,并根据许可证使用适当的标签修改每个文件的标题;
创建了以下类
===>
/** * Hack class for RN-8979. * * @author ryan * */ public class ContextLoadWaiter { private static final Logger logger = Logger.getLogger(ContextLoadWaiter.class); public void doWait() { try { while (ContextLoaderHttpInterceptor.isNotStarted()) { logger.info("Waiting for ContextLoader to start..."); Thread.sleep(1000); } } catch (InterruptedException e) { logger.error("SpringComponentProvider was interrupted!"); } } }
请注意,这特定于 our 代码库,就像ContextLoaderHttpInterceptorhttp servlet一样,如果尚未加载我们的自定义(恰好是异步的),则isNotStarted返回。trueContextLoader
ContextLoaderHttpInterceptor
isNotStarted
trueContextLoader
ContextLoader出于某种原因,有人在某个时候将自定义异步程序放置在适当的位置,以使服务器启动时允许UI显示“正在加载”页面。(可能不是添加此UI“功能”的正确方法,但是代码在那里并且UI依赖于它,所以我不得不处理它…)
ContextLoader
由于这部分内容并不直接适用于你,因此关键是要调试SpringComponentProvider(从此处开始)并查看的值ClassPathXmlApplicationContext。如果它是null,就像我们的情况一样,那么你需要找出原因,null并ContextLoader在初始化此组件之前等待用于加载的任何内容。
SpringComponentProvider
ClassPathXmlApplicationContext
==>
... private final ContextLoadWaiter waiter = new ContextLoadWaiter(); ... @Override public void initialize(ServiceLocator locator) { waiter.doWait(); // Wait on our asynchronous context loader. this.locator = locator; if (LOGGER.isLoggable(Level.FINE)) { LOGGER.fine("Context lookup started"); } ...
创建了这个文件:META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider其内容是SpringComponentProvider的完全限定的类路径,例如com.company.server.nbi.rest.internal.jspring.SpringComponentProvider
META-INF/services/org.glassfish.jersey.server.spi.ComponentProvider
com.company.server.nbi.rest.internal.jspring.SpringComponentProvider
添加了定制的Jersey-spring3软件包作为要在应用程序中进行扫描的软件包;见下文…
/** * Application configuration. * * @author ryan * */ public class MyJerseyApplication extends ResourceConfig { private static final class Messages { static final String INF_STARTING_APPLICATION = "Starting %s!"; } private static final Logger logger = Logger.getLogger(MyJerseyApplication.class); public MyJerseyApplication() { packages( /* Internal providers */ "com.company.server.nbi.rest.providers", /* Internal filters */ "com.company.server.nbi.rest.filters", /* Spring injection support */ "com.company.server.nbi.rest.internal.jspring", // HERE!!! /* Json providers */ "com.fasterxml.jackson.jaxrs.json", /* Jackson exception mappers */ "com.fasterxml.jackson.jaxrs.base"); /* Resources */ register(ResourceA.class); register(ResourceB.class); register(ResourceC.class); /* Miscellaneous features */ register(MultiPartFeature.class); register(LoggingFilter.class); logger.info(format(Messages.INF_STARTING_APPLICATION, this.getClass().getName())); } }
而已”。绝对不是值得骄傲的解决方案,但是如果你像我一样处于绝望状态,试一下可能不会有任何伤害。