美文网首页
sentinel-starter自动配置客户端

sentinel-starter自动配置客户端

作者: Gason_d796 | 来源:发表于2020-09-09 14:30 被阅读0次

sentnel中启动时要加相关参数,所以自己写一个springboot的自动配置

项目目录

image.png

pom文件依赖(项目名称和sentinel的版本自己加)


    <dependencies>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-dubbo-adapter</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
            <version>${spring-boot.version}</version>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-autoconfigure</artifactId>
            <version>${spring-boot.version}</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <version>${spring-boot.version}</version>
            <optional>true</optional>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-transport-simple-http</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-core</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-annotation-aspectj</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-datasource-zookeeper</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-api-gateway-adapter-common</artifactId>
            <version>${sentinel.version}</version>
        </dependency>


        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-web-servlet</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-parameter-flow-control</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-cluster-client-default</artifactId>
            <version>${sentinel.version}</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba.csp</groupId>
            <artifactId>sentinel-cluster-server-default</artifactId>
            <version>${sentinel.version}</version>
        </dependency>
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.8.3</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
        </dependency>
    </dependencies>

代码

  • SentinelConfiguration
@Configuration
@EnableConfigurationProperties(SentinelProperties.class)
public class SentinelConfiguration implements InitializingBean {

    public static final String LOG_DIR_PROP = "csp.sentinel.log.dir";
    public static final String PRO_NAME_PROP = "project.name";
    public static final String APP_NAME_PROP = "spring.application.name";
    public static final String DUBBO_PRO = "java.net.preferIPv4Stack";
    @Autowired
    private SentinelProperties sentinelProperties;

    @Autowired
    private Environment env;

    // 为了让默认异常注册代码优先执行
//    static {
//        ExceptionRegistry.updateForPackage("com.xmutca.sentinel.dubbo.starter.exception");
//    }

    /**
     * 熔断器注解支持
     *
     * @return
     */
    @Bean
    public SentinelResourceAspect sentinelResourceAspect() {
        return new SentinelResourceAspect();
    }

    @Override
    public void afterPropertiesSet() throws Exception {


        // 设置日志地址
        if (StringUtil.isBlank(System.getProperty(LOG_DIR_PROP))
                && StringUtil.isNotBlank(sentinelProperties.getApplication().getLogDir())) {
            System.setProperty(LOG_DIR_PROP, sentinelProperties.getApplication().getLogDir());
        }

        // 设置项目名称
        if (StringUtil.isBlank(System.getProperty(PRO_NAME_PROP))) {
            String name = env.getProperty(PRO_NAME_PROP);
            if (StringUtil.isBlank(name)) {
                name = sentinelProperties.getApplication().getName();
            }

            if (StringUtil.isBlank(name)) {
                name = env.getProperty(APP_NAME_PROP);
            }

            if (StringUtil.isNotBlank(name)) {
                System.setProperty(PRO_NAME_PROP, name);
            }
        }

        if (StringUtil.isBlank(System.getProperty(DUBBO_PRO))) {
            if (sentinelProperties.getApplication().isDubbo()) {
                System.setProperty(DUBBO_PRO, "true");
            }
        }
        // 设置主页
        if (StringUtil.isNotBlank(sentinelProperties.getApplication().getDashboard())) {
            SentinelConfig.setConfig(TransportConfig.CONSOLE_SERVER, sentinelProperties.getApplication().getDashboard());
        }

        // 设置端口
        if (StringUtil.isNotBlank(sentinelProperties.getApplication().getPort())) {
            SentinelConfig.setConfig(TransportConfig.SERVER_PORT, sentinelProperties.getApplication().getPort());
        }
        // 注册降级统一返回码
        WebCallbackManager.setUrlBlockHandler(new SnfGlobalUrlBlockHandler());
    }

    /**
     * zookeeper的datasource注册
     */
    @Configuration
    @ConditionalOnProperty(name = "sentinel.zookeeper.enable", havingValue = "true")
    public class ZookeeperDataSourceConfiguration implements InitializingBean {

        // 要与sentinel-dashboard中的路由规则相匹配
        public static final String FLOW_RULE_PATH = "/sentinel_rule_config/%s/flow";
        public static final String AUTHORITY_RULE_PATH = "/sentinel_rule_config/%s/authority";
        public static final String DEGRADE_RULE_PATH = "/sentinel_rule_config/%s/degrade";
        public static final String PARAM_FLOW_RULE_PATH = "/sentinel_rule_config/%s/param";
        public static final String SYSTEM_RULE_PATH = "/sentinel_rule_config/%s/system";
        public static final String GATEWAY_RULE_PATH = "/sentinel_rule_config/%s/gateway";
        public static final String GATEWAY_API_RULE_PATH = "/sentinel_rule_config/%s/apidefinition";

        @Override
        public void afterPropertiesSet() throws Exception {
            ReadableDataSource<String, List<FlowRule>> flowRuleDataSource = new ZookeeperDataSource<>(sentinelProperties.getZookeeper().getAddress(),
                    String.format(FLOW_RULE_PATH, AppNameUtil.getAppName()),
                    source -> JSON.parseObject(source, new TypeReference<List<FlowRule>>() {
                    }));
            FlowRuleManager.register2Property(flowRuleDataSource.getProperty());

            ReadableDataSource<String, List<AuthorityRule>> authorityRleDataSource = new ZookeeperDataSource<>(sentinelProperties.getZookeeper().getAddress(),
                    String.format(AUTHORITY_RULE_PATH, AppNameUtil.getAppName()),
                    source -> JSON.parseObject(source, new TypeReference<List<AuthorityRule>>() {
                    }));
            AuthorityRuleManager.register2Property(authorityRleDataSource.getProperty());

            ReadableDataSource<String, List<DegradeRule>> degradeRleDataSource = new ZookeeperDataSource<>(sentinelProperties.getZookeeper().getAddress(),
                    String.format(DEGRADE_RULE_PATH, AppNameUtil.getAppName()),
                    source -> JSON.parseObject(source, new TypeReference<List<DegradeRule>>() {
                    }));
            DegradeRuleManager.register2Property(degradeRleDataSource.getProperty());

            ReadableDataSource<String, List<ParamFlowRule>> paramFlowRleDataSource = new ZookeeperDataSource<>(sentinelProperties.getZookeeper().getAddress(),
                    String.format(PARAM_FLOW_RULE_PATH, AppNameUtil.getAppName()),
                    source -> JSON.parseObject(source, new TypeReference<List<ParamFlowRule>>() {
                    }));
            ParamFlowRuleManager.register2Property(paramFlowRleDataSource.getProperty());

            ReadableDataSource<String, List<SystemRule>> systemRuleDataSource = new ZookeeperDataSource<>(sentinelProperties.getZookeeper().getAddress(),
                    String.format(SYSTEM_RULE_PATH, AppNameUtil.getAppName()),
                    source -> JSON.parseObject(source, new TypeReference<List<SystemRule>>() {
                    }));
            SystemRuleManager.register2Property(systemRuleDataSource.getProperty());

            ReadableDataSource<String, Set<GatewayFlowRule>> gatewayRuleDataSource = new ZookeeperDataSource<>(sentinelProperties.getZookeeper().getAddress(),
                    String.format(GATEWAY_RULE_PATH, AppNameUtil.getAppName()),
                    source -> JSON.parseObject(source, new TypeReference<Set<GatewayFlowRule>>() {
                    }));
            GatewayRuleManager.register2Property(gatewayRuleDataSource.getProperty());

            ReadableDataSource<String, Set<ApiDefinition>> gatewayApiRuleDataSource = new ZookeeperDataSource<>(sentinelProperties.getZookeeper().getAddress(),
                    String.format(GATEWAY_API_RULE_PATH, AppNameUtil.getAppName()),
                    source -> JSON.parseObject(source, new TypeReference<Set<ApiDefinition>>() {
                    }));
            GatewayApiDefinitionManager.register2Property(gatewayApiRuleDataSource.getProperty());
        }
    }


    @Bean
    public FilterRegistrationBean sentinelFilterRegistration() {
        FilterRegistrationBean<Filter> registration = new FilterRegistrationBean<>();
        registration.setFilter(new CommonFilter());
        registration.addUrlPatterns("/*");
        registration.setName("sentinelFilter");
        registration.setOrder(1);
        // If this is enabled, the entrance of all Web URL resources will be unified as a single context name.
        // In most scenarios that's enough, and it could reduce the memory footprint.
        registration.addInitParameter(CommonFilter.WEB_CONTEXT_UNIFY, "true");
        return registration;
    }
}

  • SentinelProperties
@ConfigurationProperties(prefix = "sentinel")
public class SentinelProperties {

    /**
     * 应用配置
     */
    private ApplicationProperties application;

    /**
     * zk配置
     */
    private ZookeeperProperties zookeeper;

    public void setApplication(ApplicationProperties application) {
        this.application = application;
    }

    public ZookeeperProperties getZookeeper() {
        return zookeeper;
    }

    public void setZookeeper(ZookeeperProperties zookeeper) {
        this.zookeeper = zookeeper;
    }

    /**
     * 应用配置
     */
    public static class ApplicationProperties {

        /**
         * 客户端的 port,用于上报相关信息(默认为 8719), 同台机器上由多台时,需要指定不同的端口
         */
        private String port;

        /**
         * 控制台的地址 IP + 端口
         */
        private String dashboard;

        /**
         * 应用名称,会在控制台中显示
         */
        private String name;

        /**
         * 日志地址
         */
        private String logDir;

        /**
         * 是否为dubbo服务
         */
        private boolean dubbo;

        public boolean isDubbo() {
            return dubbo;
        }

        public void setDubbo(boolean dubbo) {
            this.dubbo = dubbo;
        }

        public String getPort() {
            return port;
        }

        public void setPort(String port) {
            this.port = port;
        }

        public String getDashboard() {
            return dashboard;
        }

        public void setDashboard(String dashboard) {
            this.dashboard = dashboard;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        public String getLogDir() {
            return logDir;
        }

        public void setLogDir(String logDir) {
            this.logDir = logDir;
        }
    }


    /**
     * zookeeper配置文件
     */
    public static class ZookeeperProperties {

        /**
         * 服务器地址
         */
        private String address;

        /**
         * 睡眠时间
         */
        private int sleepTimeMs = 100;

        /**
         * 最大重试
         */
        private int maxRetries = 3;

        /**
         * 是否开启
         */
        private boolean enable;

        public String getAddress() {
            return address;
        }

        public void setAddress(String address) {
            this.address = address;
        }

        public int getSleepTimeMs() {
            return sleepTimeMs;
        }

        public void setSleepTimeMs(int sleepTimeMs) {
            this.sleepTimeMs = sleepTimeMs;
        }

        public int getMaxRetries() {
            return maxRetries;
        }

        public void setMaxRetries(int maxRetries) {
            this.maxRetries = maxRetries;
        }

        public boolean isEnable() {
            return enable;
        }

        public void setEnable(boolean enable) {
            this.enable = enable;
        }
    }

    public ApplicationProperties getApplication() {
        if (null == application) {
            application = new ApplicationProperties();
        }
        return application;
    }
}

  • SnfGlobalUrlBlockHandler(全局降级返回参数)
public class SnfGlobalUrlBlockHandler implements UrlBlockHandler {
    @Override
    public void blocked(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, BlockException e) throws IOException {

        Result errorMsg = new Result();
        // 限流
        if(e instanceof FlowException){
          errorMsg.setStatus(Result.Status.FLOW_ERR);
          errorMsg.setMessage("限流了");
        }
        // 降级
        else if(e instanceof DegradeException){
            errorMsg.setStatus(Result.Status.DEGRADE_ERR);
            errorMsg.setMessage("限流了");
        }

        // 参数热点
        else  if(e instanceof ParamFlowException){
            errorMsg.setStatus(Result.Status.PARAM_FLOW_ERR);
            errorMsg.setMessage("热点参数限流");
        }
        // 系统异常
        else if(e instanceof SystemBlockException){
            errorMsg.setStatus(Result.Status.SYSTEM_ERR);
            errorMsg.setMessage("系统规则(负载,...)不满足规则");
        }
        // 授权异常
        else  if(e instanceof AuthorityException){
            errorMsg.setStatus(Result.Status.AUTHORITY_ERR);
            errorMsg.setMessage("授权规则不通过");
        }
        httpServletResponse.setStatus(500);
        httpServletResponse.setCharacterEncoding("utf-8");
        httpServletResponse.setHeader("Content-Type","application/json;charset=utf-8");
        httpServletResponse.setContentType("application/json;charset=utf-8");
        new ObjectMapper().writeValue(httpServletResponse.getWriter(),errorMsg);
    }
}

  • Result
public class Result<T> implements Serializable {

    /**
     * 默认
     */
    public final static Result DEFAULT_ERROR_RESULT = new Result<>(Result.Status.ERROR, "系统开小差,熔断降级处理。");

    public enum Status {

        /**
         * 限流
         */
        FLOW_ERR(101),

        /**
         * 降级
         */
        DEGRADE_ERR(102),

        /**
         * 参数热点
         */
        PARAM_FLOW_ERR(103),

        /**
         * 授权
         */
        AUTHORITY_ERR(104),

        /**
         * 系统
         */
        SYSTEM_ERR(105),

        /**
         * 业务处理成功
         */
        SUCCESS(200),

        /**
         * 页面重定向
         */
        REDIRECT(302),

        /**
         * 错误请求
         */
        BAD_REQUEST(400),

        /**
         * 请进行登陆
         */
        UNAUTHORIZED(401),

        /**
         * 权限代码
         */
        FORBIDDEN(403),

        /**
         * 页面不存在
         */
        NOT_FOUND(404),

        /**
         * 无法满足条件的,认定为攻击
         */
        NOT_ACCEPTABLE(406),

        /**
         * 请求超时
         */
        REQUEST_TIMEOUT(408),

        /**
         * 请求过多降级
         */
        TOO_MANY_REQUESTS(429),

        /**
         * 业务访问失败
         */
        ERROR(500),

        /**
         * 请求失败
         */
        BAD_GATEWAY(502),

        /**
         * 网关超时
         */
        GATEWAY_TIMEOUT(504);

        private int code;

        Status(int code) {
            this.code = code;
        }

        public int getCode() {
            return code;
        }

        @Override
        public String toString() {
            return String.valueOf(getCode());
        }

        public static Status getInstance(int code) {
            Optional<Status> op = Arrays.asList(Status.values()).parallelStream().filter(currentStatus -> currentStatus.code == code).findFirst();
            if (op.isPresent()) {
                return op.get();
            }
            return null;
        }
    }

    /**
     * 消息
     */
    private String message;

    /**
     * 状态
     */
    private Status status = Status.SUCCESS;

    /**
     * 时间戳
     */

    private Long timestamp = System.currentTimeMillis();

    /**
     * 数据
     */

    private T result;

    /**
     * 扩展信息
     */

    private Object extra;

    public static Result getDefaultErrorResult() {
        return DEFAULT_ERROR_RESULT;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }

    public Long getTimestamp() {
        return timestamp;
    }

    public void setTimestamp(Long timestamp) {
        this.timestamp = timestamp;
    }

    public T getResult() {
        return result;
    }

    public void setResult(T result) {
        this.result = result;
    }

    public Object getExtra() {
        return extra;
    }

    public void setExtra(Object extra) {
        this.extra = extra;
    }

    public Result() {

    }

    public Result(Status status) {
        this.status = status;
    }

    public Result(T result) {
        this.result = result;
    }

    public Result(Status status, String message) {
        this.status = status;
        this.message = message;
    }

    public Result(Status status, T result) {
        this.status = status;
        this.result = result;
    }

    public Result(String message, T result) {
        this.result = result;
        this.message = message;
    }

    public Result(Status status, String message, T result) {
        this.status = status;
        this.message = message;
        this.result = result;
    }

    public int getStatus() {
        return status.getCode();
    }

    public Status getStatusEnum() {
        return status;
    }

    public void setStatusEnum(Status status) {
        this.status = status;
    }

    public void setStatus(int status) {
        this.status = Status.getInstance(status);
    }

    public void setStatus(Status status) {
        this.status = status;
    }
}
  • SentinelAutoConfiguration

/**
 * @version
 * @author: zhongjias
 * @Date:
 */
@Configuration
@Import(SentinelConfiguration.class)
public class SentinelAutoConfiguration {
}

  • spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
xxx.xx.xx.SentinelAutoConfiguration (SentinelAutoConfiguration的路径)

使用时,工程引入这个starter,配置文件加入以下

image.png

相关文章

网友评论

      本文标题:sentinel-starter自动配置客户端

      本文链接:https://www.haomeiwen.com/subject/xmueektx.html