如果能跟踪每个请求,中间请求经过哪些微服务,请求耗时,网络延迟,业务逻辑耗时等。我们就能更好地分析系统瓶颈、解决系统问题。因此链路跟踪很重要。
链路追踪目的:解决错综复杂的服务调用中链路的查看。排查慢服务。
市面上链路追踪产品,大部分基于google的Dapper论文。
Sleuth是Spring cloud的分布式跟踪解决方案。
span(跨度),基本工作单元。一次链路调用,创建一个span,span用一个64位id唯一标识。包括:id,描述,时间戳事件,spanId,span父id。
span被启动和停止时,记录了时间信息,初始化span叫:root span,它的span id和trace id相等。
trace(跟踪),一组共享“root span”的span组成的树状结构 称为 trace,trace也有一个64位ID,trace中所有span共享一个trace id。类似于一颗 span 树。
annotation(标签),annotation用来记录事件的存在,其中,核心annotation用来定义请求的开始和结束。
其实数据结构是一颗树,从root span 开始。
在每个需要被监控的系统的pom中引入:
|
|
启动后,日志中可以看到类似于:[account-service,,,]
的数据,说明如下:
|
|
zipkin是twitter开源的分布式跟踪系统。
原理收集系统的时序数据,从而追踪微服务架构中系统延时等问题。还有一个友好的界面。
由4个部分组成:Collector(采集器)、Storage(存储器)、Restful API(接口)、Web UI
sleuth收集跟踪信息通过http请求发送给zipkin server,zipkin将跟踪信息存储,以及提供RESTful API接口,zipkin ui通过调用api进行数据展示。
默认内存存储,可以用mysql,ES等存储。
在每个需要被监控的系统的pom中引入:
|
|
在每个需要监听的服务的配置文件中加入:
|
|
根据zipkin官网中的Quickstart,启动zipkin。
在项目的 POM 中引入
|
|
可以通过/actuator
查看所有的暴露端点。
|
|
health端点会聚合你程序的健康指标,来检查程序的健康情况。端点公开的应用健康信息取决于:management.endpoint.health.show-details=always
show-details的值:
metrics端点用来返回当前应用的各类重要度量指标,比如:内存信息、线程信息、垃圾回收信息、tomcat、数据库连接池等。
调用:"http://localhost:8080/actuator/metrics/{requiredMetricName}"
获得各个指标。如:http://localhost:8080/actuator/metrics/jvm.memory.max
loggers 端点暴露了我们程序内部配置的所有logger的信息。
调用:http://localhost:8080/actuator/loggers
获得所有的logger信息。
可以调用对应的POST接口,修改日志级别等。
info端点可以用来展示你程序的信息。我理解过来就是一些程序的基础信息。并且你可以按照自己的需求在配置文件 application.properties中个性化配置。
beans端点会返回Spring 容器中所有bean的别名、类型、是否单例、依赖等信息。
访问:http://localhost:8080/actuator/heapdump
会自动生成一个 Jvm 的堆文件 heapdump。我们可以使用 JDK 自带的 Jvm监控工具,VisualVM 打开此文件查看内存快照。
主要展示了线程名、线程ID、线程的状态、是否等待锁资源、线程堆栈等信息。就是可能查看起来不太直观。访问:http://localhost:8080/actuator/threaddump
这个端点属于操作控制类端点,可以优雅关闭 Spring Boot 应用。要使用这个功能首先需要在配置文件中开启:
由于 shutdown 接口默认只支持 POST 请求。
获取应用所有可用的环境属性报告
获取应用所有Spring Web的控制器映射关系报告
获取应用中配置的属性信息报告
在要被监控的客户端添加pom引用:
|
|
在配置文件中如下配置:
|
|
新建一个项目,引入:
|
|
然后添加注解@EnableAdminServer
基本的容错模式有:
容错理念:
Hystrix实现了 超时机制和断路器模式。
Hystrix是Netflix开源的一个类库,用于隔离远程系统、服务或者第三方库,防止级联失败,从而提升系统的可用性与容错性。主要有以下几点功能:
Hystrix的工作原理可以可以参考官网的How it Works。如果要看中文版,可以参考:Hystrix工作原理。
默认情况下hystrix使用线程池控制请求隔离
线程池隔离技术,是用 Hystrix 自己的线程去执行调用;而信号量隔离技术,是直接让 tomcat 线程去调用依赖服务。信号量隔离,只是一道关卡,信号量有多少,就允许多少个 tomcat 线程通过它,然后去执行。
信号量隔离主要维护的是Tomcat的线程,不需要内部线程池,更加轻量级。
优点 | 不足 | 适用 | |
---|---|---|---|
信号量隔离 | 轻量,无额外开销 | 不支持任务排队和主动超时 不支持异步调用 |
受信客户 高扇出(网关) 高频高速调用(cache) |
线程池隔离 | 支持排队和超时 支持异步调用 |
线程调用会产生额外的开销 | 不受信客户 有限扇出 |
独立使用Hystrix可以参考How To Use。
如果想要中文,可以参考:Hystrix都停更了,我为什么还要学?
引入依赖spring-cloud-starter-netflix-hystrix
。
在Service中:
|
|
在Application中:
|
|
@EnableCircuitBreaker注释将扫描类路径以查找任何兼容的Circuit Breaker实现。
在集成Feign的基础上修改如下:
|
|
然后在配置文件中打开:
|
|
在一些场景中,简单的触发在 FeignClient 加入 Fallback 属性即可,而另外有一些场景需要访问导致回退触发的原因,那么这个时候可以在 FeignClient 中加入 FallbackFactory 属性即可;
|
|
@FeignClient(name = "statistics-service", fallbackFactory = WebError.class)
配置项(前缀hystrix.command.*.) | 含义 |
---|---|
execution.isolation.strategy | 线程“THREAD”或信号量“SEMAPHORE”隔离(Default: THREAD) |
execution.isolation.thread.timeoutInMilliseconds | run()方法执行超时时间(Default: 1000) |
execution.isolation.semaphore.maxConcurrentRequests | 信号量隔离最大并发数(Default:10) |
circuitBreaker.errorThresholdPercentage | 熔断的错误百分比阀值(Default:50) |
circuitBreaker.requestVolumeThreshold | 断路器生效必须满足的流量阀值(Default:20) |
circuitBreaker.sleepWindowInMilliseconds | 熔断后重置断路器的时间间隔(Default:5000) |
circuitBreaker.forceOpen | 设true表示强制熔断器进入打开状态(Default: false) |
circuitBreaker.forceClosed | 设true表示强制熔断器进入关闭状态(Default: false) |
配置项(前缀hystrix.threadpool.*.) | 含义 |
---|---|
coreSize | 使用线程池时的最大并发请求(Default: 10) |
maxQueueSize | 最大LinkedBlockingQueue大小,-1表示用SynchronousQueue(Default:-1) |
default.queueSizeRejectionThreshold | 队列大小阀值,超过则拒绝(Default:5) |
Hystrix有一个不错的可选功能是能够在仪表板上监视其状态。 为了启用它,我们将spring-cloud-starter-hystrix-dashboard
和spring-boot-starter-actuator
放入项目的pom.xml中。
然后添加@EnableHystrixDashboard
注解。
启动应用程序后,将浏览器指向http://localhost:8080/hystrix,输入“ hystrix.stream”的指标URL并开始监视。
微服务间可以使用 HTTP 协议,RESTful 规范进行通信。Spring Cloud 提供了 2 种 RESTful 调用方式:Ribbon 和 Feign 。
客户端软负载组件,支持Eureka对接,支持多种可插拔LB策略。依赖 spring-cloud-starter-netflix-eureka-client
中已经默认加载了 Ribbon 的依赖。
Ribbon作为Spring Cloud的负载均衡机制的实现:
Ribbon 的自定义配置以及一些高级使用可以参考官方文档:Client Side Load Balancer: Ribbon
官网首页:https://github.com/Netflix/ribbon
ribbon-core: 核心的通用性代码。api一些配置。
ribbon-eureka:基于eureka封装的模块,能快速集成eureka。
ribbon-examples:学习示例。
ribbon-httpclient:基于apache httpClient封装的rest客户端,集成了负载均衡模块,可以直接在项目中使用。
ribbon-loadbalancer:负载均衡模块。
ribbon-transport:基于netty实现多协议的支持。比如http,tcp,udp等。
|
|
以上代码中使用 @LoadBalanced
注解,这样就可以让 RestTemplate 在请求时拥有客户端负载均衡的能力。
|
|
|
|
Ribbon 提供了很多负载均衡的策略。详情可见:
策略名称 | 策略描述 |
---|---|
BestAvailableRule(最低并发策略) | 会先过滤掉由于多次访问故障而处于断路器跳闸状态的服务,然后选择一个并发量最小的服务。逐个找服务,如果断路器打开,则忽略。 |
AvailabilityFilteringRule(可用过滤策略) | 会先过滤掉多次访问故障而处于断路器跳闸状态的服务和过滤并发的连接数量超过阀值得服务,然后对剩余的服务列表安装轮询策略进行访问。 |
WeightedResponseTimeRule(响应时间加权策略) | 据平均响应时间计算所有的服务的权重,响应时间越快服务权重越大,容易被选中的概率就越高。刚启动时,如果统计信息不中,则使用RoundRobinRule(轮询)策略,等统计的信息足够了会自动的切换到WeightedResponseTimeRule。响应时间长,权重低,被选择的概率低。反之,同样道理。此策略综合了各种因素(网络,磁盘,IO等),这些因素直接影响响应时间。 |
RetryRule(重试策略) | 先按照RoundRobinRule(轮询)的策略获取服务,如果获取的服务失败则在指定的时间会进行重试,进行获取可用的服务。如多次获取某个服务失败,就不会再次获取该服务。主要是在一个时间段内,如果选择一个服务不成功,就继续找可用的服务,直到超时。 |
RoundRobinRule(轮询策略) | 以简单轮询选择一个服务器。按顺序循环选择一个server。 |
RandomRule(随机策略) | 随机选择一个服务器。 |
ZoneAvoidanceRule(区域权衡策略)【默认实现】 | 复合判断Server所在区域的性能和Server的可用性,轮询选择服务器。 |
|
|
如上,配置IRule的新值,直接可以切换负载均衡策略
给所有的服务指定负载均衡策略:
|
|
给特定的服务指定负载均衡策略:
|
|
在服务调用的时候,我们可能不仅仅是简单地进行调用,会涉及到一些接口的校验、权限的校验等。要实现这些,可以实现ClientHttpRequestInterceptor
接口。
|
|
添加到resttemplate中
|
|
Ribbon的配置如下:
|
|
|
|
使用ribbon重试机制,请求失败后,每个6秒会重新尝试
Feign 是 Netflix 开发的声明式、模板化的 HTTP 客户端,Feign 的使用非常简单,创建一个接口,在接口上加入一些注解,这样就完成了代码开发。
Feign 是一个 Http 请求调用的轻量级框架,可以以 Java 接口注解的方式调用 Http 请求,而不用像 Java 中通过封装 HTTP 请求报文的方式直接调用。通过处理注解,将请求模板化,当实际调用的时候,传入参数,根据参数再应用到请求上,进而转化成真正的请求,这种请求相对而言比较直观。Feign 封装 了HTTP 调用流程,面向接口编程
Spring Cloud OpenFeign 通过自动配置并绑定到Spring Environment和其他Spring编程模型习惯用法,为Spring Boot应用程序提供OpenFeign集成。
使用 Feign 必须引入 spring-cloud-starter-openfeign
。在启动类 Application
上 @EnableFeignClients
注解。
|
|
简单使用Feign不需要代码耦合,但是需要硬编码接口的信息。如下:
|
|
@FeignClient
也可以脱离Eureka使用,如:@FeignClient(name = "xxx",url="")
这个url就是接口的地址。
此方法需要引入服务提供者提供的接口jar包。
|
|
以上代码中,@FeignClient(value = "producer-service")
指定了使用哪一个服务。
feign的默认配置类是:org.springframework.cloud.openfeign.FeignClientsConfiguration。默认定义了feign使用的编码器,解码器等。
允许使用@FeignClient的configuration的属性自定义Feign配置。自定义的配置优先级高于上面的FeignClientsConfiguration。
|
|
如上面所示,在配置类上加上@Configuration注解,且该类在@ComponentScan所扫描的包中,那么该类中的配置信息就会被所有的@FeignClient共享。如果想要对某些的@FeignClient添加指定的配置,则:不指定@Configuration注解(或者指定configuration,用注解忽略),而是手动使用:@FeignClient(name = "service-valuation",configuration = FeignAuthConfiguration.class)
上面代码中:
|
|
RequestInterceptor
是一个请求拦截器,我们可以继承它做很多事情,如:
|
|
如果是BasicAuth认证,可以重写BasicAuthRequestInterceptor。
然后,在配置文件中添加:
|
|
指定服务名配置:
|
|
通用配置:
|
|
属性配置比Java代码优先级高。也可通过配置设置java代码优先级高:
|
|
|
|
Feign默认支持Ribbon;Ribbon的重试机制和Feign的重试机制有冲突,所以源码中默认关闭Feign的重试机制,使用Ribbon的重试机制。
当调用服务时,如果服务返回的状态码不是200,就会进入到Feign
的ErrorDecoder
中,因此如果我们要解析异常信息,就要重写ErrorDecoder
背景:在传统应用中,组件之间的调用,通过有规范的约束的接口来实现,从而实现不同模块间良好的协作。但是被拆分成微服务后,每个微服务实例的网络地址都可能动态变化,数量也会变化,使得原来硬编码的地址失去了作用。需要一个中心化的组件来进行服务的登记和管理。
概念:实现服务治理,即管理所有的服务信息和状态。
注册中心好处:不用关心有多少提供方。
注册中心有哪些: Eureka,Nacos,Consul,Zookeeper等。
服务注册与发现包括两部分,一个是服务器端,另一个是客户端。
Eureka 启动保护机制:
如果在 15 分钟内超过 85% 的节点都没有正常的心跳,那 么Eureka 就认为客户端与注册中心出现了网络故障。
自我保护机制的触发条件:
条件:当每分钟心跳次数( renewsLastMin ) 小于 numberOfRenewsPerMinThreshold 时,并且开启自动保护模式开关( eureka.server.enable-self-preservation = true ) 时,触发自我保护机制,不再自动过期续约。
其中:
numberOfRenewsPerMinThreshold = expectedNumberOfRenewsPerMin * 续租百分比( eureka.server.renewalPercentThreshold, 默认0.85 )
expectedNumberOfRenewsPerMin = 当前注册的应用实例数 x 2 。为什么乘以 2: 默认情况下,注册的应用实例每半分钟续租一次,那么一分钟心跳两次,因此 x 2 。
解释:服务实例数10个,期望每分钟续约数10 2=20,期望阈值200.85=17,自我保护少于17时 触发。】
Eureka 启动保护机制会出现以下情况:
引入依赖 spring-cloud-starter-netflix-eureka-server
, 在启动类 Application
上,添加 @EnableEurekaServer
注解。
如果是单机服务,可以在 application.yml
中使用以下配置:
|
|
启动服务,可在 http://localhost:2000
查看项目页面。
EurekaClient 可以在客户端获取eureka服务器上的注册者信息。
引入依赖 spring-cloud-starter-netflix-eureka-client
, 在启动类 Application
上,添加 @EnableDiscoveryClient
注解。
在 application.yml
中使用以下配置:
|
|
启动项目即可。可在 http://localhost:2000
中看到注册的状态。
Eureka Server 之间是可以互相注册的。
举个例子,我们有 3 个 Eureka 注册中心,端口分别为 2001 、 2002 和 2003 。那么端口为 2001 的最基本的配置如下:
|
|
端口 2002 和 2003 服务可以根据以上规则配置。
服务器有多个网卡,eh0,eh1,eh2,只有eh0可以让外部其他服务访问进来,而Eureka client将eh1和eh2注册到Eureka server上,这样其他服务就无法访问该微服务了。有两种方式:
指定IP注册
|
|
使用spring.cloud.inetutils配置网卡选择
由于server和client通过心跳保持 服务状态,而只有状态为UP的服务才能被访问。看eureka界面中的status。
比如心跳一直正常,服务一直UP,但是此服务DB连不上了,无法正常提供服务。
此时,我们需要将 微服务的健康状态也同步到server。只需要启动eureka的健康检查就行。这样微服务就会将自己的健康状态同步到eureka。配置如下即可。
在client端加入Actuator,并配置eureka.client.healthcheck.enabled=true
,将自己真正的健康状态传播到server。
通过代码来改动服务的状态:
|
|
应用场景:比如说短信业务,欠费了等情况,可以暂时下线服务。
如果使用了eureka.instance.prefer-ip-address: true
,然后eureka.client.service-url.defaultZone
配置的IP与实例IP不一致,会出现available-replicas为空的问题。
解决方法:在eureka.instance.ip-address
中强制设置IP,然后在eureka.client.service-url.defaultZone
配置对应的IP。
本人所在的公司由于体量小,生产环境直接使用 Eureka 的默认配置进行高可用性运行,目前也没有出现太大的问题。
以下是一些实践参考文章(注意:文章中的版本号不是最新的,可能在配置上会有调整):
概念:所有功能全部打包在一起,也就是全部的功能都在一个应用包中。应用大部分是一个 war 包或 jar 包。
优点:容易开发、测试、部署,适合项目初期试错。
缺点:
随着项目越来越复杂,团队不断扩大。坏处就显现出来了。
Martin Fowler 在 2014年提出 Microservices架构
微服务是一种架构风格,将单体应用划分为小型的服务单元。
微服务架构是一种使用一系列粒度较小的服务来开发单个应用的方式。
优点:
基于微服务的特性,微服务的组件不局限于技术的实现。主要的组件有:
Spring Cloud 是实现微服务架构的一系列框架的有机集合。是在 Spring Boot 基础上构建的,用于简化分布式系统构建的工具集。是拥有众多子项目的项目集合。利用 Spring Boot 的开发便利性,巧妙地简化了分布式系统基础设施(服务注册与发现、熔断机制、网关路由、配置中心、消息总线、负载均衡、链路追踪等)的开发。
Eureka:服务注册与发现,用于服务管理。
Feign: web调用客户端,能够简化HTTP接口的调用。
Ribbon:基于客户端的负载均衡。
Hystrix:熔断降级,防止服务雪崩。
Zuul:网关路由,提供路由转发、请求过滤、限流降级等功能。
Config:配置中心,分布式配置管理。
Sleuth:服务链路追踪
Admin:健康管理
关键字有25个。关键字不能用于自定义名字,只能在特定语法结构中使用。
|
|
大约有30多个预定义的名字,比如int和true等,主要对应内建的常量、类型和函数。
|
|
其中:
这些内部预先定义的名字并不是关键字,你可以在定义中重新使用它们。在一些特殊的场景中重新定义它们也是有意义的,但是也要注意避免过度而引起语义混乱。
Go语言中的函数名、变量名、常量名、类型名、语句标号和包名等所有的命名,都遵循一个简单的命名规则:一个名字必须以一个字母(Unicode字母)或下划线开头,后面可以跟任意数量的字母、数字或下划线。
如果一个名字是在函数内部定义,那么它的就只在函数内部有效。如果是在函数外部定义,那么将在当前包的所有文件中都可以访问。名字的开头字母的大小写决定了名字在包外的可见性。如果一个名字是大写字母开头的(必须是在函数外部定义的包级名字;包级函数名本身也是包级名字),那么它将是导出的,也就是说可以被外部的包访问。
命名的建议:
|
|
匿名变量的特点是一个下画线“”,“”本身就是一个特殊的标识符,被称为空白标识符。它可以像其他标识符那样用于变量的声明或赋值(任何类型都可以赋值给它),但任何赋给这个标识符的值都将被抛弃,因此这些值不能在后续的代码中使用,也不可以使用这个标识符作为变量对其它变量进行赋值或运算。使用匿名变量时,只需要在变量声明的地方使用下画线替换即可。
|
|
常量表达式的值在编译期计算,而不是在运行期。
常量声明可以使用iota常量生成器初始化,它用于生成一组以相似规则初始化的常量,但是不用每行都写一遍初始化表达式。在一个const声明语句中,在第一个声明的常量所在的行,iota将会被置为0,然后在每一个有常量声明的行加一。
|
|
new 和 make 是两个内置函数,主要用来创建并分配类型的内存。new 只分配内存,而 make 只能用于 slice、map 和 channel 的初始化。
|
|
运算符 | 描述 | ||
---|---|---|---|
+ |
加 | ||
- |
减 | ||
* |
乘 | ||
/ |
除 | ||
% |
取余 | ||
& |
按位与 | ||
` | ` | 按位或 | |
^ |
按位异或 | ||
&^ |
按位清除(AND NOT)&^ 即 AND NOT(x, y) = AND(x, NOT(Y)) |
||
<< |
左移 | ||
>> |
右移 | ||
== |
相等 | ||
!= |
不等 | ||
< |
小于 | ||
<= |
小于等于 | ||
> |
大于 | ||
>= |
大于等于 | ||
&& |
逻辑与 | ||
` | ` | 逻辑或 | |
! |
取反 | ||
& |
寻址(生成指针) | ||
* |
获取指针指向的数据 | ||
<- |
向 channel 中发送 / 接收数据 |
init初始化函数
对于在包级别声明的变量,如果有初始化表达式则用表达式初始化,还有一些没有初始化表达式的,例如某些表格数据初始化并不是一个简单的赋值过程。在这种情况下,我们可以用一个特殊的init初始化函数来简化初始化工作。每个文件都可以包含多个init初始化函数。
|
|
数据类型分为:基础类型、复合类型、引用类型和接口类型。
复合数据类型类型包括数组、结构体、切片、字典等。
Go 语言中没有 class 类的概念,取而代之的是 struct,struct 的方法对应到类的成员函数。
结构类型可以用来描述一组数据值,这组值的本质既可以是原始的,也可以是非原始的。
|
|
匿名结构体
使用 map[string]interface{}
开销更小且更为安全。
|
|
|
|
在Go语言中,列表使用 container/list 包来实现,内部的实现原理是双链表,列表能够高效地进行任意位置的元素插入和删除操作。
初始化:
|
|
切片是有三个字段的数据结构,指向底层数组的指针,切片访问元素的个数(长度),切片允许增长到的元素的个数(容量),这种数据结构便于使用和管理数据集。切片围绕动态数组的概念构建的,可以按需自动增长和缩小。切片是一个很小的对象,对底层数组进行了抽象,并提供相关的操作方法,切片的底层内存是在连续块中分配的。
语法:
slice [开始位置 : 结束位置]
从数组或切片生成新的切片拥有如下特性:
根据索引位置取切片 slice 元素值时,取值范围是(0~len(slice)-1),超界会报运行时错误,生成切片时,结束位置可以填写 len(slice) 但不会报错。
|
|
map (映射)是一种数据结构,用于存储一系列无序的键值对。
|
|
Go语言中的 map 在并发情况下,只读是线程安全的,同时读写是线程不安全的。1.9 版本中提供了一种效率较高的并发安全的 sync.Map。
一个指针变量可以指向任何一个值的内存地址,它所指向的值的内存地址在 32 和 64 位机器上分别占用 4 或 8 个字节,占用字节的大小与所指向的值的大小无关。
当一个指针被定义后没有分配到任何变量时,它的默认值为 nil。指针变量通常缩写为 ptr。
每个变量在运行时都拥有一个地址,这个地址代表变量在内存中的位置。Go语言中使用在变量名前面添加 &操作符(前缀)来获取变量的内存地址(取地址操作),格式如下:
ptr := &v // v 的类型为 T
==其中 v 代表被取地址的变量,变量 v 的地址使用变量 ptr 进行接收,ptr 的类型为*T,称做 T 的指针类型,*代表指针。==
变量、指针和地址三者的关系是,每个变量都拥有地址,指针的值就是地址。
从指针获取指针指向的值: 当使用&
操作符对普通变量进行取地址操作并得到变量的指针后,可以对指针使用*
操作符,也就是指针取值。
变量、指针地址、指针变量、取地址、取值的相互关系和特性如下:
*操作符的根本意义就是操作指针指向的变量。当操作在右值时,就是取指向变量的值,当操作在左值时,就是将值设置给指向的变量。
new() 函数可以创建一个对应类型的指针,创建过程会分配内存,被创建的指针指向默认值。
如果说goroutine是Go语言程序的并发体的话,那么channels则是它们之间的通信机制。一个channel是一个通信机制,它可以让一个goroutine通过它给另一个goroutine发送值信息。每个channel都有一个特殊的类型,也就是channels可发送数据的类型。
通道的声明如下:
|
|
如: ch := make(chan int) // ch has type 'chan int'
两个相同类型的channel可以使用==运算符比较。如果两个channel引用的是相同的对象,那么比较的结果为真。一个channel也可以和nil进行比较。
channel的发送和接受操作:
<-
运算符示例如下:
|
|
Channels也可以用于将多个goroutine连接在一起,一个Channel的输出作为下一个Channel的输入。这种串联的Channels就是所谓的管道(pipeline)。
示例:
|
|
Go语言的类型系统提供了单方向的channel类型,分别用于只发送或只接收的channel。箭头<-
和关键字chan的相对位置表明了channel的方向。
示例:
|
|
带缓存的Channel内部持有一个元素队列。队列的最大容量是在调用make函数创建channel时通过第二个参数指定的。
向缓存Channel的发送操作就是向内部缓存队列的尾部插入元素,接收操作则是从队列的头部删除元素。如果内部缓存队列是满的,那么发送操作将阻塞直到因另一个goroutine执行接收操作而释放了新的队列空间。相反,如果channel是空的,接收操作将阻塞直到有另一个goroutine执行发送操作而向队列插入元素。
由于Go语言不存在隐式类型转换,因此所有的类型转换都必须显式的声明:
|
|
只有相同底层类型的变量之间可以进行相互转换(如将 int16 类型转换成 int32 类型),不同底层类型的变量相互转换时会引发编译错误(如将 bool 类型转换为 int 类型)。
函数的基本语法为:
|
|
|
|
匿名函数语法为:
|
|
一些示例:
|
|
函数 + 引用环境 = 闭包
|
|
|
|
|
|
|
|
case 语句自带 break,想执行所有 case 需要手动 fallthrough
|
|
Go 语言中循环结构只有 for,没有 do、while、foreach 等
|
|
Go 中没有异常处理机制,函数在调用时在有可能会产生错误,可返回一个 Error
类型的值,Error
接口:
|
|
自定义一个错误:
|
|
一个可能产生错误的函数:
|
|
Go语言的 defer 语句会将其后面跟随的语句进行延迟处理,在 defer 归属的函数即将返回时,将延迟处理的语句按 defer 的逆序进行执行,也就是说,先被 defer 的语句最后被执行,最后被 defer 的语句,最先被执行。
关键字 defer 的用法类似于面向对象编程语言 Java 的 finally 语句块,它一般用于释放某些已分配的资源,典型的例子就是对一个互斥解锁,或者关闭一个文件。因为 defer 语句正好是在函数退出时执行的语句,所以使用 defer 能非常方便地处理资源释放问题。
Go语言的 panic 机制类似于其他语言的异常,但 panic 的适用场景有一些不同,由于 panic 会引起程序的崩溃,因此 panic 一般用于严重错误,如程序内部的逻辑不一致。任何崩溃都表明了我们的代码中可能存在漏洞,所以对于大部分漏洞,我们应该使用Go语言提供的错误机制,而不是 panic。
手动触发宕机: panic("crash")
Recover 是一个Go语言的内建函数,可以让进入宕机流程中的 goroutine 恢复过来,recover 仅在延迟函数 defer 中有效,在正常的执行过程中,调用 recover 会返回 nil 并且没有其他任何效果,如果当前的 goroutine 陷入恐慌,调用 recover 可以捕获到 panic 的输入值,并且恢复正常的执行。
panic 和 recover 的组合有如下特性:
提示
虽然 panic/recover 能模拟其他语言的异常机制,但并不建议在编写普通函数时也经常性使用这种特性。
在 panic 触发的 defer 函数内,可以继续调用 panic,进一步将错误外抛,直到程序整体崩溃。
如果想在捕获错误时设置当前函数的返回值,可以对返回值使用命名返回值方式直接进行设置。
见 struct
Go语言中的继承是通过内嵌或组合来实现的
|
|
Go语言的类型或结构体没有构造函数的功能,但是我们可以使用结构体初始化的过程来模拟实现构造函数。
|
|
Go 方法是作用在接收器(receiver)上的一个函数,接收器是某种类型的变量,因此方法是一种特殊类型的函数。
接收器语法格式:
|
|
对各部分的说明:
接收器根据接收器的类型可以分为指针接收器、非指针接收器,两种接收器在使用时会产生不同的效果,根据效果的不同,两种接收器会被用于不同性能和功能要求的代码中。
指针类型的接收器由一个结构体的指针组成,更接近于面向对象中的 this 或者 self。
由于指针的特性,调用方法时,修改接收器指针的任意成员变量,在方法结束后,修改都是有效的。
|
|
当方法作用于非指针接收器时,Go语言会在代码运行时将接收器的值复制一份,在非指针接收器的方法中可以获取接收器的成员值,但修改后无效。
|
|
在计算机中,小对象由于值复制时的速度较快,所以适合使用非指针接收器,大对象因为复制性能较低,适合使用指针接收器,在接收器和参数间传递时不进行复制,只是传递指针。
不管你的method的receiver是指针类型还是非指针类型,都是可以通过指针/非指针类型进行调用的,编译器会帮你做类型转换。
在声明一个method的receiver该是指针还是非指针类型时,你需要考虑两方面的内部,第一方面是这个对象本身是不是特别大,如果声明为非指针变量时,调用会产生一次拷贝;第二方面是如果你用指针类型作为receiver,那么你一定要注意,这种指针类型指向的始终是一块内存地址,就算你对其进行了拷贝。熟悉C或者C艹的人这里应该很快能明白。
接口是用来定义行为的类型,这些被定义的行为不由接口直接实现,而是通过方法由用户定义的类型实现。Go 接口实现机制很简洁,只要目标类型方法包含接口声明的全部方法,就被视为实现了该接口,无需做显示声明。当然,目标类可以实现多个接口。如果接口没有任何方法声明,那么就是一个空接口(interface{}),它的用途类似 Object,可被赋值为任何类型的对象。
|
|
类型断言(Type Assertion)是一个使用在接口值上的操作,用于检查接口类型变量所持有的值是否实现了期望的接口或者具体的类型。
value, ok := x.(T)
其中,x 表示一个接口的类型,T 表示一个具体的类型(也可为接口类型)。
该断言表达式会返回 x 的值(也就是 value)和一个布尔值(也就是 ok),可根据该布尔值判断 x 是否为 T 类型:
goroutine 是 Go语言中的轻量级线程实现,由 Go 运行时(runtime)管理。Go 程序会智能地将 goroutine 中的任务合理地分配给每个 CPU。
Go 程序从 main 包的 main() 函数开始,在程序启动时,Go 程序就会为 main() 函数创建一个默认的 goroutine。
使用普通函数创建 goroutine:
Go 程序中使用 go 关键字为一个函数创建一个 goroutine。一个函数可以被创建多个 goroutine,一个 goroutine 必定对应一个函数。语法:go 函数名( 参数列表 )
。使用 go 关键字创建 goroutine 时,被调用函数的返回值会被忽略。如果需要在 goroutine 中返回数据,请使用后面介绍的通道(channel)特性,通过通道把数据从 goroutine 中作为返回值传出。
也可以使用匿名函数创建:
|
|
示例:
|
|
Go语言提供了一种机制,能够在运行时更新变量和检查它们的值、调用它们的方法和它们支持的内在操作,而不需要在编译时就知道这些变量的具体类型。这种机制被称为反射。
反射是由 reflect 包提供的。 它定义了两个重要的类型, Type 和 Value。
标题:Golang 之禅
地址:https://www.oschina.net/news/113606/the-zen-of-go
在本月初的 GopherCon 上,知名 Go 语言贡献者与布道师 Dave Cheney 发表了名为《The Zen of Go》的演讲,之后他整理了演讲内容在博客中分享,由于内容过长,他又写了一个简洁版本:
完整版:https://dave.cheney.net/2020/02/23/the-zen-of-go
简洁版:https://the-zen-of-go.netlify.com
这里简单翻译一下简洁版本的内容:
编写简单、可读、可维护的 Go 代码的十个工程要点。
每个包实现单一目标
设计良好的 Go 软件包提供一个单一的思路,以及一系列相关的行为。一个好的 Go 软件包首先需要选择一个好名字,使用电梯法则(30 秒内向客户讲清楚一个方案),仅用一个词来思考你的软件包要提供什么功能。
明确处理错误
健壮的程序其实是由处理故障案例的片段组成的,并且需要在故障出现之前处理好。冗余的if err != nil { return err }比出了故障再一个个去处理更有价值。panic 和 recover 也一样。
尽早 return,不要深陷
每次缩进时都会在程序员的堆栈中添加另一个先决条件,这会占用他们短期内存中的 7±2 个片段。避免需要深层缩进的控制流。与其深入嵌套,不如使用守卫子句将成功路径保持在左侧。
并发权留给调用者
让调用者选择是否要异步运行你的库或函数,不要强制他们使用异步。
在启动 goroutine 之前,要知道它什么时候会停止
goroutines 拥有资源、锁、变量与内存等,释放这些资源的可靠方法是停止 goroutine。
避免包级别的状态
要完成明确和减少耦合的操作,需要通过提供类型需要的依赖项作为该类型上的字段,而不是使用包变量。
简单性很重要
简单性不是老练的代名词。简单并不意味着粗糙,它意味着可读性和可维护性。如果可以选择,请遵循较简单的解决方案。
编写测试以确认包 API 的行为
软件包的 API 是与使用者的一份合约,不管先后,不管多少,一定要进行测试。测试是确定合约的保证。要确保测试使用者可以观察和依赖的行为。
如果你认为速度缓慢,先通过基准测试进行验证
以性能之名会犯下许多危害可维护性的罪行。优化会破坏抽象、暴露内部和紧密耦合。如果要付出这样的代价,请确保有充分理由这样做。
节制是一种美德
适度使用 goroutine、通道、锁、接口与嵌套。
]]>在使用 Python 的时候,logging 一度让我头疼。因为,从 Java 转过来以后,总是想着 logback、log4j 那样的统一配置。在使用过程中折腾了些时候,算是勉强给出了自己比较满意的效果。
日志的简单使用可以参考官方的《日志操作手册》
其他的学习资料有:
我的 logging 配置主要基于 Tornado 的日志模块进行了修改。代码如下:
|
|
以上的代码没有考虑到多线程情况下的使用场景,且暂时考虑的是在应用程序中使用的场景。
]]>AES 是 Advanced Encryption Standard 的缩写,也就是 高级加密标准 。具体可以见:高级加密标准。本文主要讨论使用 Java SDK中对 AES 的实现。
从 JDK 的 Cipher 文档 中,知道它支持 4 种 AES 加密模式:
AES 是一种加解密算法,那么 CBC, ECB, NoPadding 和 PKCS5Padding 是什么呢?
CBC, CBC 是分组密码工作模式,是对于按块处理密码的加密方式的一种扩充。NoPadding, PKCS5Padding 是填充(Padding),是对需要按块处理的数据,当数据长度不符合块处理需求时,按照一定方法填充满块长的一种规则。
关于分组密码工作模式,可以参考: 分组密码工作模式 和 AES五种加密模式(CBC、ECB、CTR、OCF、CFB)
关于填充,可以参考:Padding (cryptography)
参考,JAVA AES算法 知道(以下部分的内容为该文章里的内容):
|
|
以上代码中 iv
的长度为 cipher.getBlockSize()
,然后将 iv
放在加密文本的前部分。解密的时候一样先获得 iv
,再进行加密内容的解密。
SpringBoot 2.x项目中引入spring-boot-starter-data-redis
:
|
|
查看引入包,发现SpringBoot 2.x 使用的是: lettuce
。
配置 application.yml
|
|
使用:
|
|
SpringBoot Redis的自动化配置位于:RedisAutoConfiguration
项目中常常用到不止一个Redis数据源,如果按照上面的简单配置,那么很难满足需要。需要我们自己来声明 ConnectionFactory
和 RedisTemplate
。
application.yml
中配置如下:
|
|
以上配置是在spring.redis
下做区分两个数据源,这是为了能够方便地查找配置位置。
添加RedisConfig.java
,如下:
|
|
使用:
|
|
如果想要忽略掉默认的Redis配置,那么可以将 RedisAutoConfiguration
和 RedisReactiveAutoConfiguration
加入忽略:
|
|
安装 Node.js 、安装以太节点以及合约代码等与web3.js编译Solidity,发布,调用全部流程(手把手教程)中的一致。
按照官方文档使用 npm install -g solc
安装。
安装后验证版本应该使用 solcjs --version
,而不是 solc --version
。而且这边安装的是最新版本,也为后面的步骤埋下了坑。
使用以下代码:
|
|
运行的时候报:
|
|
这个是因为 Geth 在 1.5.9 版本以后就不支持此功能。见:Ethereum Dapp初心者之路(7): web3.eth.compile.solidity()替代方案。
所以参考 https://ethereum.stackexchange.com/questions/6346/solc-version-command-not-found 文章,将代码改为:
|
|
编译的时候,如果遇到以下报错:
|
|
这个是因为 solc 的版本不对,我们的代码中的版本是 ^0.4.0
,而安装的 solc 的版本为 ^0.5.7
。应该用一样的版本。
代码中的版本改为^0.5.7
,即pragma solidity ^0.5.7;
。运行后,报:
|
|
|
|
然后将代码中的版本号改为:pragma solidity ^0.4.25;
index.js:
|
|
Calc.sol:
|
|
package.json:
|
|
官方网站:http://lightning.network/
闪电网络(Lightning Network)是一个去中心化的系统。闪电网络的卓越之处在于,无需信任对方以及第三方即可实现实时的、海量的交易网络。这也就解决了比特币支付存在着拥堵的问题。
闪电网络是基于微支付通道演进而来,创造性的设计出了两种类型的交易合约:序列到期可撤销合约RSMC(Revocable Sequence Maturity Contract),哈希时间锁定合约HTLC(Hashed Timelock Contract)。
RSMC解决了通道中币单向流动问题,也就是链下交易的确认问题;HTLC解决了币跨节点传递的问题,也就是支付通道问题。这两个类型的交易组合构成了闪电网络。
1. 入门级文字:
2. 如果不喜欢文字资料,还可以通过以下两个视频简单入门:
3. 白皮书:
4. 其他资料:
其他:
闪电网络的钱包可以参考Lightning mobile wallets列表。
GitHub上开源的钱包项目:
桌面
Web
移动端
可以参考Lightning mobile wallets中Open source
为yes
的项目。
在闪电网络的实现方面,现在比较主流的有Lightning Network Daemon、eclair和c-lightning。这三个实现是兼容的。
LND是论文《The Bitcoin Lightning Network: Scalable Off-Chain Instant Payments》中提出者的项目,使用Go语言编写,它比较适用于社区和开发者方面。
开发支持:
风险:目前LND还不支持导出私钥https://github.com/lightningnetwork/lnd/issues/732
Eclair(法语闪电)是闪电网络的Scala实现。它可以运行GUI,也可以不运行GUI,还可以使用JSON-RPC API。因为是Scala开发的,所以适用于所有的java语言,适合商业场景。
用C实现的一个规范兼容的闪电网络。
从源码构建bitcoin客户端,我们分为以下几步:
所以,我们的Dockerfile如下:
|
|
运行docker build -f bitcoin.dockerfile -t bitcoin-alpine .
构建一个docker镜像。
在成功构建镜像后,通过命令运行镜像docker run -it bitcoin-alpine-bin
。
bitcoind 默认的安装位置是/usr/local/bin。你可以通过询问系统下面2个可执行文件的路径,来确认bitcoin是否安装成功。
|
|
然后,在运行的容器中运行bitcoin的后台程序:
bitcoind -server=1 -rest=1 -regtest -txindex=1 -daemon
通过运行bitcoin-cli -regtest getblockchaininfo
,bitcoin-cli -regtest getnetworkinfo
,bitcoin-cli -regtest getwalletinfo
可以获得到相关的状态信息。
其中:
|
|
参考:
]]>
|
|
运行docker images
查看:
|
|
|
|
上述命令中的19001 和 19011是配置给两个节点提供RPC服务的端口。
运行make start
命令启动。
|
|
使用make getinfo
命令获得节点信息
|
|
使用make generate
命令产生一个区块。
|
|
使用make generate BLOCKS=数量
命令批量产生区块。
|
|
https://blog.csdn.net/yzpbright/article/details/81004202
https://www.codeooze.com/blockchain/bitcoind-running-in-docker/
]]>我们继承WebMvcConfigurationSupport可以自定义SpringMvc的配置。
跟踪发现DelegatingWebMvcConfiguration类是WebMvcConfigurationSupport的一个实现类,DelegatingWebMvcConfiguration类的setConfigurers方法可以收集所有的WebMvcConfigurer实现类中的配置组合起来,组成一个超级配置(这些配置会覆盖掉默认的配置)。而@EnableWebMvc又引入了DelegatingWebMvcConfiguration。
所以,我们继承了WebMvcConfigurationSupport,而后使用@EnableWebMvc会覆盖掉原来的配置。
WebMvcConfigurer配置类其实是Spring内部的一种配置方式,采用JavaBean的形式来代替传统的xml配置文件形式进行针对框架个性化定制。
在官方文档中有这么一段话:
>
If you want to keep Spring Boot MVC features and you want to add additional MVC configuration (interceptors, formatters, view controllers, and other features), you can add your own @Configuration class of type WebMvcConfigurer but without @EnableWebMvc.
所以,如果我们想要在Auto-configuration的基础上配置自定义的interceptors, formatters, view controllers等功能话,我们可以实现WebMvcConfigurer,并用@Configuration注释。
WebMvcConfigurer的主要方法有:
这里的“@EnableAutoConfiguration中的设置”是指,读取 application.properties 或 application.yml 文件中的配置。
所以,如果需要使用springBoot的@EnableAutoConfiguration中的设置,那么就只需要“implement WebMvcConfigurer”即可。如果,需要自己扩展同时不使用@EnableAutoConfiguration中的设置,可以选择另外的方式。
]]>参考官方的Running in Docker,具体的解释如下:
拉取镜像:
docker pull ethereum/client-go
启动一个节点:
docker run -it -p 30303:30303 ethereum/client-go
启动一个节点并在8545上运行JSON-RPC接口:
docker run -it -p 8545:8545 -p 30303:30303 ethereum/client-go --rpc --rpcaddr "0.0.0.0"
注意:“0.0.0.0”参数会在8545接口上接收所有主机发送的请求,公共网络慎用!
使用javascript控制台进行交互操作,可运行下命令启动节点:
docker run -it -p 30303:30303 ethereum/client-go console
docker run -it -p 30303:30303 -v /path/on/host:/root/.ethereum ethereum/client-go
-v参数指定了存储的路径。上面的命令会将/root/.ethereum挂载到本地路径/path/on/host下面。这样,容器启动以后,数据的实际存储路径就在/path/on/host下。
运行上面的命令后,节点会自动去拉取主网的区块数据。我们可以连接到运行的容器中去执行各个操作。
运行docker ps -a
查看容器实例。
|
|
执行命令docker exec -it eloquent_wiles /bin/sh
,其中eloquent_wiles是容器的名字。这样,它就连接到了现在运行的容器了。
示例操作:
|
|
默认情况下,当节点启动时会在 datadir 指定的目录之下,生成一个名字为 geth.ipc 的文件,当程序关闭时此文件随之消失。可以使用–ipcpath参数修改掉路径。可以配合 attach 命令来进入与 geth 节点进行 js 交互的窗口。基本命令为:/geth attach rpc:/path/on/host/geth.ipc
关于eth.blockNumber返回0的原因可以查看:
先来一条执行的命令:
|
|
-it:交互式运行模式,-i 标准输入给容器,-t 分配一个虚拟终端
-d:以守护进程方式运行(后台)
-p:指定端口号
-P:随机分配端口号
–name:指定容器名称
–network:指定网络连接
–ip:分配ip地址
–rinkeby:运行rinkeby网络,不设置默认为主网。
–rpc:启用HTTP-RPC服务
–rpcaddr:HTTP-RPC服务监听接口(默认:localhost)
–rpcapi:HTTP-RPC接口提供的api(默认:eth、net、web3)
–fast:快速同步模式启动Geth
–cache=512:内存容量分配
–dev:开发模式
–nodiscover:关闭节点自动发现,允许手动连接
–networkid:设置隔离网络(主网络id为1)
–verbosity 日志等级:0=silent, 1=error, 2=warn, 3=info, 4=debug, 5=detail (default: 3)
console:进入JavaScript控制台
更多的参数可以见下节。
geth的命令可以在客户端运行geth -help
或者在Command Line Options中查看。
中文资料可以参考:以太坊客户端Geth命令用法-参数详解
目录如下:
]]>Docker命令分为两大类:客户端命令和服务端命令。前者主要是操作接口,后者用来启动Docker daemon。
客户端命令基本格式:docker [OPTIONS] COMMAND [arg...]
服务端命令基本格式:docker daemon [OPTIONS]
执行 docker --help
命令可以列出Docker的使用帮助,具体如下:
|
|
参考:
]]>注解 | 解释 |
---|---|
@Required | @Required注解检查。但它只检查属性是否已经设置而不会测试属性是否非空。@Required只能设置在setter方法上 |
@Autowired | Spring提供的注入工具【由Spring的依赖注入工具(BeanPostProcessor、BeanFactoryPostProcessor)自动注入】 |
@Qualifier | 如果需要byName(byName就是通过id去标识)注入,增加@Qualifier注释。一般在候选Bean数目不为1时应该加@Qualifier注释。 |
@Configuration | 在用于指定配置信息的类上加上 @Configuration 注解,以明确指出该类是 Bean 配置的信息源。 |
@ComponentScan | @ComponentScan告诉Spring 哪个packages 的用注解标识的类 会被spring自动扫描并且装入bean容器 |
@Bean | @Bean注解用于告诉方法,产生一个Bean对象,然后这个Bean对象交给Spring管理。产生这个Bean对象的方法Spring只会调用一次,随后这个Spring将会将这个Bean对象放在自己的IOC容器中。 |
@Lazy | 如果我们想要 Spring 在启动的时候延迟加载 bean,即在调用某个 bean 的时候再去初始化,那么就可以使用 @Lazy 注解。 |
@Value | 使用@Value注解,可以直接将属性值注入到beans中。 |
@Resource | @Resource用法与@Autowired 用法 用法相似,也是做依赖注入的,从容器中自动获取bean。 |
@Inject | 这是jsr330中的规范,通过‘AutowiredAnnotationBeanPostProcessor’ 类实现的依赖注入。 |
@PropertySource | 指定文件地址。提供了一种方便的、声明性的机制,用于向Spring的环境添加PropertySource。与@configuration类一起使用。 |
@PostConstruct | 标注在方法上,该方法在构造函数执行完成之后执行。 |
@PreDestroy | 标注在方法上,该方法在对象销毁之前执行。 |
@ActiveProfiles | 用来声明活动的profile–@ActiveProfiles(“prod”(这个prod定义在配置类中)) |
@Profile | 表示当一个或多个指定的文件是活动的时,一个组件是有资格注册的。使用@Profile注解类或者方法,达到在不同情况下选择实例化不同的Bean。@Profile(“dev”)表示为dev时实例化。 |
@Component | 表示一个带注释的类是一个“组件”,成为Spring管理的Bean。当使用基于注解的配置和类路径扫描时,这些类被视为自动检测的候选对象。同时@Component还是一个元注解。 |
@Controller | 组合注解(组合了@Component注解),应用在MVC层(控制层),DispatcherServlet会自动扫描注解了此注解的类,然后将web请求映射到注解了@RequestMapping的方法上。 |
@Service | 组合注解(组合了@Component注解),应用在service层(业务逻辑层) |
@Reponsitory | 组合注解(组合了@Component注解),应用在dao层(数据访问层) |
@RestController | @RestController注解相当于@ResponseBody + @Controller合在一起的作用。 |
@ResponseBody | 将返回值放在response体内。返回的是数据而不是页面 |
@RequestBody | 允许request的参数在request体中,而不是在直接链接在地址的后面。此注解放置在参数前。 |
@PathVariable | 放置在参数前,用来接受路径参数。 |
@ModelAttribute | 将键值对添加到全局,所有注解了@RequestMapping的方法可获得次键值对(就是在请求到达之前,往model里addAttribute一对name-value而已)。 |
@RequestAttribute | 注解@RequestAttribute 可以被用于访问由过滤器或拦截器创建的、预先存在的请求属性 |
@RequestHeader | 获得指定的请求中的Header信息 |
@RequestParam | 请求参数绑定 |
@ResponseStatus | 带有@ResponseStatus注解的异常类会被ResponseStatusExceptionResolver 解析。可以实现自定义的一些异常,同时在页面上进行显示。 |
@CookieValue | 用来获取Cookie中的值 |
@CrossOrigin | @CrossOrigin是用来处理跨域请求的注解 |
@RequestMapping | 用来映射web请求(访问路径和参数),处理类和方法的。可以注解在类和方法上,注解在方法上的@RequestMapping路径会继承注解在类上的路径。同时支持Serlvet的request和response作为参数,也支持对request和response的媒体类型进行配置。其中有value(路径),produces(定义返回的媒体类型和字符集),method(指定请求方式)等属性。 |
@GetMapping | GET请求 |
@PostMapping | POST请求 |
@PutMapping | PUT请求 |
@PatchMapping | PATCH请求 |
@DeleteMapping | DELETE请求 |
@ExceptionHandler | 用在方法上定义全局处理,通过他的value属性可以过滤拦截的条件:@ExceptionHandler(value=Exception.class)–表示拦截所有的Exception。 |
@ControllerAdvice | 用在类上,声明一个控制器建言,它也组合了@Component注解,会自动注册为Spring的Bean |
@InitBinder | 通过@InitBinder注解定制WebDataBinder(用在方法上,方法有一个WebDataBinder作为参数,用WebDataBinder在方法内定制数据绑定,例如可以忽略request传过来的参数Id等)。 |
@SessionAttribute | @SessionAttribute作用于处理器类上,用于在多个请求之间传递参数,类似于Session的Attribute,但不完全一样,一般来说@SessionAttribute设置的参数只用于暂时的传递,而不是长期的保存,长期保存的数据还是要放到Session中。 |
@SessionAttributes | @sessionattributes注解应用到Controller上面,可以将Model中的属性同步到session当中。 |
@Aspect | 声明一个切面(就是说这是一个额外功能) |
@After | 后置建言(advice),在原方法前执行。 |
@Before | 前置建言(advice),在原方法后执行。 |
@Around | 环绕建言(advice),在原方法执行前执行,在原方法执行后再执行(@Around可以实现其他两种advice) |
@PointCut | 声明切点,即定义拦截规则,确定有哪些方法会被切入 |
@EnableAspectJAutoProxy | 开启Spring对AspectJ的支持 |
@SpingBootApplication | SpringBoot的核心注解,主要目的是开启自动配置。它也是一个组合注解,主要组合了@Configurer,@EnableAutoConfiguration(核心)和@ComponentScan。可以通过@SpringBootApplication(exclude={想要关闭的自动配置的类名.class})来关闭特定的自动配置。 |
@Async | 注解在方法上标示这是一个异步方法,在类上标示这个类所有的方法都是异步方法。 |
@EnableAsync | 开启异步任务支持。注解在配置类上。 |
@Scheduled | 注解在方法上,声明该方法是计划任务。支持多种类型的计划任务:cron,fixDelay,fixRate |
@EnableScheduling | 注解在配置类上,开启对计划任务的支持。 |
@EnableAutoConfiguration | 此注释自动载入应用程序所需的所有Bean——这依赖于Spring Boot在类路径中的查找。该注解组合了@Import注解,@Import注解导入了EnableAutoCofigurationImportSelector类,它使用SpringFactoriesLoader.loaderFactoryNames方法来扫描具有META-INF/spring.factories文件的jar包。而spring.factories里声明了有哪些自动配置。 |
@WebAppConfiguration | 一般用在测试上,注解在类上,用来声明加载的ApplicationContext是一个WebApplicationContext。他的属性指定的是Web资源的位置,默认为src/main/webapp,我们可以修改为:@WebAppConfiguration(“src/main/resources”)。 |
@Cacheable | 声明数据缓存 |
@EnableWebMvc | 用在配置类上,开启SpringMvc的Mvc的一些默认配置:如ViewResolver,MessageConverter等。同时在自己定制SpringMvc的相关配置时需要做到两点:1.配置类继承WebMvcConfigurerAdapter类 2.就是必须使用这个@EnableWebMvc注解。 |
@BeforeTransaction | @BeforeTransaction在事务之前执行 |
@AfterTransaction | @AfterTransaction在事务之后执行 |
@Transactional | 声明事务(一般默认配置即可满足要求,当然也可以自定义) |
@ImportResource | 虽然Spring提倡零配置,但是还是提供了对xml文件的支持,这个注解就是用来加载xml配置的。 |
@ConfigurationProperties | 将properties属性与一个Bean及其属性相关联,从而实现类型安全的配置。 |
@Conditional | 根据满足某一特定条件创建特定的Bean |
@ConditionalOnBean | 条件注解。当容器里有指定Bean的条件下。 |
@ConditionalOnClass | 条件注解。当类路径下有指定的类的条件下。 |
@ConditionalOnExpression | 条件注解。基于SpEL表达式作为判断条件。 |
@ConditionalOnJava | 条件注解。基于JVM版本作为判断条件。 |
@ConditionalOnJndi | 条件注解。在JNDI存在的条件下查找指定的位置。 |
@ConditionalOnMissingBean | 条件注解。当容器里没有指定Bean的情况下。 |
@ConditionalOnMissingClass | 条件注解。当类路径下没有指定的类的情况下。 |
@ConditionalOnNotWebApplication | 条件注解。当前项目不是web项目的条件下。 |
@ConditionalOnResource | 条件注解。类路径是否有指定的值。 |
@ConditionalOnSingleCandidate | 条件注解。当指定Bean在容器中只有一个,后者虽然有多个但是指定首选的Bean。 |
@ConditionalOnWebApplication | 条件注解。当前项目是web项目的情况下。 |
@EnableConfigurationProperties | 注解在类上,声明开启属性注入,使用@Autowired注入。 |
@AutoConfigureAfter | 在指定的自动配置类之后再配置。 |
@AutoConfigureBefore | 在指定的自动配置类之前进行配置。 |
@RunWith | 这个是Junit的注解,springboot集成了junit。一般在测试类里使用。 |
@ContextConfiguration | 用来加载配置ApplicationContext,其中classes属性用来加载配置 |
参考:
]]>