来到新公司,看了一下框架,使用了一个jersey的RESTful的API,之前听都没听过,也不知道是个什么鸟东东,抽空看了一下他的简单使用方法和原理,记录一下。
一、web.xml配置
<servlet>
<servlet-name>JerseyServlet</servlet-name>
<servlet-class>
com.xxx.servlet.MatrixServlet
</servlet-class>
<init-param>
<param-name>com.sun.jersey.spi.container.ContainerRequestFilters</param-name>
<param-value>com.xxx.InternalAuthResourceFilter</param-value>
</init-param>
<init-param>
<param-name>com.sun.jersey.spi.container.ResourceFilters</param-name>
<param-value>com.xxx.RoleApiResourceFilterFactor</param-value>
</init-param>
</servlet>
<servlet-mapping>
<servlet-name>JerseyServlet</servlet-name>
<url-pattern>/*</url-pattern>
</servlet-mapping>
二、源码解析
1、首先在web.xml中声明一个servlet,然后在这个servlet中初始化了两个Filter。我们都知道Filter是拦截请求的,那么问题来了,这两个Filter不是显示的初始声明在web.xml中的,那么他们是怎么起到拦截请求的作用的呢。
进入到MatrixServlet中发现他的继承关系是这样的:
2、首先我们都知道,servlet要是实现javax.servlet接口,web容器在初始化servlet的时候都会调用次接口的init()方法。我们在MatrixServlet中重写它的init()方法:
/**
* Initiate the Web component.
*
* @param webConfig the Web configuration.
*
* @throws javax.servlet.ServletException in case of an initialization failure
*/
protected void init(WebConfig webConfig) throws ServletException {
webComponent = (app == null)
? new InternalWebComponent()
: new InternalWebComponent(app);
webComponent.init(webConfig);
}
3、在init()方法中调用一下webComponent.init(webConfig)方法初始化web容器。进入到对应方法内,代码如下:
/**
* Initiate the Web component.
*
* @param webConfig the Web configuration.
* @throws javax.servlet.ServletException in case of any initialization error
*/
public void init(WebConfig webConfig) throws ServletException {
config = webConfig;
if (resourceConfig == null)
resourceConfig = createResourceConfig(config);
if (config.getConfigType() == WebConfig.ConfigType.FilterConfig &&
resourceConfig.getFeature(ServletContainer.FEATURE_FILTER_FORWARD_ON_404)) {
useSetStatusOn404 = true;
}
load();
Object o = resourceConfig.getProperties().get(
ResourceConfig.PROPERTY_CONTAINER_NOTIFIER);
if (o instanceof List) {
List list = (List) o;
for (Object elem : list) {
if (elem instanceof ContainerNotifier) {
ContainerNotifier crf = (ContainerNotifier) elem;
crf.addListener(this);
}
}
} else if (o instanceof ContainerNotifier) {
ContainerNotifier crf = (ContainerNotifier) o;
crf.addListener(this);
}
}
4、我们发现其中都是根据加载到的config进行容器配置,此文的目的是找到两个Filter是怎么注册到容器中的,所以相关配置就不讨论了。我们发现此方法中有一个load()方法,进入到load()方法,代码如下:
/**
* Load the Web application. This will create, configure and initiate
* the web application.
*/
public void load() {
WebApplication _application = create();
configure(config, resourceConfig, _application);
initiate(resourceConfig, _application);
application = _application;
}
5、发现是进行WebApplication的创建和配置,其中有一步initiate(resourceConfig, _application),进入到此方法内,代码如下:
/**
* Initiate the {@link WebApplication}.
* <p/>
* This method will be called once at initiation and for
* each reload of the Web application.
* <p/>
* An inheriting class may override this method to initiate the
* Web application with different parameters.
*
* @param rc the Resource configuration
* @param wa the Web application
*/
protected void initiate(ResourceConfig rc, WebApplication wa) {
wa.initiate(rc);
}
6、继续进入代码:
@Override
public void initiate(final ResourceConfig rc, final IoCComponentProviderFactory _provider) {
Errors.processWithErrors(new Errors.Closure<Void>() {
@Override
public Void f() {
Errors.setReportMissingDependentFieldOrMethod(false);
_initiate(rc, _provider);
return null;
}
});
}
7、发现调用的是另一个_initiate(rc, _provider)方法,此方法有点长,几百行,所以只列出需要的部分代码,在1252行有这样一句代码:
filterFactory.init(resourceConfig);
8、进入到此方法:
public void init(ResourceConfig resourceConfig) {
// Initiate request filters
requestFilters.addAll(
getFilters(ContainerRequestFilter.class,resourceConfig.getContainerRequestFilters())
);
requestFilters.addAll(providerServices.getServices(ContainerRequestFilter.class));
// Initiate response filters
responseFilters.addAll(
getFilters(ContainerResponseFilter.class, resourceConfig.getContainerResponseFilters())
);
responseFilters.addAll(providerServices.getServices(ContainerResponseFilter.class));
// Initiate resource filter factories
resourceFilterFactories.addAll(
getFilters(ResourceFilterFactory.class, resourceConfig.getResourceFilterFactories())
);
resourceFilterFactories.addAll(providerServices.getServices(ResourceFilterFactory.class));
resourceFilterFactories.add(new AnnotationResourceFilterFactory(this));
}
9、其中有两句:
requestFilters.addAll(getFilters(ContainerRequestFilter.class,resourceConfig.getContainerRequestFilters()));
resourceFilterFactories.addAll(getFilters(ResourceFilterFactory.class, resourceConfig.getResourceFilterFactories()));
10、而两个方法中对应的第二个参数继续点进去会发现:
public static final String PROPERTY_CONTAINER_REQUEST_FILTERS =
"com.sun.jersey.spi.container.ContainerRequestFilters";
public List getContainerRequestFilters() {
return getFilterList(PROPERTY_CONTAINER_REQUEST_FILTERS);
}
public static final String PROPERTY_RESOURCE_FILTER_FACTORIES =
"com.sun.jersey.spi.container.ResourceFilters";
public List getResourceFilterFactories() {
return getFilterList(PROPERTY_RESOURCE_FILTER_FACTORIES);
}
11、获取的就是我们在web.xml中配置的两个Filter,所以当请求来到服务器的时候,就会被这两个Filter拦截,进而就可以在这两个自定义Filter的filter()方法中实现我们对请求的校验等操作。