文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

使用springboot怎么实现自动配置

2023-06-14 19:45

关注

这篇文章将为大家详细讲解有关使用springboot怎么实现自动配置,文章内容质量较高,因此小编分享给大家做个参考,希望大家阅读完这篇文章后对相关知识有一定的了解。

springboot是什么

springboot一种全新的编程规范,其设计目的是用来简化新Spring应用的初始搭建以及开发过程,SpringBoot也是一个服务于框架的框架,服务范围是简化配置文件。

首先创建一个springboot工程用来测试,然后在pom文件中引入springboot-starter-redis的启动器依赖

<dependencies>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-web</artifactId>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-test</artifactId>            <scope>test</scope>        </dependency>        <dependency>            <groupId>org.springframework.boot</groupId>            <artifactId>spring-boot-starter-data-redis</artifactId>            <version>2.1.7.RELEASE</version>        </dependency></dependencies>

然后,在application.properties中配置redis属性

spring.redis.port=6379spring.redis.host=localhostspring.redis.database=0

然后,在启动类中注入redisTemplate类,redisTemplate为spring官方提供的对redis底层开发包(例如jedis)进行了深度封装的组件,使用redisTemplate可以优雅的操作redis。我在启动类中写了一个测试方法,向redis写入一条数据

@RequestMapping("/redistest")    public String test(){        redisTemplate.opsForSet().add("aaaaa","123456");        return "OK";    }

运行这个方法,打开redis客户端可以看到值已经写入了

使用springboot怎么实现自动配置

先抛开这里的键和值让人看不懂的问题,大家是不是觉得springboot整合redis要比普通的springmvc整合redis简单多了?我只配置了redis的连接地址,端口号,注入了redisTemplate,就能开始操作redis了,那么springboot底层到底做了些什么使得整合变得如此的简单了呢。

首先我们来看,springboot启动类上都有一个@SpringbootApplication注解,那么这个注解是起什么作用的呢,让我们点进去看一下

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan(excludeFilters = { @Filter(type = FilterType.CUSTOM, classes = TypeExcludeFilter.class),@Filter(type = FilterType.CUSTOM, classes = AutoConfigurationExcludeFilter.class) })public @interface SpringBootApplication

可以看到SpringbootApplication这个注解是由一系列的注解组合而成,这其中最重要的是@EnableAutoConfiguration和@ComponentScan,@ComponentScan的意思就是组件扫描注解,这个注解会自动注入所有在主程序所在包下的组件。比@ComponentScan注解更重要的就是@EnableAutoConfiguration注解了,这个注解的含义就是开启自动装配,直接把bean装配到ioc容器中,@EnableAutoConfiguration也是一个组合注解,我们点进去看一下

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@AutoConfigurationPackage@Import(AutoConfigurationImportSelector.class)public @interface EnableAutoConfiguration

这个地方我们主要看@AutoConfigurationPackage和@Import(AutoConfigurationImportSelector.class)两个注解,首先来看@AutoConfigurationPackage注解

@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)@Documented@Inherited@Import(AutoConfigurationPackages.Registrar.class)public @interface AutoConfigurationPackage {}

这个注解主要是获取我们注解所在包下的组件去进行注册,大家看到这个@Import注解,那么这个注解是什么含义呢,

@Import注解用来导入@Configuration注解的配置类、声明@Bean注解的bean方法、导入ImportSelector的实现类或导入ImportBeanDefinitionRegistrar的实现类,这里这个AutoConfigurationPackages.Registrar.class就是ImportBeanDefinitionRegistrar的实现类,来看下源码

static class Registrar implements ImportBeanDefinitionRegistrar, DeterminableImports {        //metadata是注解的元信息 registry是bean定义的注册器@Overridepublic void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry registry) {            //把注解所在的包下所有的组件都进行注册register(registry, new PackageImport(metadata).getPackageName());}@Overridepublic Set<Object> determineImports(AnnotationMetadata metadata) {return Collections.singleton(new PackageImport(metadata));}}public static void register(BeanDefinitionRegistry registry, String... packageNames) {//首先判断这个bean有没有被注册if (registry.containsBeanDefinition(BEAN)) {//获取bean定义BeanDefinition beanDefinition = registry.getBeanDefinition(BEAN);//通过bean定义获取构造函数值ConstructorArgumentValues constructorArguments = beanDefinition.getConstructorArgumentValues();//给构造函数添加参数值constructorArguments.addIndexedArgumentValue(0, addBasePackages(constructorArguments, packageNames));}else {//一个新的bean定义GenericBeanDefinition beanDefinition = new GenericBeanDefinition();//设置beanClass为beanPackages类型beanDefinition.setBeanClass(BasePackages.class);beanDefinition.getConstructorArgumentValues().addIndexedArgumentValue(0, packageNames);beanDefinition.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);//bean注册registry.registerBeanDefinition(BEAN, beanDefinition);}}

接下来就是@Import(AutoConfigurationImportSelector.class)这个注解,我们来看看AutoConfigurationImportSelector这个类,这个类是我们自动装配的导入选择器,首先看这个类的第一个方法,其实也就是这个类的核心方法

@Overridepublic String[] selectImports(AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return NO_IMPORTS;}//加载元数据AutoConfigurationMetadata autoConfigurationMetadata = AutoConfigurationMetadataLoader.loadMetadata(this.beanClassLoader);//获得自动装配的实体AutoConfigurationEntry autoConfigurationEntry = getAutoConfigurationEntry(autoConfigurationMetadata,annotationMetadata);return StringUtils.toStringArray(autoConfigurationEntry.getConfigurations());}
protected AutoConfigurationEntry getAutoConfigurationEntry(AutoConfigurationMetadata autoConfigurationMetadata,AnnotationMetadata annotationMetadata) {if (!isEnabled(annotationMetadata)) {return EMPTY_ENTRY;}//获得属性AnnotationAttributes attributes = getAttributes(annotationMetadata);//获得候选的配置类,核心方法List<String> configurations = getCandidateConfigurations(annotationMetadata, attributes);//去除重复configurations = removeDuplicates(configurations);//获得排除的配置Set<String> exclusions = getExclusions(annotationMetadata, attributes);//检查排除的配置checkExcludedClasses(configurations, exclusions);//排除configurations.removeAll(exclusions);configurations = filter(configurations, autoConfigurationMetadata);fireAutoConfigurationImportEvents(configurations, exclusions);return new AutoConfigurationEntry(configurations, exclusions);}

在这部分中,核心方法是getCandidateConfigurations,我们来看下这个方法

protected List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {//从工厂中获取自动配置类List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());//这句断言很重要,告诉了我们工厂是去哪里找自动配置类的,这里显然META-INF/spring.factories是一个路径Assert.notEmpty(configurations, "No auto configuration classes found in META-INF/spring.factories. If you "+ "are using a custom packaging, make sure that file is correct.");return configurations;}

那我们就找一下这个路径,去哪里找呢,我们看到这个类的包是org.springframework.boot.autoconfigure;那我们就到这个包的位置去找这个spring.factories,果不其然,我们点开这个文件

使用springboot怎么实现自动配置

使用springboot怎么实现自动配置

我们看到文件中有一行注释这Auto configure,表示这些都是自动配置相关的类,这里我们不得不说spring框架真的是强大,这里面居然有100多个自动配置类,我们找到redis有关的自动配置类

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

这里我们需要的肯定是第一个自动配置类,我们点进去看看

@Configuration//条件注解,某个class位于类路径上,才会实例化一个Bean,这个类是redis操作的类@ConditionalOnClass(RedisOperations.class)//使得@ConfigurationProperties 注解的类生效,这个类是配置redis属性的类@EnableConfigurationProperties(RedisProperties.class)//导入一些配置@Import({ LettuceConnectionConfiguration.class, JedisConnectionConfiguration.class })public class RedisAutoConfiguration {@Bean//仅仅在当前上下文中不存在某个对象时,才会实例化一个Bean,这个就是spring默认的redisTemplate@ConditionalOnMissingBean(name = "redisTemplate")public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)throws UnknownHostException {RedisTemplate<Object, Object> template = new RedisTemplate<>();template.setConnectionFactory(redisConnectionFactory);return template;}@Bean@ConditionalOnMissingBeanpublic StringRedisTemplate stringRedisTemplate(RedisConnectionFactory redisConnectionFactory)throws UnknownHostException {StringRedisTemplate template = new StringRedisTemplate();template.setConnectionFactory(redisConnectionFactory);return template;}}

我们在application.properties中配置的redis属性,其实就是设置到了这个类中

//前缀spring.redis@ConfigurationProperties(prefix = "spring.redis")public class RedisProperties {private int database = 0;private String url;private String host = "localhost";private String password;private int port = 6379;private boolean ssl;private Duration timeout;private Sentinel sentinel;private Cluster cluster;private final Jedis jedis = new Jedis();private final Lettuce lettuce = new Lettuce();}

我们前面说了,用了spring默认的redisTemplate操作redis的话,存到redis里的数据对我们的阅读不友好,我们看不懂,那是因为redisTemplate中默认用了jdk自带的序列化器

使用springboot怎么实现自动配置

要想让数据变成我们能看得懂的样子,我们需要替换掉redisTempalte默认的序列化器,现在我就来实操一下,写一个配置类

@Configurationpublic class RedisConfig {    //这里的上下文已经有了自定义的redisTemplate,所以默认的redisTemplate不会生效    @Bean    public RedisTemplate<Object,Object> redisTemplate(RedisConnectionFactory redisConnectionFactory)  {        RedisTemplate<Object,Object> redisTemplate=new RedisTemplate<>();        //设置自定义序列化器        redisTemplate.setDefaultSerializer(new Jackson2JsonRedisSerializer<Object>(Object.class));        redisTemplate.setConnectionFactory(redisConnectionFactory);        return redisTemplate;    }}

然后我改写一下测试方法,一起来看结果

public String test(){        redisTemplate.opsForSet().add("ffffff","55555555");        return "OK";    }

使用springboot怎么实现自动配置

关于使用springboot怎么实现自动配置就分享到这里了,希望以上内容可以对大家有一定的帮助,可以学到更多知识。如果觉得文章不错,可以把它分享出去让更多的人看到。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     807人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     351人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     314人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     433人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     221人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯