spring cloud连载第二篇之Spring Cloud Config
Spring Cloud Config
Spring Cloud Config为分布式服务提供了服务侧和客户侧的外部配置支持。通过Spring Cloud Config你可以有一个统一的地方来管理所有应用的外部配置。
默认服务端存储实现用的是git,因此,它很容易支持配置环境的标签版本,并且可以访问各种管理内容的工具。
1. Quick Start
此小结将介绍Spring Cloud Config Server的客户端和服务端。
首先,启动服务端:
$ cd spring-cloud-config-server
$ ../mvnw spring-boot:run
接着试一下客户端:
$ curl localhost:8888/foo/development
{"name":"foo","label":"master","propertySources":[
{"name":"https://github.com/scratches/config-repo/foo-development.properties","source":{"bar":"spam"}},
{"name":"https://github.com/scratches/config-repo/foo.properties","source":{"foo":"bar"}}
]}
默认定位属性资源的策略是使用git(spring.cloud.config.server.git.uri),并且用它来初始化一个迷你SpringApplication,这个迷你application的Environment是用来枚举属性资源并将它发布到一个JSON端点。
HTTP服务的格式如下:
/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties
其中application是是使用spring.config.name属性注入的,profile是一个激活的配置文件(或者是以逗号分隔的属性),label是一个可选的git标签(默认是master)。
Spring Cloud Config Server从git仓库为客户端拉取配置,如下:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
1.1 Client Side Usage(客户端用法)
要在一个应用中使用这些特性,你可以构建一个Spring Boot application并且添加spring-cloud-config-client相关的依赖,最方便的方法是添加org.springframework.cloud:spring-cloud-starter-config依赖。
下面是一个典型的maven配置:
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>{spring-boot-docs-version}</version>
<relativePath /> <!-- lookup parent from repository -->
</parent> <dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>{spring-cloud-version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement> <dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies> <build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
现在可以创建一个标准的Spring Boot application,如下:
@SpringBootApplication
@RestController
public class Application { @RequestMapping("/")
public String home() {
return "Hello World!";
} public static void main(String[] args) {
SpringApplication.run(Application.class, args);
} }
当这个HHTP服务启动时,它默认从本地的config server(端口8888)加载配置,可以使用bootstrap.properties配置来改变这个默认行为:
spring.cloud.config.uri: http://myconfigserver.com
可以使用/env端点来查看bootstrap properties配置:
$ curl localhost:8080/env
{
"profiles":[],
"configService:https://github.com/spring-cloud-samples/config-repo/bar.properties":{"foo":"bar"},
"servletContextInitParams":{},
"systemProperties":{...},
...
}
2. Spring Cloud Config Server(配置服务器的服务端)
Spring Cloud Config Server为外部配置提供一个基于资源的HTTP API。使用注解@EnableConfigServer可以在一个Spring Boot application中嵌入配置服务器。例如:
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
public static void main(String[] args) {
SpringApplication.run(ConfigServer.class, args);
}
}
最简单的方法是通过属性spring.config.name=configserver启动,因为在config server的jar中有一个configserver.yml配置文件,它已经设置好了默认的配置仓库。
或者你可以使用自己的配置:application.properties
server.port: 8888
spring.cloud.config.server.git.uri: file://${user.home}/config-repo
其中${user.home}/config-repo是一个包含YAML或者properties格式配置文件的git仓库。
注意:
1)在windows上,你需要在file url前多添加一个“/”,如果是绝对路径的话。(例如:file:///${user.home}/config-repo)
2)使用本地仓库只是为了演示和测试使用,在正式环境中需要使用一台服务器来管理配置
3)初始化克隆配合仓库在只有一个文件时可能比较快,但是如果存储一个二进制文件,特别是比较大的文件时,可能在第一次请求配置时有延迟甚至可能导致服务端内存溢出。
2.1 Environment Repository
在config server中我们应该将配置存储在什么地方?掌控这个行为的策略的就是为Environment对象服务的EnvironmentRepository。
Environment资源由一下三个变量参数化:
1){application} 对应客户端的spring.application.name
2){profile} 对应客户端的spring.profiles.active(以逗号分隔)
3){label} 它是服务器端功能标签“版本化”的配置文件集
Repository的实现通常像一个spring boot application,从一个和{application}相等的spring.config.name参数和与{profiles}相等的spring.profiles.active参数指定的文件来加载配置。
优先级策略和普通spring boot 的应用一样:Active profiles优先级比默认的高,如果有多个profiles,那么最后一个优先级最高。下面是客户端bootstrap 配置bootstrap.yml:
spring:
application:
name: foo
profiles:
active: dev,mysql
(和一般Spring Boot application一样,这些参数也可以在环境变量或者命令行参数中指定)
2.1.1 Git Backend
在config server中使用spring.cloud.config.server.git.uri来设置仓库位置,如果uri是以file:开头,则是本地仓库。
但是如果要扩展config server并且高可用的话,必须使所有服务器实例指向同一个仓库。因此需要一个共享的文件系统。在这种情况下,使用ssh协议是比较好的,这样服务器可以克隆一份配置到本地作为缓存使用。
仓库的实现是将HTTP路径中的{label}映射到一个git标签(commit id, branch name, or tag),如果一个git分支或者标签中包含“/”斜杠,那么在HTTP url中需要用一个特殊字符(_)来替代,以免发生混淆。
比如标签为foo/bar,则应该替换成:foo(_)bar。这个规则同样可应用到{application}参数上。
Skipping SSL Certificate Validation(跳过ssl验证)
spring:
cloud:
config:
server:
git:
uri: https://example.com/my/repo
skipSslValidation: true
Setting HTTP Connection Timeout(设置HTTP连接超时时间,以秒为单位)
spring:
cloud:
config:
server:
git:
uri: https://example.com/my/repo
timeout: 4
Placeholders in Git URI(git URI中的占位符)
Spring Cloud Config Server支持git URI中的占位符为:{application},{profile},{label}(记住label是作为git 的标签使用的)。通过下面的配置你可以支持每个应用一个仓库的策略:
spring:
cloud:
config:
server:
git:
uri: https://github.com/myorg/{application}
Pattern Matching and Multiple Repositories(规则匹配和多仓库)
Spring Cloud Config包含对application和profile名称的规则匹配支持,规则格式是包含通配符的以逗号分隔的{application}/{profile}名称。例如:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
repos:
simple: https://github.com/simple/config-repo
special:
pattern: special*/dev*,*special*/dev*
uri: https://github.com/special/config-repo
local:
pattern: local*
uri: file:/home/configsvc/config-repo
如果{application}/{profile}不匹配任何一个规则,则使用spring.cloud.config.server.git.uri下面的默认URI。在上面的例子中,匹配“simple”仓库的规则是simple/*({application}为simple,{profile}为任意值)。“local”仓库匹配任何一个以local开头的应用名称,如果没有指定{profile}规则,则会自动在规则后面添加“/*”。
由于pattern参数实际上是一个数组,所以使用YAML数组(或者在.properties文件中使用[0], [1]等后缀)来绑定多种规则。如下:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
repos:
development:
pattern:
- '*/development'
- '*/staging'
uri: https://github.com/development/config-repo
staging:
pattern:
- '*/qa'
- '*/production'
uri: https://github.com/staging/config-repo
每个仓库都可以在子目录中存储配置文件,如果要在子目录中搜索则需要使用searchPaths配置。例如:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
searchPaths: foo,bar*
在上面的例子中,服务器将会在顶级目录和foo子目录还有以bar开头的子目录中搜索配置文件。
默认情况下,服务器会在第一次收到配置请求时,克隆远程仓库。也可以在服务启动时克隆远程仓库,如下:
spring:
cloud:
config:
server:
git:
uri: https://git/common/config-repo.git
repos:
team-a:
pattern: team-a-*
cloneOnStart: true
uri: http://git/team-a/config-repo.git
team-b:
pattern: team-b-*
cloneOnStart: false
uri: http://git/team-b/config-repo.git
team-c:
pattern: team-c-*
uri: http://git/team-a/config-repo.git
在上面的例子中只有team-a的远程仓库会在启动时克隆,其他的都是在第一次接受到配置请求时才克隆。
Authentication(用户验证)
添加username和password属性来使用远程仓库基于HTTP的验证。例如:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
username: trolley
password: strongpassword
如果不使用HTTPS和用户凭证,也可以使用SHH,在默认目录下存储key(~/.ssh),并且URI指向一个SSH地址(例如:git@github.com:configuration/cloud-configuration)。
Git SSH configuration using properties(使用属性配置GIT SSH)
SSH配置可以使用java属性来解决,spring.cloud.config.server.git.ignoreLocalSshSettings值必须设置为true。例如:
spring:
cloud:
config:
server:
git:
uri: git@gitserver.com:team/repo1.git
ignoreLocalSshSettings: true
hostKey: someHostKey
hostKeyAlgorithm: ssh-rsa
privateKey: |
-----BEGIN RSA PRIVATE KEY-----
MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
+AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
-----END RSA PRIVATE KEY-----
其中hostKeyAlgorithm必须是ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, or ecdsa-sha2-nistp521中的一个。
Force pull in Git Repositories
如果本地copy已经失效(即远程仓库有改动),则Spring Cloud Config Server会强制从从远程库拉取最新的配置。如下:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
force-pull: true
如果有多个远程仓库的话,可以使用类似下面的配置:
spring:
cloud:
config:
server:
git:
uri: https://git/common/config-repo.git
force-pull: true
repos:
team-a:
pattern: team-a-*
uri: http://git/team-a/config-repo.git
force-pull: true
team-b:
pattern: team-b-*
uri: http://git/team-b/config-repo.git
force-pull: true
team-c:
pattern: team-c-*
uri: http://git/team-a/config-repo.git
force-pull属性默认是false。
Deleting untracked branches in Git Repositories(删除git仓库中未跟踪的分支)
因为Spring Cloud Config Server会克隆远程仓库到本地并且会一直保持这个分支知道下次重启,所以有一种情况是远程分支已经被删除,但是本地副本还仍然可用。
为了保证本地仓库分支和远程同步,需要设置deleteUntrackedBranches属性,它会使Spring Cloud Config Server强制删除本地未跟踪的分支。例如:
spring:
cloud:
config:
server:
git:
uri: https://github.com/spring-cloud-samples/config-repo
deleteUntrackedBranches: true
deleteUntrackedBranches默认值为false。
3. Spring Cloud Config Client(配置客户端)
3.1 Config First Bootstrap(启动时先读取config server配合)
在classpath中存在Spring Cloud Config Client的任何应用的默认行为如下:当一个config客户端启动时,它绑定到Config Server(通过bootstrap的配置属性spring.cloud.config.uri)然后使用远程配置文件初始化spring环境。
这种行为的最终结果是所有想要到 Config Server消费的客户端应用都需要一个配置有spring.cloud.config.uri(默认为:"http://localhost:8888")的bootstrap.yml或者环境变量。
3.2 Discovery First Bootstrap(使用服务发现寻找config server)
如果你正在使用服务发现框架例如Spring Cloud Netflix 和 Eureka Service Discovery 或者 Spring Cloud Consul,你可以把Config Server 注册到服务注册中心。
但是在默认的“Config First”模式下,客户端是感知不到注册中心中的config server服务的。如果你选择使用服务发现来定位Config Server,那么你需要在Config server中设置spring.cloud.config.discovery.enabled=true,
默认是false。这么做的话就需要每个客户端应用都要有一个bootstrap.yml或者环境变量来配置服务注册中心的内容。例如在Spring Cloud Netflix中,你需要配置Eureka server地址(eureka.client.serviceUrl.defaultZone),
这么做的代价是在启动时需要一个额外的网络往返来定位服务注册中心。好处是,只要注册中心是固定的,那么config server就可以随意改变坐标。默认的服务ID是configserver,但是可以通过spring.cloud.config.discovery.serviceId
来重新设置(但是通常是通过spring.application.name来设置一个服务ID)。
一般服务发现实现客户端都是支持某些元数据映射的(例如在Eureka中的eureka.instance.metadataMap)。为了让配置客户端能正确连接到config server需要在Config Server中配一些服务注册相关的元数据。
如果Config Server安全策略是基于HTTP的,你可以设置一些用户凭证像username,password。另外,如果Config Server有上下文路径,可以使用configPath设置。如下(bootstrap.yml):
eureka:
instance:
...
metadataMap:
user: osufhalskjrtl
password: lviuhlszvaorhvlo5847
configPath: /config
3.3 Config Client Fail Fast(快速失败响应)
在某些情况下,你可能希望服务在启动时如果连接config server失败时立刻响应失败而停止启动,可以设置spring.cloud.config.fail-fast=true。
3.4 Config Client Retry(配置客户端重试机制)
如果你觉得config server在你启动应用是不可达是暂时的或者偶然的,你需要在一次失败后接着重新尝试连接。第一步,设置spring.cloud.config.fail-fast=false。
接着将spring-retry和spring-boot-starter-aop加入到classpath中。默认行为是重试6次,初始间隔为1000ms,后续间隔乘以1.1。
可以通过设置spring.cloud.config.retry.*来改变默认行为。
注意:如果要完全控制重试机制,可以通过创建一个RetryOperationsInterceptor类型id为configServerRetryInterceptor的bean。
可以使用Spring Retry中的RetryInterceptorBuilder来创建。
3.5 Locating Remote Configuration Resources(定位远程配置资源)
配置服务提供/{name}/{profile}/{label}的属性源,其在客户端应用的映射为:
- "name" =
${spring.application.name}
- "profile" =
${spring.profiles.active}(其实是Environment.getActiveProfiles())
- "label" = "master"
可以使用spring.cloud.config.*来覆盖上面的默认值。
其中可以使用label属性回滚到以前的版本。在config server的实现中,label可以是git 标签,分支名或者commit ID。也可以是以逗号分隔的列表。在这种列表情况下,其中的元素会一个一个的被尝试,直到有一个成功。
3.6 Specifying Multiple Urls for the Config Server(指定多个config server url)
为了保证高可用,你可能部署多个config server,在客户端可以使用spring.cloud.config.uri,以逗号分隔指定多个URL,或者将config server的多个实例注册到服务注册中心,此时客户端需要使用之前提到的Discovery-First Bootstrap
模式(spring.cloud.config.discovery.enabled=true)。
如果Config Server使用的是HTTPS协议,则可以将用户凭证信息填写在每个config server 的 url上。如果使用其他的安全机制,则不支持为每个config server配置验证信息。
3.7 Configuring Read Timeouts(读取超时)
使用spring.cloud.config.request-read-timeout配置超时时间。
3.8 Security(安全机制)
如果config server使用的是HTTPS,则需要在url上指定用户名和密码,或者使用单独的username和password属性设置。如下(bootstrap.yml)
spring:
cloud:
config:
uri: https://user:secret@myconfig.mycompany.com
spring:
cloud:
config:
uri: https://myconfig.mycompany.com
username: user
password: secret
spring.cloud.config.password
和 spring.cloud.config.username会覆盖url中的用户名和密码。
好了,spring cloud config就先讲到这。下一篇就是spring cloud netflix。如果文章中写的有问题的希望各位读者批评指出。如果觉得在我这学到了点东西的,特别希望您能动动可爱的小手给点个赞!^_^
spring cloud连载第二篇之Spring Cloud Config的更多相关文章
- Spring Cloud实战 | 最终篇:Spring Cloud Gateway+Spring Security OAuth2集成统一认证授权平台下实现注销使JWT失效方案
一. 前言 在上一篇文章介绍 youlai-mall 项目中,通过整合Spring Cloud Gateway.Spring Security OAuth2.JWT等技术实现了微服务下统一认证授权平台 ...
- Spring Cloud实战 | 第九篇:Spring Cloud整合Spring Security OAuth2认证服务器统一认证自定义异常处理
本文完整代码下载点击 一. 前言 相信了解过我或者看过我之前的系列文章应该多少知道点我写这些文章包括创建 有来商城youlai-mall 这个项目的目的,想给那些真的想提升自己或者迷茫的人(包括自己- ...
- spring cloud连载第一篇之bootstrap context
1. Spring Cloud Context: Application Context Services(应用上下文服务) 1.1 The Bootstrap Application Context ...
- Spring Cloud第十篇 | 分布式配置中心Config
本文是Spring Cloud专栏的第十篇文章,了解前九篇文章内容有助于更好的理解本文: Spring Cloud第一篇 | Spring Cloud前言及其常用组件介绍概览 Spring Clo ...
- Spring之旅第二篇-Spring IOC概念及原理分析
一.IOC概念 上一篇已经了解了spring的相关概念,并且创建了一个Spring项目.spring中有最重要的两个概念:IOC和AOP,我们先从IOC入手. IOC全称Inversion of Co ...
- 【原】Spring整合Redis(第二篇)—SDR环境搭建具体步骤
[环境参数] Spring版本:4.2.6.RELEASESpring-Data-Redis版本:1.7.2.RELEASE Redis版本:redis-2.4.5-win32-win64 [简要说明 ...
- (转) SpringBoot非官方教程 | 第二篇:Spring Boot配置文件详解
springboot采纳了建立生产就绪spring应用程序的观点. Spring Boot优先于配置的惯例,旨在让您尽快启动和运行.在一般情况下,我们不需要做太多的配置就能够让spring boot正 ...
- SpringBoot非官方教程 | 第二篇:Spring Boot配置文件详解
转载请标明出处: 原文首发于:https://www.fangzhipeng.com/springboot/2017/07/11/springboot2-config-file/ 本文出自方志朋的博客 ...
- spring boot 学习入门篇【spring boot项目的搭建以及如何加载jsp界面】
[ 前言] Spring Boot 简介:Spring Boot是由Pivotal团队提供的全新框架,其设计目的是用来简化新Spring应用的初始搭建以及开发过程.该框架使用了特定的方式来进行配置, ...
随机推荐
- 构建命令maven install 打包不是最新的代码
问题: 之前一直用的是mvn install 命令来构建项目,但是最近发现最新的代码没有在war包中.之前看的说 mvn install 命令会执行之前的所有阶段,会被编译,测试,打包. 经查最后采用 ...
- 记那些年在asp.net mvc上挖过的坑
表现: IDE是vs2017.是在 A 控制器方法断点后,却怎么也运行不到那个位置,但是又正常返回页面.该方法位于web项目引用的控制器类库上的一个控制器,试过它隔壁的控制器,一切正常. 但每次访问该 ...
- c#设计模式之代理模式(Proxy Pattern)
引言 代理这个词语,大家在现实世界已经频繁的接触过,例如火车站代理售票点,因为这些代理售票点的存在,我们不必要去火车站的售票处就可以查询或者取到火车票.代理点本身是没有能力生产车票的,我们在代理处享受 ...
- php 命令行脚本运行php文件简单演示
众说周知,php在web服务器领域有着很重要的角色,可是它不仅仅在web领域,只是在web领域表现更为优秀! 它基本有三种用途: web服务端脚本的编写 应用程序图形界面(类似windows自带的计算 ...
- php实现循环链表
<?php /** * php实现链表 * Date: 2018/5/18 * Time: 下午5:59 */ class Node { public $nodeId = 0; public $ ...
- 微信小程序如何转换成分与秒
- CentOS7.x安装时的分区方案
-------------------------------------------------分区方案描述--------------------------------------------- ...
- linux中rc.d目录下的文件
参考 http://blog.sina.com.cn/s/blog_414d78870102vqj5.html http://www.360doc.com/content/12/0820/17/933 ...
- XMPPFramework核心类介绍
XMPPFramework结构 在进入下一步之前,先给大家讲讲XMPPFramework的目录结构,以便新手们更容易读懂文章.我们来看看下图: 虽然这里有很多个目录,但是我们在开发中基本只关心Core ...
- 编程开发之--java多线程学习总结(3)类锁
2.使用方法同步 package com.lfy.ThreadsSynchronize; /** * 1.使用同步方法 * 语法:即用 synchronized 关键字修饰方法(注意是在1个对象中用锁 ...