-
Notifications
You must be signed in to change notification settings - Fork 8.1k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
a0196b6
commit ca91234
Showing
24 changed files
with
1,407 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
# Sentinel for jax-rs | ||
|
||
Sentinel provides filter integration to enable flow control for web requests. | ||
Add the following dependency in `pom.xml` (if you are using Maven): | ||
|
||
```xml | ||
<dependency> | ||
<groupId>com.alibaba.csp</groupId> | ||
<artifactId>sentinel-jax-rs-adapter</artifactId> | ||
<version>x.y.z</version> | ||
</dependency> | ||
``` | ||
|
||
the `SentinelJaxRsProviderFilter` is auto activated in pure jax-rs application. | ||
|
||
For Spring web applications you can configure with Spring bean: | ||
|
||
```java | ||
@Configuration | ||
public class FilterConfig { | ||
|
||
@Bean | ||
public SentinelJaxRsProviderFilter sentinelJaxRsProviderFilter() { | ||
return new SentinelJaxRsProviderFilter(); | ||
} | ||
} | ||
``` | ||
|
||
For jax-rs client, register `SentinelJaxRsClientFilter` when build Client | ||
|
||
``` | ||
Client client = ClientBuilder.newClient() | ||
.register(new SentinelJaxRsClientFilter()); | ||
``` | ||
|
||
When a request is blocked, Sentinel jax-rs filter will return Response with status of TOO_MANY_REQUESTS indicating the request is rejected. | ||
|
||
You can customize it by implement your own `SentinelJaxRsFallback` and register to `SentinelJaxRsConfig`. | ||
|
||
The `RequestOriginParser` interface is useful for extracting request origin (e.g. IP or appName from HTTP Header) | ||
from HTTP request. You can implement your own `RequestOriginParser` and register to `SentinelJaxRsConfig`. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,74 @@ | ||
<?xml version="1.0" encoding="UTF-8"?> | ||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" | ||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> | ||
<modelVersion>4.0.0</modelVersion> | ||
|
||
<parent> | ||
<groupId>com.alibaba.csp</groupId> | ||
<artifactId>sentinel-adapter</artifactId> | ||
<version>1.8.0-SNAPSHOT</version> | ||
</parent> | ||
|
||
<artifactId>sentinel-jax-rs-adapter</artifactId> | ||
<packaging>jar</packaging> | ||
|
||
<properties> | ||
<javax.ws.rs-api.version>2.1.1</javax.ws.rs-api.version> | ||
</properties> | ||
|
||
<dependencies> | ||
<dependency> | ||
<groupId>com.alibaba.csp</groupId> | ||
<artifactId>sentinel-core</artifactId> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>javax.ws.rs</groupId> | ||
<artifactId>javax.ws.rs-api</artifactId> | ||
<version>${javax.ws.rs-api.version}</version> | ||
<scope>provided</scope> | ||
</dependency> | ||
|
||
<dependency> | ||
<groupId>junit</groupId> | ||
<artifactId>junit</artifactId> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-web</artifactId> | ||
<version>2.2.6.RELEASE</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.springframework.boot</groupId> | ||
<artifactId>spring-boot-starter-test</artifactId> | ||
<version>2.2.6.RELEASE</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>io.rest-assured</groupId> | ||
<artifactId>rest-assured</artifactId> | ||
<version>4.3.0</version> | ||
<scope>test</scope> | ||
</dependency> | ||
<dependency> | ||
<groupId>org.jboss.resteasy</groupId> | ||
<artifactId>resteasy-spring-boot-starter</artifactId> | ||
<version>4.5.1.Final</version> | ||
<scope>test</scope> | ||
</dependency> | ||
</dependencies> | ||
|
||
<build> | ||
<plugins> | ||
<plugin> | ||
<groupId>org.apache.maven.plugins</groupId> | ||
<artifactId>maven-surefire-plugin</artifactId> | ||
<configuration> | ||
<forkMode>always</forkMode> | ||
</configuration> | ||
</plugin> | ||
</plugins> | ||
</build> | ||
</project> |
77 changes: 77 additions & 0 deletions
77
...apter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/SentinelJaxRsClientFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,77 @@ | ||
/* | ||
* Copyright 1999-2020 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.alibaba.csp.sentinel.adapter.jaxrs; | ||
|
||
import com.alibaba.csp.sentinel.Entry; | ||
import com.alibaba.csp.sentinel.EntryType; | ||
import com.alibaba.csp.sentinel.ResourceTypeConstants; | ||
import com.alibaba.csp.sentinel.SphU; | ||
import com.alibaba.csp.sentinel.adapter.jaxrs.config.SentinelJaxRsConfig; | ||
import com.alibaba.csp.sentinel.context.ContextUtil; | ||
import com.alibaba.csp.sentinel.slots.block.BlockException; | ||
import com.alibaba.csp.sentinel.util.StringUtil; | ||
|
||
import javax.ws.rs.client.ClientRequestContext; | ||
import javax.ws.rs.client.ClientRequestFilter; | ||
import javax.ws.rs.client.ClientResponseContext; | ||
import javax.ws.rs.client.ClientResponseFilter; | ||
import javax.ws.rs.container.ResourceInfo; | ||
import javax.ws.rs.core.Context; | ||
import java.io.IOException; | ||
|
||
/** | ||
* @author sea | ||
*/ | ||
public class SentinelJaxRsClientFilter implements ClientRequestFilter, ClientResponseFilter { | ||
|
||
private static final String SENTINEL_JAX_RS_CLIENT_ENTRY_PROPERTY = "sentinel_jax_rs_client_entry_property"; | ||
|
||
@Context | ||
private ResourceInfo resourceInfo; | ||
|
||
|
||
@Override | ||
public void filter(ClientRequestContext requestContext) throws IOException { | ||
try { | ||
String resourceName = getResourceName(requestContext); | ||
|
||
if (StringUtil.isNotEmpty(resourceName)) { | ||
Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.OUT); | ||
|
||
requestContext.setProperty(SENTINEL_JAX_RS_CLIENT_ENTRY_PROPERTY, entry); | ||
} | ||
} catch (BlockException e) { | ||
try { | ||
requestContext.abortWith(SentinelJaxRsConfig.getJaxRsFallback().fallbackResponse(requestContext.getUri().toString(), e)); | ||
} finally { | ||
ContextUtil.exit(); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void filter(ClientRequestContext requestContext, ClientResponseContext responseContext) throws IOException { | ||
Entry entry = (Entry) requestContext.getProperty(SENTINEL_JAX_RS_CLIENT_ENTRY_PROPERTY); | ||
if (entry != null) { | ||
entry.exit(); | ||
} | ||
requestContext.removeProperty(SENTINEL_JAX_RS_CLIENT_ENTRY_PROPERTY); | ||
} | ||
|
||
public String getResourceName(ClientRequestContext requestContext) { | ||
return SentinelJaxRsConfig.getResourceNameParser().parse(requestContext); | ||
} | ||
} |
88 changes: 88 additions & 0 deletions
88
...ter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/SentinelJaxRsProviderFilter.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,88 @@ | ||
/* | ||
* Copyright 1999-2020 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.alibaba.csp.sentinel.adapter.jaxrs; | ||
|
||
import com.alibaba.csp.sentinel.*; | ||
import com.alibaba.csp.sentinel.adapter.jaxrs.config.SentinelJaxRsConfig; | ||
import com.alibaba.csp.sentinel.context.ContextUtil; | ||
import com.alibaba.csp.sentinel.slots.block.BlockException; | ||
import com.alibaba.csp.sentinel.util.StringUtil; | ||
|
||
import javax.ws.rs.container.*; | ||
import javax.ws.rs.core.Context; | ||
import javax.ws.rs.ext.Provider; | ||
import java.io.IOException; | ||
|
||
/** | ||
* @author sea | ||
*/ | ||
@Provider | ||
public class SentinelJaxRsProviderFilter implements ContainerRequestFilter, ContainerResponseFilter { | ||
|
||
private static final String SENTINEL_JAX_RS_PROVIDER_CONTEXT_NAME = "sentinel_jax_rs_provider_context"; | ||
|
||
|
||
private static final String SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY = "sentinel_jax_rs_provider_entry_property"; | ||
|
||
@Context | ||
private ResourceInfo resourceInfo; | ||
|
||
@Override | ||
public void filter(ContainerRequestContext containerRequestContext) throws IOException { | ||
|
||
try { | ||
String resourceName = getResourceName(containerRequestContext, resourceInfo); | ||
|
||
if (StringUtil.isNotEmpty(resourceName)) { | ||
// Parse the request origin using registered origin parser. | ||
String origin = parseOrigin(containerRequestContext); | ||
String contextName = getContextName(containerRequestContext); | ||
ContextUtil.enter(contextName, origin); | ||
Entry entry = SphU.entry(resourceName, ResourceTypeConstants.COMMON_WEB, EntryType.IN); | ||
|
||
containerRequestContext.setProperty(SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY, entry); | ||
} | ||
} catch (BlockException e) { | ||
try { | ||
containerRequestContext.abortWith(SentinelJaxRsConfig.getJaxRsFallback().fallbackResponse(containerRequestContext.getUriInfo().getPath(), e)); | ||
} finally { | ||
ContextUtil.exit(); | ||
} | ||
} | ||
} | ||
|
||
@Override | ||
public void filter(ContainerRequestContext containerRequestContext, ContainerResponseContext containerResponseContext) throws IOException { | ||
Entry entry = (Entry) containerRequestContext.getProperty(SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY); | ||
if (entry != null) { | ||
entry.exit(); | ||
} | ||
containerRequestContext.removeProperty(SENTINEL_JAX_RS_PROVIDER_ENTRY_PROPERTY); | ||
ContextUtil.exit(); | ||
} | ||
|
||
public String getResourceName(ContainerRequestContext containerRequestContext, ResourceInfo resourceInfo) { | ||
return SentinelJaxRsConfig.getResourceNameParser().parse(containerRequestContext, resourceInfo); | ||
} | ||
|
||
protected String getContextName(ContainerRequestContext request) { | ||
return SENTINEL_JAX_RS_PROVIDER_CONTEXT_NAME; | ||
} | ||
|
||
protected String parseOrigin(ContainerRequestContext request) { | ||
return SentinelJaxRsConfig.getRequestOriginParser().parseOrigin(request); | ||
} | ||
} |
62 changes: 62 additions & 0 deletions
62
...pter/src/main/java/com/alibaba/csp/sentinel/adapter/jaxrs/config/SentinelJaxRsConfig.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
/* | ||
* Copyright 1999-2020 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.alibaba.csp.sentinel.adapter.jaxrs.config; | ||
|
||
import com.alibaba.csp.sentinel.adapter.jaxrs.fallback.DefaultSentinelJaxRsFallback; | ||
import com.alibaba.csp.sentinel.adapter.jaxrs.fallback.SentinelJaxRsFallback; | ||
import com.alibaba.csp.sentinel.adapter.jaxrs.request.DefaultRequestOriginParser; | ||
import com.alibaba.csp.sentinel.adapter.jaxrs.request.DefaultResourceNameParser; | ||
import com.alibaba.csp.sentinel.adapter.jaxrs.request.RequestOriginParser; | ||
import com.alibaba.csp.sentinel.adapter.jaxrs.request.ResourceNameParser; | ||
|
||
/** | ||
* @author sea | ||
*/ | ||
public class SentinelJaxRsConfig { | ||
|
||
private static volatile ResourceNameParser resourceNameParser = new DefaultResourceNameParser(); | ||
|
||
private static volatile RequestOriginParser requestOriginParser = new DefaultRequestOriginParser(); | ||
|
||
private static volatile SentinelJaxRsFallback jaxRsFallback = new DefaultSentinelJaxRsFallback(); | ||
|
||
public static ResourceNameParser getResourceNameParser() { | ||
return resourceNameParser; | ||
} | ||
|
||
public static void setResourceNameParser(ResourceNameParser resourceNameParser) { | ||
SentinelJaxRsConfig.resourceNameParser = resourceNameParser; | ||
} | ||
|
||
public static RequestOriginParser getRequestOriginParser() { | ||
return requestOriginParser; | ||
} | ||
|
||
public static void setRequestOriginParser(RequestOriginParser originParser) { | ||
SentinelJaxRsConfig.requestOriginParser = originParser; | ||
} | ||
|
||
public static SentinelJaxRsFallback getJaxRsFallback() { | ||
return jaxRsFallback; | ||
} | ||
|
||
public static void setJaxRsFallback(SentinelJaxRsFallback jaxRsFallback) { | ||
SentinelJaxRsConfig.jaxRsFallback = jaxRsFallback; | ||
} | ||
|
||
private SentinelJaxRsConfig() { | ||
} | ||
} |
32 changes: 32 additions & 0 deletions
32
...in/java/com/alibaba/csp/sentinel/adapter/jaxrs/fallback/DefaultSentinelJaxRsFallback.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,32 @@ | ||
/* | ||
* Copyright 1999-2020 Alibaba Group Holding Ltd. | ||
* | ||
* Licensed under the Apache License, Version 2.0 (the "License"); | ||
* you may not use this file except in compliance with the License. | ||
* You may obtain a copy of the License at | ||
* | ||
* https://www.apache.org/licenses/LICENSE-2.0 | ||
* | ||
* Unless required by applicable law or agreed to in writing, software | ||
* distributed under the License is distributed on an "AS IS" BASIS, | ||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
* See the License for the specific language governing permissions and | ||
* limitations under the License. | ||
*/ | ||
package com.alibaba.csp.sentinel.adapter.jaxrs.fallback; | ||
|
||
import javax.ws.rs.core.MediaType; | ||
import javax.ws.rs.core.Response; | ||
|
||
/** | ||
* @author sea | ||
*/ | ||
public class DefaultSentinelJaxRsFallback implements SentinelJaxRsFallback { | ||
@Override | ||
public Response fallbackResponse(String route, Throwable cause) { | ||
return Response.status(Response.Status.TOO_MANY_REQUESTS) | ||
.entity("Blocked by Sentinel (flow limiting)") | ||
.type(MediaType.APPLICATION_JSON_TYPE) | ||
.build(); | ||
} | ||
} |
Oops, something went wrong.