什么是微服务架构?
微服务是一种软件开发技术,它提倡将单一应用程序划分成一组小的服务,服务之间互相协调、互相配合,为用户提供最终价值。每个服务运行在其独立的进程中,服务与服务间采用轻量级的通信机制互相沟通(通常是基于HTTP的RESTful API)。每个服务都围绕着具体业务进行构建,并且能够独立地部署到生产环境、类生产环境等。——Wikipedia
我们将在开发中将业务的所有功能都集中在一个项目开发,打成一个包部署的架构方式成为单体架构,架构简单,部署成本低是它的优点。单体架构是一些简单的演示练习项目或低并发需求的个人项目中最常采用的架构方式。但其缺点是耦合度高,不便于大型项目的维护。

分布式架构:根据业务功能进行拆分,每个业务模块作为独立项目开发,称为一个服务;优点:降低耦合,有利于服务升级扩展;缺点:架构复杂,难度大。

微服务是一种良好的分布式架构方案,它有以下特征:

一个成熟的微服务架构解决方案将包含以下相关技术栈:

注册中心:
微服务架构把单一应用程序划分成一组小的服务,每个服务运行在自己的进程中,服务之间通过网络调用进行通信。注册中心是微服务架构中的一个核心组件,它负责维护服务实例的注册和发现。
微服务架构中的服务实例是动态的,服务实例可能会经常添加、删除和修改。注册中心能够帮助服务消费者快速发现服务提供者,并且还能够监控服务提供者的健康状态。
配置中心:
每个服务都有自己的配置文件,而一个上线的项目可能会有成百上千的服务,这些配置文件,我们不可能一个一个去修改,这个时候需要一个配置中心,它主要用来统一管理整个服务集群成千上百的配置,我们要变更某些配置,只要找到配置中心就可以了,它就会去找到对应的配置,实现配置的热更新。
网关:
所有的请求进来,并不能直接就去访问对应的服务,而是要通过一个网关服务,由它来路由到对应的服务。
分布式缓存:
数据库层,由于数据库即使是集群部署,也很难抗住高并发,往往还需要一个缓存集群,把数据库的数据搬到内存中以提高访问效率。请求先查询缓存,缓存未命中的时候再去查询数据库。
分布式搜索:
对于一些复杂的数据的搜索、统计、分析,我们还需要使用搜索集群。
消息队列:
在分布式架构中,还需要消息队列,因为一个业务往往会调用多个服务,但我们不能等到所有的服务都执行完成再返回响应数据,因为这样操作就类似串行执行,响应速度有所下降。这个时候可以使用消息队列,让服务发送消息通知其他服务去执行指定的任务,而自己则可以结束运行,提高响应速度。
分布式日志服务:
主要用来统计成百上千的服务的运行日志,方便系统出问题时的定位。
系统监控链路追踪:
可以实时监控整个服务集群的所有节点的运行状态。
目前主流的微服务开发框架中,Dubbo、SpringCloud、SpringCloudAlibaba 在国内外市场拥有较高的占有率。下方是框架技术的对比图:

其中 SpringCloud 是国内使用最广泛的微服务框架技术。其官网为:https://spring.io/projects/spring-cloud。 SpringCloud 集成了各种微服务功能组件,并基于 SpringBoot 实现了这些组件的自动装配。
微服务技术依据各个服务功能分成不同的模块,而一项业务需要多个服务模块共同完成,这便少不了各模块接口间的互相调用。下面是不同微服务模块远程调用的一个实例:

首先浏览器发送请求到订单模块,订单模块在到数据库查询信息;这时候订单模块再发送请求到用户模块,用户模块在到数据库查询信息。
基于 RestTemplate 实现的服务器远程调用:
/**
* 注入RestTemplate发送http请求获取数据
*
* @return new RestTemplate()
*/
@Bean
RestTemplate restTemplate() {
return new RestTemplate();
}
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private RestTemplate restTemplate;
/**
* 通过id查询订单
*
* @param orderId 订单编号
* @return json
*/
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.使用 RestTemplate 远程调用服务器接口
String url = "http://localhost:8081/user/" + order.getUserId();
User user = restTemplate.getForObject(url, User.class);
// 3.封装数据
order.setUser(user);
// 4.返回 order 对象
return order;
}
}
考虑上述案例,我们将远程调用过程中的双方分别成为服务提供者和服务消费者。
上述服务远程调用存在一些问题:
为了解决这些问题,SpringCloud 为我们提供了一个注册中心技术——Eureka。

Eureka 是 SpringCloud 框架中的一个核心组件,它负责维护服务实例的注册和发现。服务提供者启动时会向 eureka 注册自己的信息,随后消费者则根据服务名称向 eureka 拉取提供者信息。若服务提供者存在多个,服务消费者将利用负载均衡算法,从服务列表中挑选一个。
步骤一:搭建 Eureka 服务器
<!-- eureka服务器 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-server</artifactId>
</dependency>
@EnableEurekaServer 注解:@SpringBootApplication
@EnableEurekaServer//开启Eureka服务器
public class EurekaApplication {
public static void main(String[] args) {
SpringApplication.run(EurekaApplication.class, args);
}
}
server:
port: 10086 # 服务端口
spring:
application:
name: eurekaserver # eureka的服务名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
步骤二:为服务提供者和消费者进行服务注册
<!-- eureka客户端依赖 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
Spring:
application:
name: userservice # user的服务名称
eureka:
client:
service-url: # eureka的地址信息
defaultZone: http://127.0.0.1:10086/eureka
步骤三:在服务消费者中实现服务发现(服务拉取)
//定义服务提供者接口的url地址,通过 eureka 实例名称进行服务发现
String url = "http://userservice/user/" + order.getUserId();
@Bean
@LoadBalanced//负载均衡,实现 eureka 注册中心服务发现
RestTemplate restTemplate() {
return new RestTemplate();
}
启动相关微服务后,访问 Eureka WEB 服务器地址即可进入 Eureka 的管理界面。


SpringCloud 底层其实是利用了一个名为 Ribbon 的组件,来实现负载均衡功能的。

其基本流程如下:
Ribbon 的负载均衡规则是一个叫做 IRule 的接口来定义的,每一个子接口都是一种规则:


修改负载均衡规则的两种方式:
@Bean
public IRule randomRule(){
return new RandomRule();
}
userservice: # 给某个微服务配置负载均衡规则,这里是 userservice 服务
ribbon:
NFLoadBalancerRuleClassName: com.netflix.loadbalancer.RandomRule # 负载均衡规则
Ribbon 默认是采用懒加载,即第一次访问时才会去创建LoadBalanceClient,请求时间会很长。
而饥饿加载则会在项目启动时创建,降低第一次访问的耗时,通过下面配置开启饥饿加载:
ribbon:
eager-load:
enabled: true # 开启饥饿加载
clients: userservice # 指定对userservice这个服务饥饿加载
Nacos 是阿里巴巴的产品,现在是 SpringCloud 中的一个组件。相比 Eureka 功能更加丰富,在国内受欢迎程度较高。
完成下载后,在 bin 目录下打开 cmd 命令行,运行 startup.cmd -m standalone 单机运行Nacos
<!-- Alibaba管理依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-alibaba-dependencies</artifactId>
<version>2.2.5.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
spring:
application:
name: orderservice # order的服务名称
cloud:
nacos:
server-addr: localhost:8848 # nacos 服务地址
项目和 Nacos 启动后,访问 Nacos 服务地址进入 WEB 管理界面(初始账号密码为:nacos)。


Nacos 将分布式服务分为三个等级:服务、集群、实例。

此时我们注意到:服务调用应尽可能选择本地集群的服务,跨集群调用延迟较高;本地集群不可访问时,再去访问其它集群。
Nacos 为服务跨集群调用问题提供了解决方案,即在配置文件中配置服务集群属性:
application:
name: orderservice # 服务名称
cloud: # nacos配置
nacos:
server-addr: localhost:8848 # 服务地址
discovery:
cluster-name: GZ # 自定义集群名称
userservice:
ribbon:
NFLoadBalancerRuleClassName: com.alibaba.cloud.nacos.ribbon.NacosRule # Nacos集群负载均衡策略
当微服务的部署越来越多时,我们微服务配置就会越来越多,如果不想逐个管理起来,我们就可以通过 Nacos 的配置管理服务把它们集中起来管理。
事实上,Nacos 不仅是承担注册中心重任的组件,而且是备受众多企业青睐的配置中心组件。

<!-- nacos配置管理依赖 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
</dependency>
<!-- nacos配置类依赖 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
# nacos配置文件
spring:
application:
name: userservice # 实例名称
profiles:
active: public # 环境
cloud:
nacos:
server-addr: localhost:8848 # 项目地址
config:
file-extension: yaml # 配置文件文件后缀
discovery:
cluster-name: GZ # 自定义集群名称
ephemeral: true # 是否为临时实例
Nacos 配置管理配置完成后,可以通过格式化时间代码测试一下:
@RestController
@RequestMapping("/user")
@RefreshScope//当使用@Value注解时,启用该注解实现配置文件热部署
public class UserController {
@Autowired
private UserService userService;
//属性注入加载配置文件
@Value("${pattern.dateformat}")
private String dateformat;
/**
* @Value加载测试userservice-public.yaml配置文件属性
*
* @return 格式化后的当前时间
*/
@GetMapping("/now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(dateformat));
}
......//下略
}
除了 @Value 注解获取配置文件属性外,还可以使用 @ConfigurationProperties 注解获取配置对象,并自动实现配置热部署。
@Data
@Component
@ConfigurationProperties(prefix = "pattern")
public class PatternProperties {
private String dateformat;//userservice-public.yaml属性
}
在使用处注入对象:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
//使用@ConfigurationProperties(prefix = "pattern")注解注入配置文件属性
@Autowired
private PatternProperties patternProperties;
/**
* 使用@ConfigurationProperties注解获取userservice-public.yaml配置文件
* 实现配置的热部署
*
* @return time
*/
@GetMapping("/now")
public String now(){
return LocalDateTime.now().format(DateTimeFormatter.ofPattern(patternProperties.getDateformat()));
}
......//下略
}
微服务启动时会从nacos读取多个配置文件:
无论profile如何变化,[spring.application.name].yaml这个文件一定会加载,因此多环境共享配置可以写入这个文件
且配置文件优先性为:服务名-profile.yaml > 服务名称.yaml > 本地配置
前文我们通过 RestTemplate 远程调用服务接口,但其存在的下面问题:
而 SpringCloud 在服务远程调用方面为我们提供了一个HTTP客户端——Feign。Feign 是一个声明式的http客户端,其作用就是帮助我们优雅的实现http请求的发送,解决上面提到的问题。Feign提供了HTTP请求的模板,通过编写简单的接口和插入注解,就可以定义好HTTP请求的参数、格式、地址等信息。Feign 会完全代理HTTP请求,我们只需要像调用方法一样调用它就可以完成服务请求及相关处理。
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-openfeign</artifactId>
</dependency>
@EnableFeignClients
@FeignClient("userservice")
public interface UserClient {
/**
* Feign 接口调用 http://userservice/user/{id}
*
* @param id
* @return User对象
*/
@GetMapping("/user/{id}")
User findById(@PathVariable("id") Long id);
}
@Service
public class OrderService {
@Autowired
private OrderMapper orderMapper;
@Autowired
private UserClient userClient;
/**
* 通过id查询订单
*
* @param orderId 订单编号
* @return json
*/
public Order queryOrderById(Long orderId) {
// 1.查询订单
Order order = orderMapper.findById(orderId);
// 2.使用 Feign 调用远程服务器接口
User user = userClient.findById(order.getUserId());
// 3.封装数据
order.setUser(user);
// 4.返回
return order;
}
}
Feign 运行自定义配置来覆盖默认配置,可以修改的配置如下:

其中修改日志等级或其他配置方式有两种:
方式一:修改配置文件
feign:
client:
config:
default:
loggerLever: basic # 日志等级,默认为none
feign:
client:
config:
userservice: # 针对某个微服务的配置
loggerLevel: FULL # 日志级别
方式二:@Bean 注入方式
@Bean。public class DefaultFeignConfiguration {
@Bean
public Logger.Level feignLogLevel(){
return Logger.Level.BASIC; // 日志级别为BASIC
}
}
如果是全局配置,则把它放到 @EnableFeignClients 注解中:
@EnableFeignClients(defaultConfiguration = FeignClientConfiguration.class)
如果是局部配置,则把它放到 @FeignClient 注解中:
@FeignClient(value = "userservice", configuration = FeignClientConfiguration.class)
Feign 底层的客户端实现:
因此优化 Feign 的性能主要包括:
下面提到了如何将默认连接客户端切换为 HttpClient:
<!-- HttpClient依赖 -->
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-httpclient</artifactId>
</dependency>
feign:
client:
config:
default: # default全局的配置
loggerLevel: BASIC # 日志级别,BASIC就是基本的请求和响应信息
httpclient:
enabled: true # 开启feign对HttpClient的支持
max-connections: 200 # 最大的连接数
max-connections-per-route: 50 # 每个路径的最大连接数
方式一(继承):给消费者的 FeignClient 和提供者的 Controller 定义统一的父接口作为标准。

方式二(抽取):将 FeignClient 抽取为独立模块,并且把接口有关的 POJO、默认的 Feign 配置都放到这个模块中,提供给所有消费者使用。

下面样例使用了抽取方式完成对 feign-api 的实现:
当定义的 FeignClient 不在 SpringBootApplication 的扫描包范围时,这些 FeignClient 无法使用。有两种方式解决:
方式一:指定 FeignClient 所在包
@EnableFeignClients(basePackages = "cn.itcast.feign.clients")
方式二:指定 FeignClient 字节码
@EnableFeignClients(clients = {UserClient.class})

在微服务架构中,网关是一种中间层,它在客户端和服务端之间提供了一个单一的入口点,并且可以用于路由请求、鉴权、监控、安全性、负载均衡等多种功能。
网关在微服务架构中起到了身份认证和权限校验、统一管理服务调用关系、服务路由、负载均衡、提供统一的接口、请求限流等重要作用,因此是微服务架构中不可或缺的一环。

在 SpringCloud 中网关的实现包括两种:
Zuul是基于 Servlet 的实现,属于阻塞式编程。而 SpringCloudGateway 则是基于 Spring5 中提供的 WebFlux,属于响应式编程的实现,具备更好的性能。
使用 Gateway 搭建网关服务的一些步骤:
<!-- nacos客户端依赖包 -->
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
<!-- gateway网关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-gateway</artifactId>
</dependency>
server:
port: 10010
spring:
application:
name: gateway # 服务名称
cloud:
nacos:
server-addr: localhost:8848 # 给服务注册在nacos
gateway: # gateway配置
routes: # 网关配置
- id: user-service # 唯一路由id,自定义
uri: lb://userservice # 路由目标地址,使用Nacos负载均衡
predicates: # 路由断言,判断请求是否符合规则
- Path=/user/** # 路径断言
- id: order-service
uri: lb://orderservice
predicates:
- Path=/order/**

网关路由 routes 可以配置的内容包括:
我们在配置文件中写的断言规则只是字符串,这些字符串会被 Predicate Factory 读取并处理,转变为路由判断的条件。

GatewayFilter 是网关中提供的一种过滤器,可以对进入网关的请求和微服务返回的响应做处理:
以下是 Spring 提供的部分路由过滤器工厂:
| 名称 | 说明 |
|---|---|
| AddRequestHeader | 给当前请求添加一个请求头 |
| RemoveRequestHeader | 移除请求中的一个请求头 |
| AddResponseHeader | 给响应结果中添加一个响应头 |
| RemoveResponseHeader | 从响应结果中移除有一个响应头 |
| RequestRateLimiter | 限制请求的流量 |
| ... | ... |
更多的详细路由过滤器请见 Spring Cloud 官方文档:https://docs.spring.io/spring-cloud-gateway/docs/3.1.5-SNAPSHOT/reference/html/#gatewayfilter-factories
一个简单的案例:给所有进入 userservice 的请求添加一个请求头:Message=Hello World!
如上文,我们可以在配置文件的 filters 处声明 AddRequestHeader。
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
filters: # 过滤器
- AddRequestHeader=Massage, Hello World! # 添加请求头
默认过滤器:如果要对所有的路由都生效,则可以将过滤器工厂写到 default 下。格式如下:
spring:
cloud:
gateway:
routes:
- id: user-service
uri: lb://userservice
predicates:
- Path=/user/**
default-filters: # 默认过滤项
- AddRequestHeader=Massage, Hello World!
全局过滤器的作用也是处理一切进入网关的请求和微服务响应,与 GatewayFilter 的作用一样。区别在于 GatewayFilte r通过配置定义,处理逻辑是固定的。而 GlobalFilter 的逻辑需要自己写代码实现。定义方式是实现 GlobalFilter 接口。
public interface GlobalFilter {
/**
* 处理当前请求,有必要的话通过{@link GatewayFilterChain}将请求交给下一个过滤器处理
*
* @param exchange 请求上下文,里面可以获取Request、Response等信息
* @param chain 用来把请求委托给下一个过滤器
* @return {@code Mono<Void>} 返回标示当前过滤器业务结束
*/
Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain);
}
下面是一个入门的案例:
需求:定义全局过滤器,拦截请求,判断请求的参数是否满足下面条件:
如果同时满足则放行,否则拦截;下方代码是具体实现:
/**
* gateway网关模拟登录实现
*/
@Order(-1)// 过滤器优先级,有小越高
@Component
public class AuthorizeFilter implements GlobalFilter {
/**
* 登录过滤器实现
*
* @param exchange ServerWebExchange
* @param chain 过滤器链
* @return
*/
@Override
public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
// 获取取请求参数
ServerHttpRequest request = exchange.getRequest();
MultiValueMap<String, String> params = request.getQueryParams();
String authorization = params.getFirst("authorization");
// 判断参数值是否等于 admin
if ("admin".equals(authorization)) {
// http://localhost:10010/order/101?authorization=admin 请求成功,放行
return chain.filter(exchange);
}
// 否,拦截
exchange.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);//设置状态码——未登录
return exchange.getResponse().setComplete();
}
}
此时若访问 http://localhost:10010/order/101?authorization=admin 时,过滤器将放行,使得请求成功。否则,将无法通过过滤器。
在 gateway 服务的 application.yml 文件中配置下的内容:
spring:
cloud:
gateway:
# ...略
globalcors: # 全局的跨域处理
add-to-simple-url-handler-mapping: true # 解决options请求被拦截问题
corsConfigurations:
'[/**]':
allowedOrigins: # 允许哪些网站的跨域请求
- "http://localhost:8090"
allowedMethods: # 允许的跨域ajax的请求方式
- "GET"
- "POST"
- "DELETE"
- "PUT"
- "OPTIONS"
allowedHeaders: "*" # 允许在请求中携带的头信息
allowCredentials: true # 是否允许携带cookie
maxAge: 360000 # 这次跨域检测的有效期
本复习随笔笔记依据 SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式,系统详解springcloud微服务技术栈课程|黑马程序员Java微服务 课程教学顺序辅助完成。
感谢@黑马程序员讲师的热情与付出,用颇为生动的授课方式让我愉快地入门了 Java 微服务框架。
SpringCloud课程资料链接:点我进入
matlab打开matlab,用最简单的imread方法读取一个图像clcclearimg_h=imread('hua.jpg');返回一个数组(矩阵),往往是a*b*cunit8类型解释一下这个三维数组的意思,行数、数和层数,unit8:指数据类型,无符号八位整形,可理解为0~2^8的数三个层数分别代表RGB三个通道图像rgb最常用的是24-位实现方法,即RGB每个通道有256色阶(2^8)。基于这样的24-位RGB模型的色彩空间可以表现256×256×256≈1670万色当imshow传入了一个二维数组,它将以灰度方式绘制;可以把图像拆分为rgb三层,可以以灰度的方式观察它figure(1
这篇文章是继上一篇文章“Observability:从零开始创建Java微服务并监控它(一)”的续篇。在上一篇文章中,我们讲述了如何创建一个Javaweb应用,并使用Filebeat来收集应用所生成的日志。在今天的文章中,我来详述如何收集应用的指标,使用APM来监控应用并监督web服务的在线情况。源码可以在地址 https://github.com/liu-xiao-guo/java_observability 进行下载。摄入指标指标被视为可以随时更改的时间点值。当前请求的数量可以改变任何毫秒。你可能有1000个请求的峰值,然后一切都回到一个请求。这也意味着这些指标可能不准确,你还想提取最小/
目录前言滤波电路科普主要分类实际情况单位的概念常用评价参数函数型滤波器简单分析滤波电路构成低通滤波器RC低通滤波器RL低通滤波器高通滤波器RC高通滤波器RL高通滤波器部分摘自《LC滤波器设计与制作》,侵权删。前言最近需要学习放大电路和滤波电路,但是由于只在之前做音乐频谱分析仪的时候简单了解过一点点运放,所以也是相当从零开始学习了。滤波电路科普主要分类滤波器:主要是从不同频率的成分中提取出特定频率的信号。有源滤波器:由RC元件与运算放大器组成的滤波器。可滤除某一次或多次谐波,最普通易于采用的无源滤波器结构是将电感与电容串联,可对主要次谐波(3、5、7)构成低阻抗旁路。无源滤波器:无源滤波器,又称
Transformers开始在视频识别领域的“猪突猛进”,各种改进和魔改层出不穷。由此作者将开启VideoTransformer系列的讲解,本篇主要介绍了FBAI团队的TimeSformer,这也是第一篇使用纯Transformer结构在视频识别上的文章。如果觉得有用,就请点赞、收藏、关注!paper:https://arxiv.org/abs/2102.05095code(offical):https://github.com/facebookresearch/TimeSformeraccept:ICML2021author:FacebookAI一、前言Transformers(VIT)在图
我想开始使用“Sinatra”框架进行编码,但我找不到该框架的“MVC”模式。是“MVC-Sinatra”模式或框架吗? 最佳答案 您可能想查看Padrino这是一个围绕Sinatra构建的框架,可为您的项目提供更“类似Rails”的感觉,但没有那么多隐藏的魔法。这是使用Sinatra可以做什么的一个很好的例子。虽然如果您需要开始使用这很好,但我个人建议您将它用作学习工具,以对您来说最有意义的方式使用Sinatra构建您自己的应用程序。写一些测试/期望,写一些代码,通过测试-重复:)至于ORM,你还应该结帐Sequel其中(imho
写在之前Shader变体、Shader属性定义技巧、自定义材质面板,这三个知识点任何一个单拿出来都是一套知识体系,不能一概而论,本文章目的在于将学习和实际工作中遇见的问题进行总结,类似于网络笔记之用,方便后续回顾查看,如有以偏概全、不祥不尽之处,还望海涵。1、Shader变体先看一段代码......Properties{ [KeywordEnum(on,off)]USL_USE_COL("IsUseColorMixTex?",int)=0 [Toggle(IS_RED_ON)]_IsRed("IsRed?",int)=0}......//中间省略,后续会有完整代码 #pragmamulti_c
TCL脚本语言简介•TCL(ToolCommandLanguage)是一种解释执行的脚本语言(ScriptingLanguage),它提供了通用的编程能力:支持变量、过程和控制结构;同时TCL还拥有一个功能强大的固有的核心命令集。TCL经常被用于快速原型开发,脚本编程,GUI和测试等方面。•实际上包含了两个部分:一个语言和一个库。首先,Tcl是一种简单的脚本语言,主要使用于发布命令给一些互交程序如文本编辑器、调试器和shell。由于TCL的解释器是用C\C++语言的过程库实现的,因此在某种意义上我们又可以把TCL看作C库,这个库中有丰富的用于扩展TCL命令的C\C++过程和函数,所以,Tcl是
目录SpringBootStarter是什么?以前传统的做法使用SpringBootStarter之后starter的理念:starter的实现: 创建SpringBootStarter步骤在idea新建一个starter项目、直接执行下一步即可生成项目。 在xml中加入如下配置文件:创建proterties类来保存配置信息创建业务类:创建AutoConfiguration测试如下:SpringBootStarter是什么? SpringBootStarter是在SpringBoot组件中被提出来的一种概念、简化了很多烦琐的配置、通过引入各种SpringBootStarter包可以快速搭建出一
按照目前的情况,这个问题不适合我们的问答形式。我们希望答案得到事实、引用或专业知识的支持,但这个问题可能会引发辩论、争论、投票或扩展讨论。如果您觉得这个问题可以改进并可能重新打开,visitthehelpcenter指导。关闭10年前。我一直在Rails上做两个项目,它们运行良好,但在这个过程中重新发明了轮子,自来水(和热水)和止痛药,正如我随后了解到的那样,这些已经存在于框架中。那么基本上,正确了解框架中所有智能部分的最佳方法是什么,这将节省时间而不是自己构建已经实现的功能?从第1页开始阅读文档?是否有公开所有内容的特定示例应用程序?一个特定的开源项目?所有的rails交通?还是完全
关闭。这个问题不符合StackOverflowguidelines.它目前不接受答案。我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。关闭4年前。Improvethisquestion我希望能够将模板化的YARD文档样式注释插入到我现有的Rails遗留应用程序中。目前它的评论很少。我想要具有指定参数的类header和方法header(通过从我假定的方法签名中提取)和返回值的占位符。在PHP代码中,我有一些工具可以检查代码并在适当的位置创建插入到代码中的文档header注释。在带有Ducktyping等的Ruby中,我确信诸如@params等类型之类