sentinel upgrade to 0.1.1 & add annotation support in RestTemplate & update example and readme on branch 1.x
parent
6509a2d2d1
commit
5fbe3e18d7
@ -0,0 +1,14 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
public class ExceptionUtil {
|
||||
|
||||
public static void handleException(BlockException ex) {
|
||||
System.out.println("Oops: " + ex.getClass().getCanonicalName());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,23 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo;
|
||||
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.CommandLineRunner;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.cloud.alibaba.cloud.examples.dubbo.provider.ProviderApplication;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
@Component
|
||||
public class DubboProviderRunner implements CommandLineRunner {
|
||||
|
||||
@Override
|
||||
public void run(String... args) throws Exception {
|
||||
SpringApplicationBuilder providerBuilder = new SpringApplicationBuilder()
|
||||
.bannerMode(Banner.Mode.OFF).registerShutdownHook(false)
|
||||
.logStartupInfo(false).web(false);
|
||||
providerBuilder.sources(ProviderApplication.class).run(args);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,10 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
public interface FooService {
|
||||
|
||||
String hello(String name);
|
||||
|
||||
}
|
@ -0,0 +1,82 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.consumer;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
import org.springframework.boot.Banner;
|
||||
import org.springframework.boot.builder.SpringApplicationBuilder;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.RuleConstant;
|
||||
import com.alibaba.csp.sentinel.slots.block.SentinelRpcException;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRule;
|
||||
import com.alibaba.csp.sentinel.slots.block.flow.FlowRuleManager;
|
||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
||||
import com.alibaba.dubbo.config.ConsumerConfig;
|
||||
import com.alibaba.dubbo.config.RegistryConfig;
|
||||
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
@DubboComponentScan("org.springframework.cloud.alibaba.cloud.examples.dubbo.provider")
|
||||
public class ConsumerApplication {
|
||||
|
||||
@Bean
|
||||
public ApplicationConfig applicationConfig() {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setName("demo-consumer");
|
||||
return applicationConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RegistryConfig registryConfig() {
|
||||
RegistryConfig registryConfig = new RegistryConfig();
|
||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ConsumerConfig consumerConfig() {
|
||||
ConsumerConfig consumerConfig = new ConsumerConfig();
|
||||
return consumerConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public FooServiceConsumer annotationDemoServiceConsumer() {
|
||||
return new FooServiceConsumer();
|
||||
}
|
||||
|
||||
public static void main(String[] args) {
|
||||
|
||||
SpringApplicationBuilder consumerBuilder = new SpringApplicationBuilder()
|
||||
.bannerMode(Banner.Mode.OFF).registerShutdownHook(false)
|
||||
.logStartupInfo(false).web(false);
|
||||
ApplicationContext applicationContext = consumerBuilder
|
||||
.sources(ConsumerApplication.class).run(args);
|
||||
|
||||
FlowRule flowRule = new FlowRule();
|
||||
flowRule.setResource(
|
||||
"org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService:hello(java.lang.String)");
|
||||
flowRule.setCount(10);
|
||||
flowRule.setGrade(RuleConstant.FLOW_GRADE_QPS);
|
||||
flowRule.setLimitApp("default");
|
||||
FlowRuleManager.loadRules(Collections.singletonList(flowRule));
|
||||
|
||||
FooServiceConsumer service = applicationContext.getBean(FooServiceConsumer.class);
|
||||
|
||||
for (int i = 0; i < 15; i++) {
|
||||
try {
|
||||
String message = service.hello("Jim");
|
||||
System.out.println((i + 1) + " -> Success: " + message);
|
||||
}
|
||||
catch (SentinelRpcException ex) {
|
||||
System.out.println("Blocked");
|
||||
}
|
||||
catch (Exception ex) {
|
||||
ex.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,19 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.consumer;
|
||||
|
||||
import org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService;
|
||||
|
||||
import com.alibaba.dubbo.config.annotation.Reference;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
public class FooServiceConsumer {
|
||||
|
||||
@Reference(url = "dubbo://127.0.0.1:25758", timeout = 3000)
|
||||
private FooService fooService;
|
||||
|
||||
public String hello(String name) {
|
||||
return fooService.hello(name);
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,17 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.provider;
|
||||
|
||||
import org.springframework.cloud.alibaba.cloud.examples.dubbo.FooService;
|
||||
|
||||
import com.alibaba.dubbo.config.annotation.Service;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
@Service
|
||||
public class FooServiceImpl implements FooService {
|
||||
|
||||
@Override
|
||||
public String hello(String name) {
|
||||
return "hello, " + name;
|
||||
}
|
||||
}
|
@ -0,0 +1,38 @@
|
||||
package org.springframework.cloud.alibaba.cloud.examples.dubbo.provider;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
import com.alibaba.dubbo.config.ApplicationConfig;
|
||||
import com.alibaba.dubbo.config.ProtocolConfig;
|
||||
import com.alibaba.dubbo.config.RegistryConfig;
|
||||
import com.alibaba.dubbo.config.spring.context.annotation.DubboComponentScan;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
@DubboComponentScan("org.springframework.cloud.alibaba.cloud.examples.dubbo.provider")
|
||||
public class ProviderApplication {
|
||||
|
||||
@Bean
|
||||
public ApplicationConfig applicationConfig() {
|
||||
ApplicationConfig applicationConfig = new ApplicationConfig();
|
||||
applicationConfig.setName("demo-provider");
|
||||
return applicationConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public RegistryConfig registryConfig() {
|
||||
RegistryConfig registryConfig = new RegistryConfig();
|
||||
registryConfig.setAddress("multicast://224.5.6.7:1234");
|
||||
return registryConfig;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public ProtocolConfig protocolConfig() {
|
||||
ProtocolConfig protocolConfig = new ProtocolConfig();
|
||||
protocolConfig.setName("dubbo");
|
||||
protocolConfig.setPort(25758);
|
||||
return protocolConfig;
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
/**
|
||||
* @author fangjian
|
||||
*/
|
||||
final class BlockClassRegistry {
|
||||
|
||||
private static final Map<String, Method> FALLBACK_MAP = new ConcurrentHashMap<>();
|
||||
private static final Map<String, Method> BLOCK_HANDLER_MAP = new ConcurrentHashMap<>();
|
||||
|
||||
static Method lookupFallback(Class<?> clazz, String name) {
|
||||
return FALLBACK_MAP.get(getKey(clazz, name));
|
||||
}
|
||||
|
||||
static Method lookupBlockHandler(Class<?> clazz, String name) {
|
||||
return BLOCK_HANDLER_MAP.get(getKey(clazz, name));
|
||||
}
|
||||
|
||||
static void updateFallbackFor(Class<?> clazz, String name, Method method) {
|
||||
if (clazz == null || StringUtil.isBlank(name)) {
|
||||
throw new IllegalArgumentException("Bad argument");
|
||||
}
|
||||
FALLBACK_MAP.put(getKey(clazz, name), method);
|
||||
}
|
||||
|
||||
static void updateBlockHandlerFor(Class<?> clazz, String name, Method method) {
|
||||
if (clazz == null || StringUtil.isBlank(name)) {
|
||||
throw new IllegalArgumentException("Bad argument");
|
||||
}
|
||||
BLOCK_HANDLER_MAP.put(getKey(clazz, name), method);
|
||||
}
|
||||
|
||||
private static String getKey(Class<?> clazz, String name) {
|
||||
return String.format("%s:%s", clazz.getCanonicalName(), name);
|
||||
}
|
||||
|
||||
}
|
@ -1,46 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
public class HandlerUtil {
|
||||
|
||||
private static final ConcurrentHashMap<String, SentinelBlockHandler> map = new ConcurrentHashMap<>(
|
||||
16);
|
||||
|
||||
/**
|
||||
* you should add your custom handler before use it
|
||||
* @param name see {@link EnableSentinel#handler()}
|
||||
* @param handler you custom handler
|
||||
*/
|
||||
public static void addHandler(String name, SentinelBlockHandler handler) {
|
||||
map.put(name, handler);
|
||||
}
|
||||
|
||||
public static SentinelBlockHandler getHandler(String name) {
|
||||
SentinelBlockHandler handler = map.get(name);
|
||||
if (null == handler) {
|
||||
throw new RuntimeException("cannot find handler name=<" + name
|
||||
+ ",> did you forgot to invoke HandlerUtil.addHandler(name, handler) ?");
|
||||
}
|
||||
return handler;
|
||||
}
|
||||
}
|
@ -1,109 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
import org.aspectj.lang.ProceedingJoinPoint;
|
||||
import org.aspectj.lang.annotation.Around;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.reflect.MethodSignature;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
@Aspect
|
||||
public class SentinelAspect {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory.getLogger(SentinelAspect.class);
|
||||
|
||||
@Around("@annotation(org.springframework.cloud.alibaba.sentinel.custom.EnableSentinel)")
|
||||
public Object customBlock(ProceedingJoinPoint pjp) throws Throwable {
|
||||
SentinelEntry sentinelEntry = new SentinelEntry();
|
||||
try {
|
||||
beforeProceed(sentinelEntry, pjp);
|
||||
return pjp.proceed();
|
||||
}
|
||||
catch (BlockException e) {
|
||||
LOGGER.error(e.getMessage(), e);
|
||||
if (null != sentinelEntry.getHandler()
|
||||
&& sentinelEntry.getHandler().length() > 0) {
|
||||
return HandlerUtil.getHandler(sentinelEntry.getHandler()).handler(e);
|
||||
}
|
||||
else {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
finally {
|
||||
releaseContextResources(sentinelEntry);
|
||||
}
|
||||
}
|
||||
|
||||
private void beforeProceed(SentinelEntry sentinelEntry, ProceedingJoinPoint pjp)
|
||||
throws BlockException {
|
||||
Method method = getMethod(pjp);
|
||||
|
||||
int modifiers = method.getModifiers();
|
||||
|
||||
if (!Modifier.isPublic(modifiers) || "toString".equals(method.getName())
|
||||
|| "hashCode".equals(method.getName())
|
||||
|| "equals".equals(method.getName())
|
||||
|| "finalize".equals(method.getName())) {
|
||||
return;
|
||||
}
|
||||
|
||||
Annotation[] annotations = method.getDeclaredAnnotations();
|
||||
for (Annotation annotation : annotations) {
|
||||
if (annotation instanceof EnableSentinel) {
|
||||
sentinelEntry.setKey(((EnableSentinel) annotation).value());
|
||||
sentinelEntry.setHandler(((EnableSentinel) annotation).handler());
|
||||
}
|
||||
}
|
||||
if (null == sentinelEntry.getKey() || sentinelEntry.getKey().length() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
ContextUtil.enter(sentinelEntry.getKey());
|
||||
sentinelEntry.setEntry(SphU.entry(sentinelEntry.getKey()));
|
||||
}
|
||||
|
||||
private void releaseContextResources(SentinelEntry sentinelEntry) {
|
||||
|
||||
if (null == sentinelEntry.getEntry()) {
|
||||
return;
|
||||
}
|
||||
|
||||
Entry entry = sentinelEntry.getEntry();
|
||||
entry.exit();
|
||||
ContextUtil.exit();
|
||||
}
|
||||
|
||||
private Method getMethod(ProceedingJoinPoint joinPoint) {
|
||||
MethodSignature signature = (MethodSignature) joinPoint.getSignature();
|
||||
return signature.getMethod();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import com.alibaba.csp.sentinel.annotation.aspectj.SentinelResourceAspect;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
@Configuration
|
||||
public class SentinelAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
public SentinelResourceAspect sentinelResourceAspect() {
|
||||
return new SentinelResourceAspect();
|
||||
}
|
||||
|
||||
@Bean
|
||||
@ConditionalOnMissingBean
|
||||
@ConditionalOnClass(value = RestTemplate.class)
|
||||
public SentinelBeanPostProcessor sentinelBeanPostProcessor() {
|
||||
return new SentinelBeanPostProcessor();
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.config.BeanDefinition;
|
||||
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
|
||||
import org.springframework.beans.factory.support.DefaultListableBeanFactory;
|
||||
import org.springframework.beans.factory.support.MergedBeanDefinitionPostProcessor;
|
||||
import org.springframework.beans.factory.support.RootBeanDefinition;
|
||||
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.core.type.StandardMethodMetadata;
|
||||
import org.springframework.util.StringUtils;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* PostProcessor handle @SentinelProtect Annotation, add interceptor for RestTemplate
|
||||
*
|
||||
* @author fangjian
|
||||
* @see SentinelProtect
|
||||
* @see SentinelProtectInterceptor
|
||||
*/
|
||||
public class SentinelBeanPostProcessor implements MergedBeanDefinitionPostProcessor {
|
||||
|
||||
@Autowired
|
||||
private ApplicationContext applicationContext;
|
||||
|
||||
private ConcurrentHashMap<String, SentinelProtect> cache = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void postProcessMergedBeanDefinition(RootBeanDefinition beanDefinition,
|
||||
Class<?> beanType, String beanName) {
|
||||
if (checkSentinelProtect(beanDefinition, beanType)) {
|
||||
SentinelProtect sentinelProtect = ((StandardMethodMetadata) beanDefinition
|
||||
.getSource()).getIntrospectedMethod()
|
||||
.getAnnotation(SentinelProtect.class);
|
||||
cache.put(beanName, sentinelProtect);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean checkSentinelProtect(RootBeanDefinition beanDefinition,
|
||||
Class<?> beanType) {
|
||||
return beanType == RestTemplate.class
|
||||
&& beanDefinition.getSource() instanceof StandardMethodMetadata
|
||||
&& ((StandardMethodMetadata) beanDefinition.getSource())
|
||||
.isAnnotated(SentinelProtect.class.getName());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessAfterInitialization(Object bean, String beanName)
|
||||
throws BeansException {
|
||||
if (cache.containsKey(beanName)) {
|
||||
// add interceptor for each RestTemplate with @SentinelProtect annotation
|
||||
StringBuilder interceptorBeanName = new StringBuilder();
|
||||
SentinelProtect sentinelProtect = cache.get(beanName);
|
||||
interceptorBeanName
|
||||
.append(StringUtils.uncapitalize(
|
||||
SentinelProtectInterceptor.class.getSimpleName()))
|
||||
.append("_")
|
||||
.append(sentinelProtect.blockHandlerClass().getSimpleName())
|
||||
.append(sentinelProtect.blockHandler()).append("_")
|
||||
.append(sentinelProtect.fallbackClass().getSimpleName())
|
||||
.append(sentinelProtect.fallback());
|
||||
RestTemplate restTemplate = (RestTemplate) bean;
|
||||
registerBean(interceptorBeanName.toString(), sentinelProtect);
|
||||
SentinelProtectInterceptor sentinelProtectInterceptor = applicationContext
|
||||
.getBean(interceptorBeanName.toString(),
|
||||
SentinelProtectInterceptor.class);
|
||||
restTemplate.getInterceptors().add(sentinelProtectInterceptor);
|
||||
}
|
||||
return bean;
|
||||
}
|
||||
|
||||
private void registerBean(String interceptorBeanName,
|
||||
SentinelProtect sentinelProtect) {
|
||||
// register SentinelProtectInterceptor bean
|
||||
DefaultListableBeanFactory beanFactory = (DefaultListableBeanFactory) applicationContext
|
||||
.getAutowireCapableBeanFactory();
|
||||
BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder
|
||||
.genericBeanDefinition(SentinelProtectInterceptor.class);
|
||||
beanDefinitionBuilder.addConstructorArgValue(sentinelProtect);
|
||||
BeanDefinition interceptorBeanDefinition = beanDefinitionBuilder
|
||||
.getRawBeanDefinition();
|
||||
beanFactory.registerBeanDefinition(interceptorBeanName,
|
||||
interceptorBeanDefinition);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
|
||||
return bean;
|
||||
}
|
||||
|
||||
}
|
@ -1,34 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
|
||||
/**
|
||||
* Sentinel Block Handler
|
||||
* @author xiaojing
|
||||
*/
|
||||
public interface SentinelBlockHandler {
|
||||
|
||||
/**
|
||||
* custom method to process BlockException
|
||||
* @param e block exception when blocked by sentinel
|
||||
* @return Object result processed by the handler
|
||||
*/
|
||||
Object handler(BlockException e);
|
||||
|
||||
}
|
@ -1,30 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
|
||||
/**
|
||||
* @author xiaojing
|
||||
*/
|
||||
public class SentinelCustomAspectAutoConfiguration {
|
||||
|
||||
@Bean
|
||||
public SentinelAspect sentinelAspect() {
|
||||
return new SentinelAspect();
|
||||
}
|
||||
}
|
@ -0,0 +1,139 @@
|
||||
/*
|
||||
* Copyright (C) 2018 the original author or authors.
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* http://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 org.springframework.cloud.alibaba.sentinel.custom;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URI;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.cloud.alibaba.sentinel.annotation.SentinelProtect;
|
||||
import org.springframework.http.HttpRequest;
|
||||
import org.springframework.http.client.ClientHttpRequestExecution;
|
||||
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||
import org.springframework.http.client.ClientHttpResponse;
|
||||
import org.springframework.util.ClassUtils;
|
||||
|
||||
import com.alibaba.csp.sentinel.Entry;
|
||||
import com.alibaba.csp.sentinel.SphU;
|
||||
import com.alibaba.csp.sentinel.context.ContextUtil;
|
||||
import com.alibaba.csp.sentinel.slots.block.BlockException;
|
||||
import com.alibaba.csp.sentinel.slots.block.degrade.DegradeException;
|
||||
import com.alibaba.csp.sentinel.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Interceptor using by SentinelProtect and SentinelProtectInterceptor
|
||||
*
|
||||
* @author fangjian
|
||||
*/
|
||||
public class SentinelProtectInterceptor implements ClientHttpRequestInterceptor {
|
||||
|
||||
private static final Logger LOGGER = LoggerFactory
|
||||
.getLogger(SentinelProtectInterceptor.class);
|
||||
|
||||
private SentinelProtect sentinelProtect;
|
||||
|
||||
public SentinelProtectInterceptor(SentinelProtect sentinelProtect) {
|
||||
this.sentinelProtect = sentinelProtect;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ClientHttpResponse intercept(HttpRequest request, byte[] body,
|
||||
ClientHttpRequestExecution execution) throws IOException {
|
||||
URI uri = request.getURI();
|
||||
String hostResource = uri.getScheme() + "://" + uri.getHost() + ":"
|
||||
+ (uri.getPort() == -1 ? 80 : uri.getPort());
|
||||
String hostWithPathResource = hostResource + uri.getPath();
|
||||
Entry hostEntry = null, hostWithPathEntry = null;
|
||||
ClientHttpResponse response = null;
|
||||
try {
|
||||
ContextUtil.enter(hostWithPathResource);
|
||||
hostWithPathEntry = SphU.entry(hostWithPathResource);
|
||||
hostEntry = SphU.entry(hostResource);
|
||||
response = execution.execute(request, body);
|
||||
}
|
||||
catch (BlockException e) {
|
||||
LOGGER.error("RestTemplate block", e);
|
||||
try {
|
||||
handleBlockException(e);
|
||||
}
|
||||
catch (Exception ex) {
|
||||
LOGGER.error("sentinel handle BlockException error.", e);
|
||||
}
|
||||
}
|
||||
finally {
|
||||
if (hostEntry != null) {
|
||||
hostEntry.exit();
|
||||
}
|
||||
if (hostWithPathEntry != null) {
|
||||
hostWithPathEntry.exit();
|
||||
}
|
||||
ContextUtil.exit();
|
||||
}
|
||||
return response;
|
||||
}
|
||||
|
||||
private void handleBlockException(BlockException ex) throws Exception {
|
||||
Object[] args = new Object[] { ex };
|
||||
// handle degrade
|
||||
if (isDegradeFailure(ex)) {
|
||||
Method method = extractFallbackMethod(sentinelProtect.fallback(),
|
||||
sentinelProtect.fallbackClass());
|
||||
if (method != null) {
|
||||
method.invoke(null, args);
|
||||
}
|
||||
}
|
||||
// handle block
|
||||
Method blockHandler = extractBlockHandlerMethod(sentinelProtect.blockHandler(),
|
||||
sentinelProtect.blockHandlerClass());
|
||||
if (blockHandler != null) {
|
||||
blockHandler.invoke(null, args);
|
||||
}
|
||||
}
|
||||
|
||||
private Method extractFallbackMethod(String fallback, Class<?> fallbackClass) {
|
||||
if (StringUtil.isBlank(fallback) || fallbackClass == void.class) {
|
||||
return null;
|
||||
}
|
||||
Method cachedMethod = BlockClassRegistry.lookupFallback(fallbackClass, fallback);
|
||||
if (cachedMethod == null) {
|
||||
cachedMethod = ClassUtils.getStaticMethod(fallbackClass, fallback,
|
||||
BlockException.class);
|
||||
BlockClassRegistry.updateFallbackFor(fallbackClass, fallback, cachedMethod);
|
||||
}
|
||||
return cachedMethod;
|
||||
}
|
||||
|
||||
private Method extractBlockHandlerMethod(String block, Class<?> blockClass) {
|
||||
if (StringUtil.isBlank(block) || blockClass == void.class) {
|
||||
return null;
|
||||
}
|
||||
Method cachedMethod = BlockClassRegistry.lookupBlockHandler(blockClass, block);
|
||||
if (cachedMethod == null) {
|
||||
cachedMethod = ClassUtils.getStaticMethod(blockClass, block,
|
||||
BlockException.class);
|
||||
BlockClassRegistry.updateBlockHandlerFor(blockClass, block, cachedMethod);
|
||||
}
|
||||
return cachedMethod;
|
||||
}
|
||||
|
||||
private boolean isDegradeFailure(BlockException ex) {
|
||||
return ex instanceof DegradeException;
|
||||
}
|
||||
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
|
||||
org.springframework.cloud.alibaba.sentinel.SentinelWebAutoConfiguration,\
|
||||
org.springframework.cloud.alibaba.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
|
||||
org.springframework.cloud.alibaba.sentinel.custom.SentinelCustomAspectAutoConfiguration
|
||||
org.springframework.cloud.alibaba.sentinel.custom.SentinelAutoConfiguration
|
||||
|
Loading…
Reference in New Issue