redis devops(二) springboot 2.4.2 集成r2dbc

Spring boot 开发

本节内容的版本声明:

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
        <spring.cloud-version>2020.0.1</spring.cloud-version>
        <spring.boot-version>2.4.2</spring.boot-version>
        <spring.cloud-alibaba-version>2021.1</spring.cloud-alibaba-version>
        <kotlin.version>1.4.31</kotlin.version>
        <kotlin.compiler.jvmTarget>1.8</kotlin.compiler.jvmTarget>
        <kotlin.compiler.incremental>true</kotlin.compiler.incremental>
    </properties>

引入依赖

	<dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-data-redis-reactive</artifactId>
    </dependency>

官网有2个redis,一个是reactive的,一个不是。我这只讲reactive的。
引入的依赖结构:
spring-boot-starter-data-redis-reactivespring-boot-starter-data-redis-reactive-2.4.2
查看spring-boot-autoconfigure:2.4.2的自动配置中关于redis

org.springframework.boot.autoconfigure.data.redis.RedisAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisReactiveAutoConfiguration,\
org.springframework.boot.autoconfigure.data.redis.RedisRepositoriesAutoConfiguration,\

看源码讲起来就比较复杂了,简单说一下关键项
RedisAutoConfiguration下@EnableConfigurationProperties(RedisProperties.class)可以看见配置类是RedisProperties
RedisProperties上看见@ConfigurationProperties(prefix = “spring.redis”)所以配置怎么写就在了。里面有个静态类Cluster,静态类下面属性就是集群配置。

最简配置如下:

对应redis devops(一)的配置

spring:
  redis:
    cluster:
      nodes:
        - ip:端口
        - ip:端口
        - ip:端口
        - ip:端口
        - ip:端口
        - ip:端口
    port: 端口
    password: 密码

开发中有用json序列化器,就配一个序列化器。
工具类,我之前有发过一篇。

关键是,引入之后R2dbc的Repository注入会失败。

申明一下spring boot版本2.4.2

错误类型: NoSuchBeanDefinitionException 一个找不到BeanDefinition的错误,很常见!
具体描述是(隐去一些项目信息)

Parameter 0 of constructor in XXService required a bean of type 'XXRepository' that could not be found.

The injection point has the following annotations:
	- @org.springframework.beans.factory.annotation.Autowired(required=true)


Action:

Consider defining a bean of type 'XXRepository' in your configuration.

提示BeanDefinition,把端口打在 DefaultListableBeanFactory 1343行代码(截图已解决了,machingBeans size = 1),用条件断点

第1个打断点
步过1次,machingBeans size = 0,用评估器确认一下
异常
确定了是BeanDefinition没有被ioc容器收集。
r2dbc Repository 从接口到实现类,用的jdk动态代理。去除redis依赖可以验证一下:

依赖注入打印实例:
org.springframework.data.r2dbc.repository.support.SimpleR2dbcRepository@d6e361b3
打印java class:
class com.sun.proxy.$Proxy123
依赖查找打印实例:
org.springframework.data.r2dbc.repository.support.SimpleR2dbcRepository@d6e361b3

从SimpleR2dbcRepository可以推测R2dbc的实现基本就是jpaRepository类似

从@EnableR2dbcRepositories 的@Import(R2dbcRepositoriesRegistrar.class) 进入

找到RepositoryBeanDefinitionRegistrarSupport#registerBeanDefinitions 断点打在 104 行 new RepositoryConfigurationDelegate这。RepositoryConfigurationDelegate 是实际注册Repository BeanDefinitions的类,这个类主要的注册实现是registerRepositoriesIn方法。
单步调试这个方法,会发现 148 行 返回的configurations长度为0。项目中应有4个,跳转到RepositoryConfigurationExtensionSupport#getRepositoryConfigurations 中。
发现返回result :HashSet没有内容。2个add方法都跳过了!

//98行
			if (repositoryInterface == null) {
				result.add(configuration);
				continue;
			}
//108行
			if (qualifiedForImplementation && useRepositoryConfiguration(metadata)) {
				result.add(configuration);
			}
			

第一个repositoryInterface 明显不为空,任务就落在第二个if,其中qualifiedForImplementation 很关键

//105行
			boolean qualifiedForImplementation = !strictMatchesOnly || configSource.usesExplicitFilters()
					|| isStrictRepositoryCandidate(metadata);

通过去除依赖,发现 !strictMatchesOnly = true 所以qualifiedForImplementation = true 所以add。
引入redis依赖之后!strictMatchesOnly = false。
strictMatchesOnly 是参数传入,来源RepositoryConfigurationDelegate#inMultiStoreMode,赋值唯一的是构造函数时调用了RepositoryConfigurationDelegate#multipleStoresDetected。函数中对RepositoryFactorySupport.class进行计数,返回是否有多个RepositoryFactorySupport的支持。
通过idea看到引入后的支持
多个Repository的支持
看到这,大家都会以为有冲突,我们排除一下依赖

@SpringBootApplication(exclude = [RedisRepositoriesAutoConfiguration::class])

或者配置一下

spring:
  data:
    redis:
      repositories:
        enabled: false

现实很残酷,以上做法都不会改变RepositoryConfigurationDelegate#multipleStoresDetected函数的返回结果。所以,到qualifiedForImplementation 的值依然是false。
回到qualifiedForImplementation 值判断上第二个参数configSource.usesExplicitFilters(),看一下走到RepositoryConfigurationSource接口,实现类是我们是注解启动,源码:

@Override
	public boolean usesExplicitFilters() {
		return hasExplicitFilters;
	}

给AnnotationRepositoryConfigurationSource#hasExplicitFilters 打上检测断点(直接看代码也可以发现),这个属性值依赖

private static boolean hasExplicitFilters(AnnotationAttributes attributes) {

		return Stream.of("includeFilters", "excludeFilters") //
				.anyMatch(it -> attributes.getAnnotationArray(it).length > 0);
	}

也就是我们需要在@EnableR2dbcRepositories 配置includeFilters 或者excludeFilters 可以改变 configSource.usesExplicitFilters()的值从而改变qualifiedForImplementation 从而让BeanDefinition 添加到ioc容器管理。

附:以上顺便解释为什么配置basePackages也不能注入

解决方法

需要配置 @EnableR2dbcRepositories 的 includeFilters 或者 excludeFilters 属性。
Filter[] 数组,是一个注解数组,有很多方式实现,具体不讲解,就讲一下我的实现。
自定义一个注解 R2dbcRepository

//kotlin 版本的注解 用java的自己写
@Target(AnnotationTarget.CLASS)
@kotlin.annotation.Retention(AnnotationRetention.RUNTIME)
@MustBeDocumented
annotation class R2dbcRepository()

然后在@EnableR2dbcRepositories配置

//kotlin 版本 用java的自己写
@EnableR2dbcRepositories(
    basePackages = ["com.xxx.xxx.repository"],
    includeFilters = [ComponentScan.Filter(type = FilterType.ANNOTATION, classes = [R2dbcRepository::class])])

找一个Component打上就可以了。

C++ 开发

留空,暂时还不会,会了再来补。

业务逻辑

无非是一些缓存,token等应用场景,主要是分布式后,相同微服务一些的状态同步,锁,计时器都可以找redis。具体到公司业务,不能说。大家可以去看一些教学视频,想到什么能说,以后发出来,这里也留个坑。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值