要想全面快速学习Spring的内容,最好的方法肯定是先去Spring官网去查阅文档,在Spring官网中找到了适合新手了解的官网Guides,一共68篇,打算全部过一遍,能尽量全面的了解Spring框架的每个特性和功能。
接着上篇看过的guide31,接着往下看。
guide31、Observability with Spring
主要讲的是通过waveFront去直观查看spring应用程序的运行情况。
将 Micrometer 指标发布到 Tanzu Observability by Wavefront ,这是一个基于 SaaS
的指标监控和分析平台,可让您对整个堆栈中的数据进行可视化、查询和警报
引入对应的依赖,
<dependency>
<groupId>com.wavefront</groupId>
<artifactId>wavefront-spring-boot-starter</artifactId>
<scope>runtime</scope>
</dependency>
添加配置文件:
management.wavefront.application.name=demo
management.wavefront.application.service-name=getting-started
启动程序,显示:
guide中的运行显示图:
guide32、accessing vault
Vault 是 hashicorp 推出的 secrets 管理、加密即服务与权限管理工具。 vault官网:
https://developer.hashicorp.com/vault/docs/internals/architecture
先下载并启动vault:
--下载
brew install vault
--启动
vault server --dev --dev-root-token-id="00000000-0000-0000-0000-000000000000"
然后进行配置, 使用 Vault 命令行启动另一个控制台窗口:
--将应用程序配置存储在 Vault 中
export export VAULT_TOKEN="00000000-0000-0000-0000-000000000000"
export VAULT_ADDR="http://127.0.0.1:8200"
--配置键值对:
vault kv put secret/github github.oauth2.key=foobar
spring boot项目中配置application.properties:
spring.cloud.vault.token=00000000-0000-0000-0000-000000000000
spring.cloud.vault.scheme=http
Application 类启动文件:
@SpringBootApplication
public class Application implements CommandLineRunner {
@Autowired
private VaultTemplate vaultTemplate;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Override
public void run(String... strings) throws Exception {
VaultResponse response = vaultTemplate
.opsForKeyValue("secret", KeyValueBackend.KV_2).get("github");
System.out.println("Value of github.oauth2.key");
System.out.println("-------------------------------");
System.out.println(response.getData().get("github.oauth2.key"));
System.out.println("-------------------------------");
System.out.println();
// 使用Transit后端加密一些数据。
VaultTransitOperations transitOperations = vaultTemplate.opsForTransit();
// 首先需要设置传输(如果还没有设置它)。
VaultSysOperations sysOperations = vaultTemplate.opsForSys();
if (!sysOperations.getMounts().containsKey("transit/")) {
sysOperations.mount("transit", VaultMount.create("transit"));
transitOperations.createKey("foo-key");
}
// 加密明文值
String ciphertext = transitOperations.encrypt("foo-key", "Secure message");
System.out.println("Encrypted value");
System.out.println("-------------------------------");
System.out.println(ciphertext);
System.out.println("-------------------------------");
System.out.println();
// 解密
String plaintext = transitOperations.decrypt("foo-key", ciphertext);
System.out.println("Decrypted value");
System.out.println("-------------------------------");
System.out.println(plaintext);
System.out.println("-------------------------------");
System.out.println();
}
}
启动后显示:
guide33、Accessing Data Reactively with Redis
主要讲的是用响应式编程去和redis交互。
创建一个实体类:
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Coffee {
private String id;
private String name;
}
再创建一个支持反应式Redis操作的bean类:
@Configuration
public class CoffeeConfiguration {
@Bean
ReactiveRedisOperations<String, Coffee> redisOperations(ReactiveRedisConnectionFactory factory) {
Jackson2JsonRedisSerializer<Coffee> serializer = new Jackson2JsonRedisSerializer<>(Coffee.class);
RedisSerializationContext.RedisSerializationContextBuilder<String, Coffee> builder =
RedisSerializationContext.newSerializationContext(new StringRedisSerializer());
RedisSerializationContext<String, Coffee> context = builder.value(serializer).build();
return new ReactiveRedisTemplate<>(factory, context);
}
}
再创建一个bean来在程序启动时加载示例数据:
@Component
public class CoffeeLoader {
private final ReactiveRedisConnectionFactory factory;
private final ReactiveRedisOperations<String, Coffee> coffeeOps;
public CoffeeLoader(ReactiveRedisConnectionFactory factory, ReactiveRedisOperations<String, Coffee> coffeeOps) {
this.factory = factory;
this.coffeeOps = coffeeOps;
}
@PostConstruct
public void loadData() {
factory.getReactiveConnection().serverCommands().flushAll().thenMany(
Flux.just("Jet Black Redis", "Darth Redis", "Black Alert Redis")
.map(name -> new Coffee(UUID.randomUUID().toString(), name))
.flatMap(coffee -> coffeeOps.opsForValue().set(coffee.getId(), coffee)))
.thenMany(coffeeOps.keys("*")
.flatMap(coffeeOps.opsForValue()::get))
.subscribe(System.out::println);
}
}
@PostConstruct:@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
通常是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)
再创建一个接口类,去提供对外接口:
@RestController
public class CoffeeController {
private final ReactiveRedisOperations<String, Coffee> coffeeOps;
CoffeeController(ReactiveRedisOperations<String, Coffee> coffeeOps) {
this.coffeeOps = coffeeOps;
}
@GetMapping("/coffees")
public Flux<Coffee> all() {
return coffeeOps.keys("*")
.flatMap(coffeeOps.opsForValue()::get);
}
}
然后直接启动应用,可以看到结果:
guide34、 Accessing data with Cassandra
Apache Cassandra是一个高度可扩展的高性能分布式数据库,用于处理大量商用服务器上的大量数据,提供高可用性,无单点故障。这是一种NoSQL类型的数据库。
使用的是DataStax Astra DB Cassandra-as-a-Service,这个服务可以在Cassandra数据库内创建和使用数据。
不过需要配置很多的参数:
-- 配置 Spring Data Cassandra
spring.cassandra.schema-action=CREATE_IF_NOT_EXISTS
spring.cassandra.request.timeout=10s
spring.cassandra.connection.connect-timeout=10s
spring.cassandra.connection.init-query-timeout=10s
#spring.cassandra.local-datacenter=datacenter1
#spring.cassandra.keyspace-name=spring_cassandra
--Astra 自动配置需要配置信息才能连接到云数据库
# Credentials to Astra DB
astra.client-id=<CLIENT_ID>
astra.client-secret=<CLIENT_SECRET>
astra.application-token=<APP_TOKEN>
# Select an Astra instance
astra.cloud-region=<DB_REGION>
astra.database-id=<DB_ID>
astra.keyspace=spring_cassandra
我这边没有申请这些Astra的账户密码。
后续的demo中,创建一个实体类,然后使用spring data Cassandra 去进行数据的存储与查找,它继承了 Spring Data Commons 项目的功能,包括派生查询的能力。
public interface VetRepository extends CrudRepository<Vet, UUID> {
Vet findByFirstName(String username);
}
@SpringBootApplication
public class AccessingDataCassandraApplication {
public static void main(String[] args) {
SpringApplication.run(AccessingDataCassandraApplication.class, args);
}
@Bean
public CommandLineRunner clr(VetRepository vetRepository) {
return args -> {
vetRepository.deleteAll();
Vet john = new Vet(UUID.randomUUID(), "John", "Doe", new HashSet<>(Arrays.asList("surgery")));
Vet jane = new Vet(UUID.randomUUID(), "Jane", "Doe", new HashSet<>(Arrays.asList("radiology, surgery")));
Vet savedJohn = vetRepository.save(john);
Vet savedJane = vetRepository.save(jane);
vetRepository.findAll()
.forEach(v -> log.info("Vet: {}", v.getFirstName()));
vetRepository.findById(savedJohn.getId())
.ifPresent(v -> log.info("Vet by id: {}", v.getFirstName()));
};
}
}
使用起来和之前的Spring Data JPA、Spring Data Gemfire和Spring Data Neo4j类似。
中期回顾和小结
总体来说,每个guide涉及到一个spring的点,由于一篇guide中尽量不去涉及到其他内容,所以整体guide内容比较浅显, 一般只展示了其基本使用。
1、写一个简单的controller, 可以接受请求。
2、用RestTemplate去发送http请求。
3、用maven去构建java项目。
4、上传文件,核心内容是java.nio.file.Path类和java.nio.file.Files类,利用Files.copy(InputStream in, Path target, CopyOption… options)进行文件复制。
5、利用redis进行消息的发送和接收,虽然项目中一般使用redis作数据存储。在消息系统中,有消息的发布者和消息接收者,用StringRedisTemplate去发送消息,再定义一个消息监听容器(定义用到RedisConnectionFactory)。
7、讲了Spring Boot Actuator,是Spring Boot提供用于对应用系统进行自省和监控的功能模块。集成也比较简单,添加依赖即可。
8、guide里通过xml配置用srping integration创建了一个流服务, 也是分为输入适配器、处理通道、输出适配器等组件。未深入了解和掌握。
9、了解了spring batch,一个轻量级的批处理框架。包含的基本组件如下图
10、spring HATEOAS: 一个api库,可以使用它创建指向Spring MVC控制器的链接,其实就是响应中包含指向其它资源的链接,客户端可以利用这些链接和服务器交互。可以扩展了解下rest成熟度模型,第四层次就是HATEOAS。
11、讲了非侵入式事务 @Transactional注解的使用。
13、讲了jar包和war包,了解了二者的区别。
14、前端提交表单,后端进行处理。
15、使用websocket在浏览器和服务端之间发送消息,guide里用的是stomp协议。guide里展示的比较简单,和传统controller相比,服务端映射注解变成了@messageMapping,发送注解使用@SendTo。浏览器js里使用SockJs和stomp.js去创建socket链接和发请求。
16、编写一个简单的angularJS客户端,没有多了解。
17、了解了跨域,以及@CrossOrigin注解,是用来处理跨源资源共享(CORS)的注解。
20、基于WSDL去创建一个SOAP服务,只知道了概念,未深入了解。
21、讲了用STS的spring boot dashboard,把一个简单的web应用程序,部署到cloud Foundry的操作步骤。
22、用Vaadin去写CURD的UI页面,Vaadin类似于以前的java swing。
23、使用spring cloud config构建轻量级配置中心。基本工作原理图:
24、讲了怎么连接mysql去操作数据。
25、用spring rest docs为API生成文档,不过要和单元测试结合使用。
26、构建了一个简单的响应式编程服务。这个和传统的web服务地址路由和处理请求的方式不同,后续可以深入了解下。
27、在项目里加上一个简单的spring cloud gateway,其中gateway核心概念是route(路由)、predictae(预言)、filter(过滤器)这三个。
28、只简单介绍了spring cloud stream的概念,也就是source(来源),process(处理器)、sink(接收器)。
29、用spring cloud task构建短期的spring boot服务。
31、通过waveFront去查看应用的运行情况。
32、介绍了可以用来sercet管理加密的vault怎么去使用的。
33、使用spring data redis进行响应式编程,没看太懂,响应式代码编程这块都没有掌握,只了解了表面概念。
6、12、18、19、30、34:
这几个guide讲的东西大同小异,都基本是从某个地方获取数据,在spring data中repository类的基础上,进行各种数据存储与操作。
6 是从基于图形的数据库neo4j中获取数据,实体类查询接口扩展了Neo4jRepository接口类;
12 是从基于文档的数据库MongoDB中获取数据,实体类查询接口继承继承了MongoRepository接类;
18 使用 Spring Data REST 创建和检索存储在JPA中的数据;
19 使用 Spring Data REST 创建和检索存储在MongoDB中的数据;Spring Data REST 还支持Spring Data JPA、Spring Data Gemfire和Spring Data Neo4j作为后端数据存储。
30 是使用Spring提供的数据库响应式编程框架R2DBC去处理数据,实体类查询接口扩展ReactiveCrudRepository接口;
34 是从基于分布式的nosql数据库Cassandra中获取数据,然后进行数据的存储及处理。
上述多个guide中涉及到docker, 响应式编程,还未进行深入了解,后续会再看看这些。