赞
踩
Spring Framework一致在解决如何让bean的管理更加简单,如何让开发者尽可能少的去管理bean生成的一些配置;当我们在引用其他模块中的bean时,我们可以自动的创建bean,并交给spring的Ioc容器去管理。
spring3.x产生了Enable模块驱动注解,在调用其他模块bean的时候,可以通过Enable注解或者import注解生成bean。但是在spring4.x中,conditional条件注解的出现才真正的实现了自动装配。
在阅读自动装配源码之前,我们先来演示一个自动装配的案例。本文讲解的是如何定义一个有条件的Redis自动装配的模板。
Maven项目版本:
<groupId>com.my</groupId>
<artifactId>RedissonTemplate</artifactId>
<version>1.0-SNAPSHOT</version>
创建带有@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); } }
我们可以看到改类上携带了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; }
此处使用了lombok.Data注解,就不需要我们对RedissonProperties的成员变量进行get、set处理了。但是别忘记了需要添加lombok.Data的依赖。
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.12</version>
</dependency>
此刻,我们完成了程序的编写,接下来,我们会配置我们服务的自动装配。
我们需要在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 }] }
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
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
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>
然后在application.yml/application.properties文件中配置Redis的启动参数:
my:
redisson:
host: 127.0.0.1
port: 6379
timeout: 2000
编写测试案例,我们通过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中可以得知,自动装配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
此时,我们再运行测试项目,将会看到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。
至此,我们完成了如何配置一个自动装配的工程。下一章节,我们将从源码的角度去解读自动装配的逻辑。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。