Commit 125b0ca7 by Nepxion

新增用户自定义和编程灰度路由策略

parent 1b5e6db3
<?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">
<artifactId>discovery-plugin-strategy-extension-service</artifactId>
<name>Nepxion Discovery Plugin Strategy Extension Service</name>
<packaging>jar</packaging>
<modelVersion>4.0.0</modelVersion>
<description>Nepxion Discovery is an enhancement for Spring Cloud Discovery</description>
<url>http://www.nepxion.com</url>
<parent>
<groupId>com.nepxion</groupId>
<artifactId>discovery</artifactId>
<version>4.1.9</version>
</parent>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>discovery-plugin-framework</artifactId>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>matrix-aop-starter</artifactId>
<version>${matrix.version}</version>
</dependency>
</dependencies>
</project>
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.aop;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.lang.annotation.Annotation;
import org.springframework.web.bind.annotation.RestController;
import com.nepxion.matrix.proxy.aop.DefaultAutoScanProxy;
import com.nepxion.matrix.proxy.mode.ProxyMode;
import com.nepxion.matrix.proxy.mode.ScanMode;
public class StrategyAutoScanProxy extends DefaultAutoScanProxy {
private static final long serialVersionUID = 6503834158946539913L;
private String[] commonInterceptorNames;
@SuppressWarnings("rawtypes")
private Class[] methodAnnotations;
public StrategyAutoScanProxy(String scanPackages) {
super(scanPackages, ProxyMode.BY_CLASS_ANNOTATION_ONLY, ScanMode.FOR_CLASS_ANNOTATION_ONLY);
}
@Override
protected String[] getCommonInterceptorNames() {
if (commonInterceptorNames == null) {
commonInterceptorNames = new String[] { "strategyInterceptor" };
}
return commonInterceptorNames;
}
@SuppressWarnings("unchecked")
@Override
protected Class<? extends Annotation>[] getClassAnnotations() {
if (methodAnnotations == null) {
methodAnnotations = new Class[] { RestController.class };
}
return methodAnnotations;
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.aop;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.LinkedHashMap;
import java.util.Map;
import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.lang3.ArrayUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.nepxion.discovery.plugin.strategy.extension.constant.StrategyConstant;
import com.nepxion.discovery.plugin.strategy.extension.context.StrategyContext;
import com.nepxion.discovery.plugin.strategy.extension.context.StrategyContextHolder;
import com.nepxion.matrix.proxy.aop.AbstractInterceptor;
public class StrategyInterceptor extends AbstractInterceptor {
private static final Logger LOG = LoggerFactory.getLogger(StrategyInterceptor.class);
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
Class<?> proxiedClass = getProxiedClass(invocation);
String methodName = getMethodName(invocation);
String[] methodParameterNames = getMethodParameterNames(invocation);
Object[] arguments = getArguments(invocation);
Map<String, Object> parameterMap = new LinkedHashMap<String, Object>();
if (ArrayUtils.isNotEmpty(arguments)) {
for (int i = 0; i < arguments.length; i++) {
String parameterName = null;
if (ArrayUtils.isNotEmpty(methodParameterNames)) {
parameterName = methodParameterNames[i];
} else {
parameterName = String.valueOf(i);
}
Object argument = arguments[i];
parameterMap.put(parameterName, argument);
}
}
LOG.debug("Context is set with class={}, methodName={}, parameterMap={}", proxiedClass, methodName, parameterMap);
StrategyContext context = StrategyContextHolder.currentContext();
context.add(StrategyConstant.CLASS, proxiedClass);
context.add(StrategyConstant.METHOD, methodName);
context.add(StrategyConstant.PARAMETER_MAP, parameterMap);
try {
return invocation.proceed();
} catch (Exception e) {
throw e;
} finally {
context.clear();
}
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.configuration;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.AutoConfigureBefore;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cloud.netflix.ribbon.RibbonClientConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import com.nepxion.discovery.plugin.strategy.extension.aop.StrategyAutoScanProxy;
import com.nepxion.discovery.plugin.strategy.extension.aop.StrategyInterceptor;
import com.nepxion.discovery.plugin.strategy.extension.constant.StrategyConstant;
import com.nepxion.discovery.plugin.strategy.extension.enable.DiscoveryEnabledAdapter;
import com.nepxion.discovery.plugin.strategy.extension.enable.DiscoveryEnabledPredicate;
import com.nepxion.discovery.plugin.strategy.extension.enable.DiscoveryEnabledRule;
@Configuration
@AutoConfigureBefore(RibbonClientConfiguration.class)
@ConditionalOnProperty(value = StrategyConstant.SPRING_APPLICATION_STRATEGY_CONTROL_ENABLED, matchIfMissing = true)
public class StrategyAutoConfiguration {
@Value("${" + StrategyConstant.SPRING_APPLICATION_STRATEGY_SCAN_PACKAGES + ":}")
private String scanPackages;
@Autowired
private DiscoveryEnabledAdapter discoveryEnabledAdapter;
@Bean
@ConditionalOnMissingBean
// @Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
public DiscoveryEnabledRule discoveryEnabledRule() {
DiscoveryEnabledRule discoveryEnabledRule = new DiscoveryEnabledRule();
DiscoveryEnabledPredicate discoveryEnabledPredicate = discoveryEnabledRule.getDiscoveryEnabledPredicate();
discoveryEnabledPredicate.setDiscoveryEnabledAdapter(discoveryEnabledAdapter);
return discoveryEnabledRule;
}
@Bean
@ConditionalOnProperty(value = StrategyConstant.SPRING_APPLICATION_STRATEGY_BUSINESS_CONTEXT_CONTROL_ENABLED, matchIfMissing = true)
public StrategyAutoScanProxy strategyAutoScanProxy() {
return new StrategyAutoScanProxy(scanPackages);
}
@Bean
@ConditionalOnProperty(value = StrategyConstant.SPRING_APPLICATION_STRATEGY_BUSINESS_CONTEXT_CONTROL_ENABLED, matchIfMissing = true)
public StrategyInterceptor strategyInterceptor() {
return new StrategyInterceptor();
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.constant;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
public class StrategyConstant {
public static final String SPRING_APPLICATION_STRATEGY_CONTROL_ENABLED = "spring.application.strategy.control.enabled";
public static final String SPRING_APPLICATION_STRATEGY_BUSINESS_CONTEXT_CONTROL_ENABLED = "spring.application.strategy.business.context.control.enabled";
public static final String SPRING_APPLICATION_STRATEGY_SCAN_PACKAGES = "spring.application.strategy.scan.packages";
public static final String CLASS = "class";
public static final String METHOD = "method";
public static final String PARAMETER_MAP = "parameterMap";
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.context;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.Map;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class StrategyContext {
private final Map<String, Object> attributes = new LinkedHashMap<String, Object>();
public StrategyContext add(String key, Object value) {
attributes.put(key, value);
return this;
}
public Object get(String key) {
return attributes.get(key);
}
public StrategyContext remove(String key) {
attributes.remove(key);
return this;
}
public StrategyContext clear() {
attributes.clear();
return this;
}
public Map<String, Object> getAttributes() {
return Collections.unmodifiableMap(attributes);
}
@Override
public int hashCode() {
return HashCodeBuilder.reflectionHashCode(this);
}
@Override
public boolean equals(Object object) {
return EqualsBuilder.reflectionEquals(this, object);
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.context;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
public class StrategyContextHolder {
private static final ThreadLocal<StrategyContext> HOLDER = new InheritableThreadLocal<StrategyContext>() {
@Override
protected StrategyContext initialValue() {
return new StrategyContext();
}
};
public static StrategyContext currentContext() {
return HOLDER.get();
}
public static void clearContext() {
HOLDER.remove();
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.enable;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import com.nepxion.discovery.plugin.strategy.extension.context.StrategyContext;
import com.netflix.loadbalancer.Server;
public interface DiscoveryEnabledAdapter {
boolean apply(Server server, StrategyContext context);
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.enable;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import javax.annotation.Nullable;
import com.nepxion.discovery.plugin.strategy.extension.context.StrategyContext;
import com.nepxion.discovery.plugin.strategy.extension.context.StrategyContextHolder;
import com.netflix.loadbalancer.AbstractServerPredicate;
import com.netflix.loadbalancer.PredicateKey;
import com.netflix.loadbalancer.Server;
public class DiscoveryEnabledPredicate extends AbstractServerPredicate {
private DiscoveryEnabledAdapter discoveryEnabledAdapter;
@Override
public boolean apply(@Nullable PredicateKey input) {
return input != null && apply(input.getServer());
}
protected boolean apply(Server server) {
StrategyContext context = StrategyContextHolder.currentContext();
return discoveryEnabledAdapter.apply(server, context);
}
public void setDiscoveryEnabledAdapter(DiscoveryEnabledAdapter discoveryEnabledAdapter) {
this.discoveryEnabledAdapter = discoveryEnabledAdapter;
}
}
\ No newline at end of file
package com.nepxion.discovery.plugin.strategy.extension.enable;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import org.springframework.util.Assert;
import com.netflix.loadbalancer.AbstractServerPredicate;
import com.netflix.loadbalancer.AvailabilityPredicate;
import com.netflix.loadbalancer.CompositePredicate;
import com.netflix.loadbalancer.PredicateBasedRule;
public class DiscoveryEnabledRule extends PredicateBasedRule {
private final CompositePredicate predicate;
private final DiscoveryEnabledPredicate discoveryEnabledPredicate;
public DiscoveryEnabledRule() {
this(new DiscoveryEnabledPredicate());
}
public DiscoveryEnabledRule(DiscoveryEnabledPredicate discoveryEnabledPredicate) {
Assert.notNull(discoveryEnabledPredicate, "Parameter 'discoveryEnabledPredicate' can't be null");
this.predicate = createCompositePredicate(discoveryEnabledPredicate, new AvailabilityPredicate(this, null));
this.discoveryEnabledPredicate = discoveryEnabledPredicate;
}
@Override
public AbstractServerPredicate getPredicate() {
return predicate;
}
public DiscoveryEnabledPredicate getDiscoveryEnabledPredicate() {
return discoveryEnabledPredicate;
}
private CompositePredicate createCompositePredicate(DiscoveryEnabledPredicate discoveryEnabledPredicate, AvailabilityPredicate availabilityPredicate) {
return CompositePredicate.withPredicates(discoveryEnabledPredicate, availabilityPredicate).build();
}
}
\ No newline at end of file
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.nepxion.discovery.plugin.strategy.extension.configuration.StrategyAutoConfiguration
\ No newline at end of file
package com.nepxion.discovery.plugin.example.extension;
/**
* <p>Title: Nepxion Discovery</p>
* <p>Description: Nepxion Discovery</p>
* <p>Copyright: Copyright (c) 2017-2050</p>
* <p>Company: Nepxion</p>
* @author Haojun Ren
* @version 1.0
*/
import java.util.Map;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.nepxion.discovery.plugin.framework.adapter.PluginAdapter;
import com.nepxion.discovery.plugin.strategy.extension.constant.StrategyConstant;
import com.nepxion.discovery.plugin.strategy.extension.context.StrategyContext;
import com.nepxion.discovery.plugin.strategy.extension.enable.DiscoveryEnabledAdapter;
import com.netflix.loadbalancer.Server;
public class MyDiscoveryEnabledAdapter implements DiscoveryEnabledAdapter {
private static final Logger LOG = LoggerFactory.getLogger(MyDiscoveryEnabledAdapter.class);
@Autowired
protected PluginAdapter pluginAdapter;
@SuppressWarnings("unchecked")
@Override
public boolean apply(Server server, StrategyContext context) {
String serviceId = server.getMetaInfo().getAppName().toLowerCase();
Map<String, String> metadata = pluginAdapter.getServerMetaData(server);
Map<String, Object> attributes = context.getAttributes();
LOG.info("负载均衡用户定制触发:serviceId={}, host={}, metadata={}, context={}", serviceId, server.toString(), metadata, context);
if (attributes.containsKey(StrategyConstant.PARAMETER_MAP)) {
Map<String, Object> parameterMap = (Map<String, Object>) attributes.get(StrategyConstant.PARAMETER_MAP);
String value = parameterMap.get("value").toString();
if (value.contains("abc")) {
LOG.info("过滤条件:当前端输入值包含'abc'的时候,不能被Ribbon负载均衡到");
return false;
}
}
/*String version = metadata.get(PluginConstant.VERSION);
if (StringUtils.equals(serviceId, "discovery-springcloud-example-c") && StringUtils.equals(version, "1.0")) {
LOG.info("过滤条件:当serviceId={},version={}的时候,不能被Ribbon负载均衡到", serviceId, version);
return false;
}*/
return true;
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment