sentinel 使用说明
sentinel 使用说明
相关依赖
<!-- sentinel starter --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-sentinel</artifactId></dependency><!-- dubbo限流适配器 --><dependency><groupId>com.alibaba.csp</groupId><artifactId>sentinel-apache-dubbo-adapter</artifactId></dependency><!-- sentinel规则存储 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-datasource</artifactId></dependency><!-- sentinel网关限流 --><dependency><groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-alibaba-sentinel-gateway</artifactId></dependency>
自动配置类
spring-cloud-starter-alibaba-sentinel/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.alibaba.cloud.sentinel.SentinelWebAutoConfiguration,\
com.alibaba.cloud.sentinel.SentinelWebFluxAutoConfiguration,\
com.alibaba.cloud.sentinel.endpoint.SentinelEndpointAutoConfiguration,\
com.alibaba.cloud.sentinel.custom.SentinelAutoConfiguration,\
com.alibaba.cloud.sentinel.feign.SentinelFeignAutoConfigurationorg.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker=\
com.alibaba.cloud.sentinel.custom.SentinelCircuitBreakerConfiguration
SentinelAutoConfiguration
@Configuration(proxyBeanMethods = false
)
@ConditionalOnProperty(name = {"spring.cloud.sentinel.enabled"},matchIfMissing = true
)
@EnableConfigurationProperties({SentinelProperties.class}) //从配置文件中读取数据,装配SentinelProperties类
public class SentinelAutoConfiguration {@Value("${project.name:${spring.application.name:}}")private String projectName;@Autowiredprivate SentinelProperties properties;public SentinelAutoConfiguration() {}@PostConstructprivate void init() { //初始化属性配置if (StringUtils.isEmpty(System.getProperty("csp.sentinel.log.dir")) && StringUtils.hasText(this.properties.getLog().getDir())) {System.setProperty("csp.sentinel.log.dir", this.properties.getLog().getDir());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.log.use.pid")) && this.properties.getLog().isSwitchPid()) {System.setProperty("csp.sentinel.log.use.pid", String.valueOf(this.properties.getLog().isSwitchPid()));}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.app.name")) && StringUtils.hasText(this.projectName)) {System.setProperty("csp.sentinel.app.name", this.projectName);}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.api.port")) && StringUtils.hasText(this.properties.getTransport().getPort())) {System.setProperty("csp.sentinel.api.port", this.properties.getTransport().getPort());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.dashboard.server")) && StringUtils.hasText(this.properties.getTransport().getDashboard())) {System.setProperty("csp.sentinel.dashboard.server", this.properties.getTransport().getDashboard());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.heartbeat.interval.ms")) && StringUtils.hasText(this.properties.getTransport().getHeartbeatIntervalMs())) {System.setProperty("csp.sentinel.heartbeat.interval.ms", this.properties.getTransport().getHeartbeatIntervalMs());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.heartbeat.client.ip")) && StringUtils.hasText(this.properties.getTransport().getClientIp())) {System.setProperty("csp.sentinel.heartbeat.client.ip", this.properties.getTransport().getClientIp());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.charset")) && StringUtils.hasText(this.properties.getMetric().getCharset())) {System.setProperty("csp.sentinel.charset", this.properties.getMetric().getCharset());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.metric.file.single.size")) && StringUtils.hasText(this.properties.getMetric().getFileSingleSize())) {System.setProperty("csp.sentinel.metric.file.single.size", this.properties.getMetric().getFileSingleSize());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.metric.file.total.count")) && StringUtils.hasText(this.properties.getMetric().getFileTotalCount())) {System.setProperty("csp.sentinel.metric.file.total.count", this.properties.getMetric().getFileTotalCount());}if (StringUtils.isEmpty(System.getProperty("csp.sentinel.flow.cold.factor")) && StringUtils.hasText(this.properties.getFlow().getColdFactor())) {System.setProperty("csp.sentinel.flow.cold.factor", this.properties.getFlow().getColdFactor());}if (StringUtils.hasText(this.properties.getBlockPage())) {SentinelConfig.setConfig("csp.sentinel.web.servlet.block.page", this.properties.getBlockPage());}if (this.properties.isEager()) {InitExecutor.doInit();}}@Bean@ConditionalOnMissingBeanpublic SentinelResourceAspect sentinelResourceAspect() {return new SentinelResourceAspect();}@Bean@ConditionalOnMissingBean@ConditionalOnClass(name = {"org.springframework.web.client.RestTemplate"})@ConditionalOnProperty(name = {"resttemplate.sentinel.enabled"},havingValue = "true",matchIfMissing = true)public SentinelBeanPostProcessor sentinelBeanPostProcessor(ApplicationContext applicationContext) {return new SentinelBeanPostProcessor(applicationContext);} //处理@SentinelRestTemplate@Bean@ConditionalOnMissingBeanpublic SentinelDataSourceHandler sentinelDataSourceHandler(DefaultListableBeanFactory beanFactory, SentinelProperties sentinelProperties, Environment env) {return new SentinelDataSourceHandler(beanFactory, sentinelProperties, env);} //sentinel规则数据源处理@ConditionalOnClass({ObjectMapper.class})@Configuration(proxyBeanMethods = false)protected static class SentinelConverterConfiguration {protected SentinelConverterConfiguration() {}@ConditionalOnClass({XmlMapper.class})@Configuration(proxyBeanMethods = false)protected static class SentinelXmlConfiguration { //解析xml格式规则private XmlMapper xmlMapper = new XmlMapper();public SentinelXmlConfiguration() {this.xmlMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);}@Bean({"sentinel-xml-flow-converter"})public XmlConverter xmlFlowConverter() {return new XmlConverter(this.xmlMapper, FlowRule.class);} //解析限流规则@Bean({"sentinel-xml-degrade-converter"})public XmlConverter xmlDegradeConverter() {return new XmlConverter(this.xmlMapper, DegradeRule.class);} //解析熔断降级规则@Bean({"sentinel-xml-system-converter"})public XmlConverter xmlSystemConverter() {return new XmlConverter(this.xmlMapper, SystemRule.class);} //解析系统限流规则@Bean({"sentinel-xml-authority-converter"})public XmlConverter xmlAuthorityConverter() {return new XmlConverter(this.xmlMapper, AuthorityRule.class);} //解析黑白名单规则@Bean({"sentinel-xml-param-flow-converter"})public XmlConverter xmlParamFlowConverter() {return new XmlConverter(this.xmlMapper, ParamFlowRule.class);} //解析热点限流规则}@Configuration(proxyBeanMethods = false)protected static class SentinelJsonConfiguration { //解析json格式规则private ObjectMapper objectMapper = new ObjectMapper();public SentinelJsonConfiguration() {this.objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);}@Bean({"sentinel-json-flow-converter"})public JsonConverter jsonFlowConverter() {return new JsonConverter(this.objectMapper, FlowRule.class);} //解析限流规则@Bean({"sentinel-json-degrade-converter"})public JsonConverter jsonDegradeConverter() {return new JsonConverter(this.objectMapper, DegradeRule.class);} //解析熔断降级规则@Bean({"sentinel-json-system-converter"})public JsonConverter jsonSystemConverter() {return new JsonConverter(this.objectMapper, SystemRule.class);} //解析系统限流规则@Bean({"sentinel-json-authority-converter"})public JsonConverter jsonAuthorityConverter() {return new JsonConverter(this.objectMapper, AuthorityRule.class);} //解析黑白名单规则@Bean({"sentinel-json-param-flow-converter"})public JsonConverter jsonParamFlowConverter() {return new JsonConverter(this.objectMapper, ParamFlowRule.class);} //解析热点限流规则}}
}
SentinelProperties
@ConfigurationProperties(prefix = "spring.cloud.sentinel"
)
@Validated
public class SentinelProperties {private boolean eager = false;private boolean enabled = true;private String blockPage;private Map<String, DataSourcePropertiesConfiguration> datasource;private SentinelProperties.Transport transport;private SentinelProperties.Metric metric;private SentinelProperties.Servlet servlet;private SentinelProperties.Filter filter;private SentinelProperties.Flow flow;private SentinelProperties.Log log;private Boolean httpMethodSpecify;private Boolean webContextUnify;*********
Transportpublic static class Transport {private String port = "8719";private String dashboard = "";private String heartbeatIntervalMs;private String clientIp;*********
Metricpublic static class Metric {private String fileSingleSize;private String fileTotalCount;private String charset = "UTF-8";*********
Servletpublic static class Servlet {private String blockPage;*********
Filterpublic static class Filter {private int order = -2147483648;private List<String> urlPatterns = Arrays.asList("/**");private boolean enabled = true;*********
Flowpublic static class Flow {private String coldFactor = "3";*********
Logpublic static class Log {private String dir;private boolean switchPid = false;
DataSourcePropertiesConfiguration
public class DataSourcePropertiesConfiguration {private FileDataSourceProperties file; //本地文件存储private NacosDataSourceProperties nacos; //nacos存储private ZookeeperDataSourceProperties zk; //zookeeper存储private ApolloDataSourceProperties apollo; //apollo存储private RedisDataSourceProperties redis; //redis存储private ConsulDataSourceProperties consul; //consul存储
NacosDataSourceProperties
public class NacosDataSourceProperties extends AbstractDataSourceProperties {private String serverAddr;private String username;private String password;@NotEmptyprivate String groupId = "DEFAULT_GROUP";@NotEmptyprivate String dataId;private String endpoint;private String namespace;private String accessKey;private String secretKey;public NacosDataSourceProperties() {super(NacosDataSourceFactoryBean.class.getName());}
AbstractDataSourceProperties
public class AbstractDataSourceProperties {@NotEmptyprivate String dataType = "json"; //数据默认用json格式存储@NotNullprivate RuleType ruleType; //规则类型private String converterClass;@JsonIgnoreprivate final String factoryBeanName;@JsonIgnoreprivate Environment env;public AbstractDataSourceProperties(String factoryBeanName) {this.factoryBeanName = factoryBeanName;}
RuleType:限流、熔断降级、热点限流、系统限流、黑白名单、网关限流、网关api限流
public enum RuleType {FLOW("flow", FlowRule.class),DEGRADE("degrade", DegradeRule.class),PARAM_FLOW("param-flow", ParamFlowRule.class),SYSTEM("system", SystemRule.class),AUTHORITY("authority", AuthorityRule.class),GW_FLOW("gw-flow", "com.alibaba.csp.sentinel.adapter.gateway.common.rule.GatewayFlowRule"),GW_API_GROUP("gw-api-group", "com.alibaba.csp.sentinel.adapter.gateway.common.api.ApiDefinition");private final String name;private Class clazz;private String clazzName;private RuleType(String name, Class clazz) {this.name = name;this.clazz = clazz;}private RuleType(String name, String clazzName) {this.name = name;this.clazzName = clazzName;}
相关注解
@SentinelResource
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface SentinelResource {String value() default ""; //资源名称,必填EntryType entryType() default EntryType.OUT;int resourceType() default 0;String blockHandler() default ""; //处理blockException的方法,参数及返回类型需相同,//方法参数最后也可添加BlockException(可不添加)Class<?>[] blockHandlerClass() default {}; //处理blockException的类,对应的函数必需为static函数String fallback() default ""; //处理所有异常,指定异常时的服务降级方法,同时配置fallback、defaultFallback,fallback生效String defaultFallback() default ""; //处理所有异常,异常时默认的服务降级处理方法Class<?>[] fallbackClass() default {}; //处理所有异常,异常时服务降级处理类Class<? extends Throwable>[] exceptionsToTrace() default {Throwable.class}; //需要追踪处理的异常类Class<? extends Throwable>[] exceptionsToIgnore() default {}; //忽略处理的异常类,不会统计异常,不会用fallback处理,直接抛出异常
}
EntryType
public enum EntryType {IN("IN"),OUT("OUT");private final String name;private EntryType(String s) {this.name = s;}public boolean equalsName(String otherName) {return this.name.equals(otherName);}public String toString() {return this.name;}
}
@SentinelResource使用示例
public class TestService {// 原函数@SentinelResource(value = "hello", blockHandler = "exceptionHandler", fallback = "helloFallback")public String hello(long s) {return String.format("Hello at %d", s);}// Fallback 函数,函数签名与原函数一致或加一个 Throwable 类型的参数.public String helloFallback(long s) {return String.format("Halooooo %d", s);}// Block 异常处理函数,参数最后多一个 BlockException,其余与原函数一致.public String exceptionHandler(long s, BlockException ex) {// Do some log here.ex.printStackTrace();return "Oops, error occurred at " + s;}// 这里单独演示 blockHandlerClass 的配置.// 对应的 `handleException` 函数需要位于 `ExceptionUtil` 类中,并且必须为 public static 函数.@SentinelResource(value = "test", blockHandler = "handleException", blockHandlerClass = {ExceptionUtil.class})public void test() {System.out.println("Test");}
}
限流降级规则
RuleConstant:限流降级规则常量
public final class RuleConstant {public static final int FLOW_GRADE_THREAD = 0;public static final int FLOW_GRADE_QPS = 1;public static final int DEGRADE_GRADE_RT = 0;public static final int DEGRADE_GRADE_EXCEPTION_RATIO = 1;public static final int DEGRADE_GRADE_EXCEPTION_COUNT = 2;public static final int DEGRADE_DEFAULT_SLOW_REQUEST_AMOUNT = 5;public static final int DEGRADE_DEFAULT_MIN_REQUEST_AMOUNT = 5;public static final int AUTHORITY_WHITE = 0;public static final int AUTHORITY_BLACK = 1;public static final int STRATEGY_DIRECT = 0;public static final int STRATEGY_RELATE = 1;public static final int STRATEGY_CHAIN = 2;public static final int CONTROL_BEHAVIOR_DEFAULT = 0;public static final int CONTROL_BEHAVIOR_WARM_UP = 1;public static final int CONTROL_BEHAVIOR_RATE_LIMITER = 2;public static final int CONTROL_BEHAVIOR_WARM_UP_RATE_LIMITER = 3;public static final String LIMIT_APP_DEFAULT = "default";public static final String LIMIT_APP_OTHER = "other";public static final int DEFAULT_SAMPLE_COUNT = 2;public static final int DEFAULT_WINDOW_INTERVAL_MS = 1000;private RuleConstant() {}
}
AbstractRule
public abstract class AbstractRule implements Rule {private String resource; //限制的资源名称private String limitApp; //规则针对的调用来源:some_origin、default(不区分来源,默认)、otherpublic AbstractRule() {}
FlowRule:限流规则
public class FlowRule extends AbstractRule {private int grade = 1; //限流阈值类型:0(并发线程数限流)、1(QPS限流)private double count; //限流阀值private int strategy = 0; //调用关系限流策略:直接(默认)、链路、关联private String refResource; //关联资源名称private int controlBehavior = 0; //流控效果:直接拒绝(默认)、WarmUp、匀速+排队等待private int warmUpPeriodSec = 10; //流控效果为warm up时,冷启动时长,默认10sprivate int maxQueueingTimeMs = 500; //流控效果为匀速+排队等待时,最长排队时间private boolean clusterMode; //是否是集群模式private ClusterFlowConfig clusterConfig; //集群限流配置private TrafficShapingController controller; //自定义流控效果public FlowRule() {this.setLimitApp("default");}public FlowRule(String resourceName) {this.setResource(resourceName);this.setLimitApp("default");}
ClusterFlowConfig:集群流控策略
public class ClusterFlowConfig {private Long flowId; //集群流控id,需保证全局唯一private int thresholdType = 0; //阀值模式:0(单机均摊)、1(全局模式)private boolean fallbackToLocalWhenFail = true; //在 client 连接失败或通信失败时,是否退化到本地的限流模式private int strategy = 0; //限流策略:直接(资源本深,默认)、链路、关联private int sampleCount = 10; //窗口数量private int windowIntervalMs = 1000; //窗口统计时长,默认1spublic ClusterFlowConfig() {}
DegradeRule:降级策略
public class DegradeRule extends AbstractRule {private int grade = 0; //熔断策略:慢调用比例(默认)、异常比例、异常数策略private double count; //熔断阀值(慢调用为最长响应时间)private int timeWindow; //熔断时间窗口private int minRequestAmount = 5; //最小请求数,请求数小于该值时即使异常比率超出阈值也不会熔断private double slowRatioThreshold = 1.0D; //慢调用比例阈值private int statIntervalMs = 1000; //统计时长(单位为ms)public DegradeRule() {}public DegradeRule(String resourceName) {this.setResource(resourceName);}
ParamFlowRule:热点限流规则
public class ParamFlowRule extends AbstractRule {private int grade = 1; //限流模式,默认为QPS限流private Integer paramIdx; //热点参数的索引private double count; //限流阀值private int controlBehavior = 0; //流控策略:快速失败(默认)、匀速排队模式private int maxQueueingTimeMs = 0; //最大排队等待时长(仅在匀速排队模式生效), 默认0msprivate int burstCount = 0; //应对突发流量额外允许的数量,默认为0private long durationInSec = 1L; //统计窗口时间长度(单位为秒),默认1sprivate List<ParamFlowItem> paramFlowItemList = new ArrayList(); //参数例外项,针对指定的参数值单独设置限流阈值,//不受count阈值限制,仅支持基本类型和字符串类型private Map<Object, Integer> hotItems = new HashMap(); //额外参数private boolean clusterMode = false; //是否是集群模式private ParamFlowClusterConfig clusterConfig; //集群流控配置public ParamFlowRule() {}public ParamFlowRule(String resourceName) {this.setResource(resourceName);}
SystemRule:系统流控规则
public class SystemRule extends AbstractRule {private double highestSystemLoad = -1.0D; //系统最高负载private double highestCpuUsage = -1.0D; //系统cpu最高使用率private double qps = -1.0D; //入口资源的QPSprivate long avgRt = -1L; //入口流量的平均响应时间private long maxThread = -1L; //入口流量的最大并发数public SystemRule() {}
AuthorityRule:访问控制规则(黑白名单规则)
public class AuthorityRule extends AbstractRule {private int strategy = 0; //限制模式:白名单模式(默认)、黑名单模式
SentinelgateWayConstants:网关限流常量
public final class SentinelGatewayConstants {public static final int APP_TYPE_GATEWAY = 1;public static final int RESOURCE_MODE_ROUTE_ID = 0;public static final int RESOURCE_MODE_CUSTOM_API_NAME = 1;public static final int PARAM_PARSE_STRATEGY_CLIENT_IP = 0;public static final int PARAM_PARSE_STRATEGY_HOST = 1;public static final int PARAM_PARSE_STRATEGY_HEADER = 2;public static final int PARAM_PARSE_STRATEGY_URL_PARAM = 3;public static final int PARAM_PARSE_STRATEGY_COOKIE = 4;public static final int URL_MATCH_STRATEGY_EXACT = 0;public static final int URL_MATCH_STRATEGY_PREFIX = 1;public static final int URL_MATCH_STRATEGY_REGEX = 2;public static final int PARAM_MATCH_STRATEGY_EXACT = 0;public static final int PARAM_MATCH_STRATEGY_PREFIX = 1;public static final int PARAM_MATCH_STRATEGY_REGEX = 2;public static final int PARAM_MATCH_STRATEGY_CONTAINS = 3;public static final String GATEWAY_CONTEXT_DEFAULT = "sentinel_gateway_context_default";public static final String GATEWAY_CONTEXT_PREFIX = "sentinel_gateway_context$$";public static final String GATEWAY_CONTEXT_ROUTE_PREFIX = "sentinel_gateway_context$$route$$";public static final String GATEWAY_NOT_MATCH_PARAM = "$NM";public static final String GATEWAY_DEFAULT_PARAM = "$D";private SentinelGatewayConstants() {}
}
GateWayFlowRule:网关限流规则
public class GatewayFlowRule {private String resource; //限流资源private int resourceMode = 0; //资源模式:RESOURCE_MODE_ROUTE_ID(0,默认)、RESOURCE_MODE_CUSTOM_API_NAME(1)private int grade = 1; //限流阈值类型:并发线程模式(0)、QPS模式(1,默认)private double count; //限流阀值private long intervalSec = 1L; //统计时间窗口,默认1sprivate int controlBehavior = 0; //流控效果:快速失败、匀速排队private int burst; //应对突发请求时额外允许的请求数目private int maxQueueingTimeoutMs = 500; //匀速排队模式下的最长排队时间,单位毫秒private GatewayParamFlowItem paramItem; //参数限流配置,若不提供,则代表不针对参数进行限流public GatewayFlowRule() {}public GatewayFlowRule(String resource) {this.resource = resource;}
sentinel 使用说明相关推荐
- Sentinel使用教程
文章目录 一.Sentinel简介 1.sentinel介绍 2.sentinel应用场景 3.sentinel与hystrix 4.sentinel组件介绍 二.Sentinel使用说明 1.控制台 ...
- java xml 推模式 拉模式_Alibaba Sentinel规则持久化-推模式-手把手教程(基于Nacos)...
点击上方"IT牧场",选择"设为星标"技术干货每日送达! 一.推模式架构图 TIPS 图片来自官方. 引用自 https://github.com/alibab ...
- Sentinel: 分布式系统的流量防卫兵 1
Sentinel 是什么? 随着微服务的流行,服务和服务之间的稳定性变得越来越重要.Sentinel 以流量为切入点,从流量控制.熔断降级.系统负载保护等多个维度保护服务的稳定性. Sentinel ...
- Sentinel圣天诺加密狗简单使用教程(Linux)
前言:帮学校的学长做了个Ubuntu的软件,需要给软件加密,用到了加密狗,在网上挑了很多,大都不支持Linux下ELF文件的加密,最后终于找到了Sentinel加密狗支持我们的需求,当然这个进口货也很 ...
- sentinel 限流熔断神器详细介绍
一.限流熔断神器 sentinel 1.什么是 sentinel: 在基于 SpringCloud 构建的微服务体系中,服务间的调用链路会随着系统的演进变得越来越长,这无疑会增加了整个系统的不可靠因素 ...
- Sentinel(二)之Quick Start
转载自 Sentinel Quick Start 1.1 公网 Demo 如果希望最快的了解 Sentinel 在做什么,我们可以通过 Sentinel 新手指南 来运行一个例子,并且能在云上控制台上 ...
- Alibaba Sentinel规则持久化-推模式-手把手教程【基于Nacos】
前面,已经为Sentinel实现了 基于拉模式的规则持久化 ,本文来实现基于 推模式的规则持久化. 文章目录 一.推模式架构图 二.原理简述 三.微服务改造 3.1. 加依赖 3.2. 添加配置 四. ...
- Hard Disk Sentinel Pro v5.70.8 硬盘哨兵 电脑硬盘检测工具
前言 Hard Disk Sentinel是一款国外的硬盘检测软件,持winpe也支持win10,支持ssd固态硬盘.它使用 SMART 技术监控硬盘健康.性能,及温度等重要参数.此软件最大的作用就是 ...
- Sentinel 高可用流量管理框架
Sentinel 是面向分布式服务架构的高可用流量防护组件,主要以流量为切入点,从限流.流量整形.熔断降级.系统负载保护.热点防护等多个维度来帮助开发者保障微服务的稳定性. Sentinel 具有以下 ...
最新文章
- 启动Tomcat一闪而过解决
- 重构智能合约(中):平行宇宙与无限扩展
- SpringCloud F.RC2 整合Zipkin简单步骤
- gradle各版本下载地址
- coolite TreeNode NodeClick传id到后台的方法
- 新手学html 第一节:html简介
- Python开发第一篇 基础篇(下)
- brave浏览器_火狐联创、Java Script之父,居然也来倒腾区块链浏览器?
- 【渝粤教育】国家开放大学2019年春季 45烹饪原料学(1) 参考试题
- 工具推荐-极速全文搜索工具、文档内容搜索引擎
- java 换行分割_java – 如何通过换行分割字符串?
- 小程序input绑定输入保存数据
- 工业镜头的主要参数与选型
- 上亿用户,如何高效统计独立用户访问量?
- 如何安装配置eosjs并连接到EOS区块链
- python中mysqldb的用法
- 微信小程序 | 基于ChatGPT实现电影推荐小程序
- Microsoft SQL Server 2008 R2(Microsoft SQL Server,错误: 2)
- N4BiasFieldCorrection
- 一年级计算机课画画用什么,一年级学画画入门教程