启动工程,请执行
cd projects/stage-0/user-platform
mvn clean package
java -jar user-web/target/user-web-v1-SNAPSHOT-war-exec.jar
#启动工程
cd projects/stage-0/user-platform
mvn clean package
java -jar user-web/target/user-web-v1-SNAPSHOT-war-exec.jar
#启动工程,并且设置环境变量
java -jar -Dapplication.name=java-user-web user-web/target/user-web-v1-SNAPSHOT-war-exec.jar
文件环境变量
user-web/src/main/resources/META-INF/application.properties
查看MBean
http://127.0.0.1:8080/jolokia/read/org.geektimes.projects.user.management:type=User
获取配置的测试在TestingListener类里面
cd projects/stage-0/user-platform
mvn clean package
java -jar user-web/target/user-web-v1-SNAPSHOT-war-exec.jar
需要先启动activemq
修复本程序 org.geektimes.reactive.streams 包下
已完成
继续完善 my-rest-client POST 方法
已完成
cd projects/stage-0/user-platform
mvn clean package
java -jar user-web/target/user-web-v1-SNAPSHOT-war-exec.jar
org.geektimes.rest.demo.RestClientDemo.testPostWithEmptyBody
方法测试类
org.geektimes.cache.CachingTest#testSampleRedis
org.geektimes.cache.CachingTest#testSampleRedisWithPojo
序列化实现,实现了String和JSON,Object3种方式
如何清除某个 Spring Cache 所有的 Keys 关联的对象
如果 Redis 中心化方案,Redis + Sentinel
如果 Redis 去中心化方案,Redis Cluster
org.geektimes.projects.user.web.spring.cache.RedisCacheConfigurationDemo
@Bean(name = "customCacheManager")
public RedisCacheManager cacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager("redis://127.0.0.1:6379/");
return redisCacheManager;
}
在@Cacheable中配置自定义的CacheManager
@Cacheable(value = "test",key = "#ttt", cacheManager = "customCacheManager")
这样就实现了RedisCacheManager 与 @Cacheable 注解打通
Redis Cluster去中心划方案
@Bean(name = "redisClusterCacheManager")
public RedisClusterCacheManager redisClusterCacheManager() {
RedisClusterCacheManager redisCacheManager = new RedisClusterCacheManager("redis://192.168.10.100:6379/;redis://192.168.10.101:6379/");
return redisCacheManager;
}
@Bean(name = "redisSentinelCacheManager")
public RedisSentinelCacheManager redisSentinelCacheManager() {
RedisSentinelCacheManager redisCacheManager = new RedisSentinelCacheManager("mymaster", "192.168.10.100:6379;192.168.10.101:6379");
return redisCacheManager;
}
完善@org.geektimes.projects.user.mybatis.annotation.EnableMyBatis 实现,尽可能多地注入org.mybatis.spring.SqlSessionFactoryBean 中依赖的组件
测试入口类
org.geektimes.projects.user.mybatis.annotation.EnableMyBatisExample
完善这几个组件
properties = "META-INF/mybatis/mybatis.properties",
typeAliases = {User.class},
typeHandlers = {EmailTypeHandler.class}
plugins = {MyInterceptor.class}
启动时需要配置数据库密码
@Bean
public DataSource dataSource() {
BasicDataSource dataSource = new BasicDataSource();
dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/test");
dataSource.setUsername("root");
dataSource.setPassword("12345678");
return dataSource;
}
CREATE TABLE users
(
id INT NOT NULL PRIMARY KEY auto_increment,
name VARCHAR(16) NOT NULL,
password VARCHAR(64) NOT NULL,
email VARCHAR(64) NOT NULL,
phoneNumber VARCHAR(64) NOT NULL
);
INSERT INTO users(name, password, email, phoneNumber)
VALUES ('A', '******', 'a@gmail.com', '1'),
('B', '******', 'b@gmail.com', '2'),
('C', '******', 'c@gmail.com', '3'),
('D', '******', 'd@gmail.com', '4'),
('E', '******', 'e@gmail.com', '5');
通过 Java 实现两种(以及)更多的一致性 Hash 算法
(可选)实现服务节点动态更新
一致性Hash是为了解决Hash节点更新时,尽量少的变更节点上的数据内容。
方式1:不带虚拟节点的Hash算法
org.geektimes.projects.user.dubbo.ConsistentHashingWithoutVirtualNode
方式2:带虚拟节点的Hash算法
org.geektimes.projects.user.dubbo.ConsistentHashingWithVirtualNode
将上次 MyBatis @Enable 模块驱动,封装成 Spring Boot Starter ⽅式
创建一个新的工程mybatis-spring-starter
创建引导文件 META-INF/spring.factories
,内容如下
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.geektimes.projects.mybatis.autoconfiguration.MybatisAutoConfiguration
新建自动装配类MybatisAutoConfiguration
,完成自动装配sqlSessionFactory
在user-web
工程下新增application.yml
文件,内容如下:
mybatis:
enabled: true #是否启用开关
config-location: META-INF/mybatis/mybatis-config.xml
data-source: dataSource
mapper-locations: META-INF/mybatis/mappers/**/*.xml
properties: META-INF/mybatis/mybatis.properties
type-aliases: EmailTypeHandler.class
type-handlers: User.class
修改测试类 org.geektimes.projects.user.mybatis.EnableMyBatisExample
,使用SpringBootApplication方式启动。执行main方法,输出查询结果,结果正确,说明starter已经成功。
User{id=1, name='A', password='******', email='a@gmail.com', phoneNumber='null'}
User{id=2, name='B', password='******', email='b@gmail.com', phoneNumber='null'}
User{id=3, name='C', password='******', email='c@gmail.com', phoneNumber='null'}
User{id=4, name='D', password='******', email='d@gmail.com', phoneNumber='null'}
User{id=5, name='E', password='******', email='e@gmail.com', phoneNumber='null'}
基于文件系统为 Spring Cloud 提供 PropertySourceLocator实现
配置文件命名规则(META-INF/config/default.properties或者 META-INF/config/default.yaml)
可选:实现文件修改通知
在pom.xml
中增加如下的依赖(Spring Cloud 2020.1必须增加,之前的版本不需要,坑点!)
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
</dependency>
实现 PropertySourceLocator -> org.geektimes.projects.spring.cloud.config.client.FileSystemPropertySourceLocator
读取配置文件目录 META-INF/config/
,根据profile找到对应的配置文件,可以是properties的,也可以是yaml的,构建PropertySource
注入测试类 ConfigClient
@Value("${user.name}")
private String userName;
@Value("${user.age}")
private int userAge;
@Bean
public ApplicationRunner runner() {
return args -> System.out.printf("user.name = %s, user.age = %d, foo = %s %n", myName, myAge, foo);
}
实现文件修改通知。利用Java类 WatchService
实现文件监听类org.geektimes.projects.spring.cloud.config.client.FileSystemPropertySourceLocator.FileWatch
,目前只实现到监听文件变化了,暂时未实现配置刷新。
启动方式
利用 Redis 实现 Spring Cloud Bus 中的 BusBridge,避免强依赖于 Spring Cloud Stream
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-bus</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-stream</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.integration</groupId>
<artifactId>spring-integration-redis</artifactId>
<version>5.4.2</version>
</dependency>
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.15.5</version>
</dependency>
<dependency>
<groupId>io.lettuce</groupId>
<artifactId>lettuce-core</artifactId>
</dependency>
BusBridge
public class RedisBusBridge implements BusBridge {
private final RedisBridge redisBridge;
private final BusProperties properties;
public RedisBusBridge(RedisBridge redisBridge, BusProperties properties) {
this.redisBridge = redisBridge;
this.properties = properties;
}
public void send(RemoteApplicationEvent event) {
this.redisBridge.send(properties.getDestination(), MessageBuilder.withPayload(event).build());
}
}
RedisBridge
代替StreamBridge
public class RedisBridge implements SmartInitializingSingleton {
}
org.geektimes.projects.spring.cloud.stream.binder.redis.RedisMessageChannelBinder
发送方
MessageChannel messageChannel = new SubscribableRedisChannel(redisConnectionFactory, "springCloudBus");
GenericMessage<String> message = new GenericMessage("Hello,World");
messageChannel.send(message);
System.out.println("send message=" + message.getPayload());
接收方
@Bean
public Consumer<String> message() {
return message -> {
System.out.println("Consumer 消息内容:" + message);
};
}
配置文件 application.yml
spring:
application:
name: spring-cloud-service-consumer
cloud:
stream:
bindings:
springCloudBusInput:
destination: springCloudBus
group: foo
但是目前就只到这里了。。。启动后,能够看到redis里面有队列,但是发送数据不成功。。。
自定义的RedisBusBridge没有生效。
接收方从日志能发现有订阅Redis,但是没有消息。。。
只能交个半成品。。。
通过 GraalVM 将一个简单 Spring Boot 工程构建为 Native
Image,要求:
@RequestMapping("/helloworld")
相关插件可以参考 Spring Native Samples
(可选)理解 Hint 注解的使用
项目 spring-native
环境准备
执行打包命令
mvn package -Pnative
报错:
[ERROR] Failed to execute goal org.graalvm.nativeimage:native-image-maven-plugin:21.0.0.2:native-image (default) on project demo-spring-native: Could not find executable native-image in D:\software\graalvm-ce-java11-21.1.0\jre\lib\svm\bin\native-image.exe -> [Help 1]
缺少native-image.exe?这个执行文件是哪里来的呢?
请安装组件 gu install native-image
启动 target/com.example.springnative.springnativeapplication.exe
访问 http://localhost:8080
,页面显示hello
.完成
将 Spring Boot 应用打包 Java Native 应用,再将该应用通过 Dockerfile
构建 Docker 镜像,部署到 Docker 容器中,并且成功运行,Spring Boot 应用的实现复杂度不做要求
在上次的项目中增加 Dockerfile
FROM centos:centos7
#安装maven
RUN mkdir /usr/local/maven
WORKDIR /usr/local/maven/
#从本地复制maven到容器,ADD命令会自动解压
ADD apache-maven-3.8.1-bin.tar.gz /usr/local/maven/
#设置MAVEN_HOME
ENV MAVEN_HOME=/usr/local/maven/apache-maven-3.8.1/
#安装graalvm
RUN mkdir /usr/local/graalvm
#从本地复制graalvm及native-image到容器
ADD graalvm-ce-java11-linux-amd64-21.1.0.tar.gz /usr/local/graalvm/
ADD native-image-installable-svm-java11-linux-amd64-21.1.0.jar /usr/local/graalvm/
WORKDIR /usr/local/graalvm/
#设置JAVA_HOME
ENV JAVA_HOME=/usr/local/graalvm/graalvm-ce-java11-21.1.0/
#设置PATH
ENV PATH=${JAVA_HOME}/bin:${MAVEN_HOME}/bin:$PATH
#安装native-image
RUN gu install -L /usr/local/graalvm/native-image-installable-svm-java11-linux-amd64-21.1.0.jar
#安装native-iamge运行时依赖gcc等环境
RUN yum -y install gcc glibc-devel zlib-devel libstdc++-static
#从gitee拉取代码并构建native-image
RUN yum -y install git
WORKDIR /usr/local/
RUN git clone https://gitee.com/karidyang/geekbang-lessons-v1.git
WORKDIR /usr/local/geekbang-lessons-v1/
WORKDIR /usr/local/geekbang-lessons-v1/projects/stage-0/spring-native
RUN mvn -Pnative clean package -Dmaven.test.skip=true
EXPOSE 8080
CMD /usr/local/geekbang-lessons-v1/projects/stage-0/spring-native/target/
执行创建镜像
docker build -t spring-native:v1 .
启动容器
docker run -d -it -p 8080:8080 spring-native
访问 http://localhost:8080/helloworld
注意:
需要将3个本地拷贝到库放到项目文件下
apache-maven-3.8.1-bin.tar.gz
graalvm-ce-java11-linux-amd64-21.1.0.tar.gz
native-image-installable-svm-java11-linux-amd64-21.1.0.jar
下载地址
此处可能存在不合适展示的内容,页面不予展示。您可通过相关编辑功能自查并修改。
如您确认内容无涉及 不当用语 / 纯广告导流 / 暴力 / 低俗色情 / 侵权 / 盗版 / 虚假 / 无价值内容或违法国家有关法律法规的内容,可点击提交进行申诉,我们将尽快为您处理。