【发布时间】:2015-07-23 13:55:54
【问题描述】:
在实现oauth2 系统时,我遇到了以下代码的一些问题:
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
import org.springframework.web.servlet.HandlerMapping;
...
HandlerMapping.class.isAssignableFrom(FrameworkEndpointHandlerMapping.class);
确实,由于类FrameworkEndpointHandlerMapping 实现了接口HandlerMapping,所以这个函数应该总是返回true。当我对此函数运行单元测试时就是这种情况。但是,在服务器启动期间,此函数返回false(使用调试器检查)。这是一个大问题,因为当 DispatcherServlet 被实例化时,它会搜索实现 HandlerMapping 的类,而我的 FrameworkEndpointHandlerMapping 被丢弃,从而导致应用程序出现错误。
我已经搜索过类似这样的其他问题,但大多数人回答isAssignableFrom 方法使用不正确(类和函数参数的混合)。这里不是这种情况,因为 JUnit 正在工作。
怀疑导入的jar 文件有问题,我将它们限制为以下几种:
- spring-beans-4.1.4.RELEASE.jar
- spring-security-oauth2-2.0.6.RELEASE.jar
- spring-webmvc-4.1.4.RELEASE.jar(4.0.9也试过)
- spring-core-4.1.4.RELEASE.jar
- ...
请问您有什么想法可以探索吗?
如需更多信息,请参考以下来源:
我自己的DispatcherServlet(以String为参数的构造函数被JUnit测试调用,系统启动时调用默认构造函数)
import org.junit.Assert;
import org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping;
import org.springframework.web.context.WebApplicationContext;
import org.springframework.web.servlet.DispatcherServlet;
import org.springframework.web.servlet.HandlerMapping;
import org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping;
public class MobileDispatcherServlet extends DispatcherServlet
{
private static final long serialVersionUID = 1L;
public MobileDispatcherServlet()
{
super();
HandlerMapping.class.isAssignableFrom(FrameworkEndpointHandlerMapping.class);
}
public MobileDispatcherServlet(final WebApplicationContext webApplicationContext)
{
super(webApplicationContext);
final FrameworkEndpointHandlerMapping handlerMapping = webApplicationContext.getBean(FrameworkEndpointHandlerMapping.class);
HandlerMapping.class.isAssignableFrom(handlerMapping.getClass());
}
public MobileDispatcherServlet(final String test)
{
Assert.assertTrue(HandlerMapping.class.isAssignableFrom(FrameworkEndpointHandlerMapping.class));
}
}
oauth 配置文件:
<?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"
xmlns:security="http://www.springframework.org/schema/security"
xmlns:oauth="http://www.springframework.org/schema/security/oauth2"
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
http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security.xsd
http://www.springframework.org/schema/security/oauth2 http://www.springframework.org/schema/security/spring-security-oauth2.xsd">
<!-- Root of the configuration -->
<!-- The FrameworkEndpointHandlerMapping is created here -->
<oauth:authorization-server client-details-service-ref="clientDetails"
token-services-ref="tokenServices"
user-approval-handler-ref="userApprovalHandler"
authorization-endpoint-url="/oauth/authorize.action"
token-endpoint-url="/oauth/token.action" >
<oauth:authorization-code authorization-code-services-ref="authorizationCodeServices" disabled="false" />
<oauth:refresh-token />
</oauth:authorization-server>
...
</beans>
web.xml:
<web-app id="sitestorefront" version="3.0" 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.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app.xsd"
metadata-complete="true">
...
<context-param>
<description>
The 'contextConfigLocation' param specifies where your configuration files are located.
The 'WEB-INF/config/web-application-config.xml' file includes several other XML config
files to build up the configuration for the application.
</description>
<param-name>contextConfigLocation</param-name>
<param-value>WEB-INF/config/web-application-config.xml</param-value>
</context-param>
<context-param>
<param-name>tagpoolMaxSize</param-name>
<param-value>50</param-value>
</context-param>
<servlet>
<description>
DispatcherServlet
</description>
<servlet-name>DispatcherServlet</servlet-name>
<servlet-class>be.sbh.site.storefront.oauth2.MobileDispatcherServlet</servlet-class>
<init-param>
<description>
Specifies the location for Spring MVC to load an additional XML configuration file.
Because hybris is already configured with the XML spring configuration files to load
we must set this param value to EMPTY in order to prevent loading of the default
/WEB-INF/applicationContext.xml file.
</description>
<param-name>contextConfigLocation</param-name>
<param-value></param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>DispatcherServlet</servlet-name>
<!-- Map all requests to the DispatcherServlet -->
<url-pattern>/</url-pattern>
</servlet-mapping>
...
</web-app>
web-application-config.xml 导入所有配置文件(其中,oauth 配置文件)。其中一个有一个<mvc:annotation-driven /> 来启用 mvc 注释。
我试图将我的来源限制为与我相关的来源。如果您需要更多,请随时问我。
感谢您阅读此问题,
劳伦特
【问题讨论】:
-
我建议您仔细查看每个类文字的类加载器 - 并根据超类等探索(在调试器中)
FrameworkEndpointHandlerMapping.class。 -
嗯,我曾经怀疑有些奇怪,因为在调试器中没有命中断点......直到我意识到断点在弹簧初始化期间没有激活!不要在那些早期阶段依赖调试器,而是依赖日志记录(slf4j、commons logging、JUL、log4j ...)
-
@Serge:感谢您的 cmets。我已重新启动服务器以记录
isAssignableFrom的值,但它仍然是错误的(因此没有调试器)。我的自定义DispatcherServlet扩展了 Spring 中的那个,因此除了我在构造函数中添加的那个之外,它具有相同的行为。如果您查看DispatcherServlet的来源,在方法@987654346@(第545 行)中,它会搜索所有HandlerMapping类型的bean。在此搜索期间,使用方法isAssignableFrom并返回 false 丢弃我的FrameworkEndpointHandlerMapping。 -
@Jon:感谢您的评论。我不确定你建议我做什么。为了进行测试,我调试了
ClassUtils类的方法isAssignable,其中调用了方法isAssignableFrom。在那里,在lhsType和rhsType的值中,我可以看到完整的类名,它正是需要的(我的意思是,“包+ 类名”正是我所期望的)。但是,isAssignableFrom方法仍然返回 false。 -
除了类名之外,还有更多的类标识 - 还有类 loader。查看每个类的加载器,如果它们不同,那很可能是问题所在。查看
FrameworkEndpointHandlerMapping的超类——我怀疑它与您正在查看的HandlerMapping类不同,可能是因为它们是由不同的类加载器加载的。
标签: java spring spring-mvc oauth-2.0