当前位置:   article > 正文

SpringBoot源码分析(二)之自动装配demo_required a bean of type 'org.redisson.api.redisson

required a bean of type 'org.redisson.api.redissonclient' that could not be

SpringBoot源码分析(二)之自动装配demo


前言

Spring Framework一致在解决如何让bean的管理更加简单,如何让开发者尽可能少的去管理bean生成的一些配置;当我们在引用其他模块中的bean时,我们可以自动的创建bean,并交给spring的Ioc容器去管理。
spring3.x产生了Enable模块驱动注解,在调用其他模块bean的时候,可以通过Enable注解或者import注解生成bean。但是在spring4.x中,conditional条件注解的出现才真正的实现了自动装配
在阅读自动装配源码之前,我们先来演示一个自动装配的案例。本文讲解的是如何定义一个有条件的Redis自动装配的模板。

一、创建RedissonTemplate的Maven服务

Maven项目版本:

<groupId>com.my</groupId>
<artifactId>RedissonTemplate</artifactId>
<version>1.0-SNAPSHOT</version>
  • 1
  • 2
  • 3

创建带有@Configuration注解的RedissonAutoConfiguration.class:

package com.my.redission;

import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@EnableConfigurationProperties(RedissonProperties.class)
@Configuration
//@ConditionalOnClass(RedissonProperties.class)
public class RedissonAutoConfiguration {

    /**
     * RedissonClient:操作Redis的核心对象
     *     将该对象注入到容器中
     *     需要连接Redis 服务, host  port
     * @return
     */
    @Bean
    public RedissonClient redissonClient(RedissonProperties redissonProperties){
        Config config = new Config();
        String prefix = "redis://";
        if(redissonProperties.getSsl()){
            prefix = "rediss://";
        }
        config.useSingleServer()
                .setAddress(prefix+redissonProperties.getHost()+":"+redissonProperties.getPort())
                .setTimeout(redissonProperties.getTimeout());
        return Redisson.create(config);
    }

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

我们可以看到改类上携带了EnableConfigurationProperties(RedissonProperties.class)注解,该注解是自动从application.yml/application.properties文件中获取关于Redis的有关配置参数。
RedissonProperties.clas

package com.my.redission;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;

@Data
@ConfigurationProperties(prefix = "my.redisson")
public class RedissonProperties {

    private String host = "localhost";
    private Integer port = 6379;
    private Integer timeout = 1000;
    private Boolean ssl = false;

}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

此处使用了lombok.Data注解,就不需要我们对RedissonProperties的成员变量进行get、set处理了。但是别忘记了需要添加lombok.Data的依赖。

<dependency>
  <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <version>1.18.12</version>
 </dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

此刻,我们完成了程序的编写,接下来,我们会配置我们服务的自动装配。
我们需要在resource下创建一个META-INF文件夹,在META-INF文件夹下添加三个文件,分别是:spring.factories、additional-spring-configuration-metadata.json和spring-autoconfigure-metadata.properties。
在这里插入图片描述

首先,我们先讲一下additional-spring-configuration-metadata.json,该文件是为了配置如何从application.yml/application.properties文件中获取RedissonProperties中的成员变量的信息,也就是Redis的配置参数。
additional-spring-configuration-metadata.json

{
  "properties": [{
    "name": "my.redisson.host",
    "type": "java.lang.String",
    "description": "Redis的服务地址",
    "defaultValue": "localhost"
  },{
    "name": "my.redisson.port",
    "type": "java.lang.Integer",
    "description": "Redis的服务端口",
    "defaultValue": 6379
  },{
    "name": "my.redisson.timeout",
    "type": "java.lang.Integer",
    "description": "Redis的服务端口",
    "defaultValue": 1000
  },{
    "name": "my.redisson.ssl",
    "type": "java.lang.Boolean",
    "description": "Redis的服务端口",
    "defaultValue": false
  }]
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

spring.factories文件中配置了RedissonAutoConfiguration类的全路径,可以让Spring Boot通过自动装配加载RedissonAutoConfiguration类。加载的原理是通过SpringFactoriesLoader从classpath/META-INF/spring.factories文件中,根据key来加载对应的类到spring IoC容器中。该文件中的数据格式:key为自定配置类EnableAutoConfiguration的全路径,value是配置类的全路径;其中EnableAutoConfiguration就是自动装配的Enable。
spring.factories

org.springframework.boot.autoconfigure.EnableAutoConfiguration=com.my.redission.RedissonAutoConfiguration
  • 1

Spring Boot的自动装配中可以使用条件过滤,即conditional。
AutoConfigurationImportSelector方法会先扫描spring-autoconfiguration-metadata.properties文件,获取需要装配的类;最后再扫描spring.factories对应的类时,会结合前面的元数据进行过滤。为什么自动装配需要有过滤的条件,因为@Configuration注释的bean大部分情况下,需要依赖其他框架的类,当依赖的类不存在时,就不能将该bean注入到Ioc。同时也可以减少无效的@configuration类的数量从而降低SpringBoot的启动时间。Spring Boot同时也将自己的二方依赖框架和友商的依赖框架的@Configuration的类全路径添加在spring-boot、spring-boot-autoconfigure框架下的classpath/META-INF/spring.factories文件中,当条件满足的时候,会自动加载spring.factories文件中的bean。
就像本文的demo,RedissonTemplate在创建RedissonAutoConfiguration类时,需要依赖org.redisson.api.RedissonClient类。那么我们就可以将这个条件加上,只有当项目的classpath中有org.redisson.api.RedissonClient类时,Spring Boot的自动装配才能将RedissonAutoConfiguration加载到Ioc中。
spring-autoconfigure-metadata.properties

com.my.redission.RedissonAutoConfiguration=
com.my.redission.RedissonAutoConfiguration.ConditionalOnClass=org.redisson.api.RedissonClient
  • 1
  • 2

ConditionalOnClass的意思就是后面的类需要存在,同时Conditional条件注解还有很多。像:ConditionalOnBean、ConditionalOnResource等。

如果我们不使用spring-autoconfigure-metadata.properties文件配置,也可以在RedissonAutoConfiguration类上添加@ConditionalOnClass(RedissonProperties.class)注解。
在这里插入图片描述

至此,我们的RedissonTemplate配置完成。

二、创建测试服务

首先我们先创建一个spring boot项目,将RedissonTemplate的依赖引入。

<dependency>
    <groupId>com.my</groupId>
    <artifactId>RedissonTemplate</artifactId>
    <version>1.0-SNAPSHOT</version>
</dependency>
  • 1
  • 2
  • 3
  • 4
  • 5

然后在application.yml/application.properties文件中配置Redis的启动参数:

my:
  redisson:
    host: 127.0.0.1
    port: 6379
    timeout: 2000
  • 1
  • 2
  • 3
  • 4
  • 5

编写测试案例,我们通过Controller对外提供一个get接口,在浏览器中通过访问get接口来访问Redis中的数据,如果能正常连接到Redis并正常访问Redis数据,及代表,RedissonTemplate被自动装配到Ioc中。
首先,我们先排除@ComponentScan注解的自动扫描。由图可以看出,我们没有配置@ComponentScan扫描路径,所以该路径为当前class路径及其子类。
在这里插入图片描述
我们的启动类的全路径:com.example.demo1.Demo1Application
我们的RedissonTemplate的全路径:com.my.redission.RedissonAutoConfiguration

编写我们的Controller层代码:

package com.example.demo1.action;

import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping("/api")
public class RedissionAction {
    @Autowired
    private RedissonClient redissonClient;

    @GetMapping("/query")
    public String query(){
        return "key的个数="+redissonClient.getKeys().count()+"";
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

由1中可以得知,自动装配RedissonTemplate的条件是
在这里插入图片描述
我们看一下我们的libraries中是否存在org.redission框架,以及该框架中是否存在RedisClient。
在这里插入图片描述
在这里插入图片描述
可以看出,我们的条件满足自动装配RedissonTemplate。接下来,我们运行Spring Boot测试项目。可以看到启动日志中打印出连接上Redis的日志信息。
在这里插入图片描述
同时,我们来访问我们的controller接口,可以看到返回了redis中的key的数量。
在这里插入图片描述

接下来,我们测试一下条件不符合的场景。
我们将spring-autoconfigure-metadata.properties文件的条件改成:项目中必须存在rg.redisson.api.RedissonClientTets类,当然了该类是不存在的。

com.my.redission.RedissonAutoConfiguration=
com.my.redission.RedissonAutoConfiguration.ConditionalOnClass=org.redisson.api.RedissonClientTets
  • 1
  • 2

此时,我们再运行测试项目,将会看到Spring Boot启动报错,显示Field redissonClient in com.example.demo1.action.RedissionAction required a bean of type ‘org.redisson.api.RedissonClient’ that could not be found.
意思就是找不到RedissonClient这个Bean。
在这里插入图片描述

三、总结

至此,我们完成了如何配置一个自动装配的工程。下一章节,我们将从源码的角度去解读自动装配的逻辑。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/不正经/article/detail/125793
推荐阅读
相关标签
  

闽ICP备14008679号