Spring Boot初识-2

2023-11-10

Spring Boot初识-2

1. 整合Redis

Spring传统的整合Redis:

  • 导入jedis包
  • 利用IoC和DI帮你实现Jedis连接实例的管理
    • 原本:
      • JedisPool(JedisPoolConfig,主机地址,数据库索引,密码,超时时间);
      • JedisPool -> Jedis getResouce();
    • IoC和DI:
      • <bean id="jedisPoolConfig" class="xxx"/>
      • <bean id="jedisPool" class=""/> 构造注入相应信息
      • <bean id="redisUtil" class="xxx"/>

SpringBoot现代的整合Redis:

  • 导入spring-boot-starter-data-redis
  • 配置Redis的数据源信息
  • 使用RedisTemplate来进行Redis操作

2. 自动配置的原理

反斜杠表示换行
在这里插入图片描述

官方-HttpEncodingAutoConfiguration

  • 在spring.factories中发现了一系列的自动配置类

在这里插入图片描述

  • 自动配置类的结构:原来自动配置关键就在于 Java代码实现Spring IoC的配置类
@Configuration // Java实现Spring配置文件的注解  applicationContext.xml    【配置类】
@EnableConfigurationProperties({HttpEncodingProperties.class}) // 启用配置属性 【加载属性配置类】
// SpringBoot提供的一套@Conditionalxxxxx条件注解  能够进行条件判断
@ConditionalOnWebApplication // 判断当前是否是处于一个web应用程序
@ConditionalOnClass({CharacterEncodingFilter.class}) // 判断当前的classpath下是否有该类
@ConditionalOnProperty( // 判断当前的属性列表中是否有spring.http.encoding前缀的属性信息 如果enabled属性不存在 则默认的值为true
    prefix = "spring.http.encoding",
    value = {"enabled"},
    matchIfMissing = true
)
public class HttpEncodingAutoConfiguration {
    // 实例属性:属性配置类
    private final HttpEncodingProperties properties;

    // 构造方法:注入了一个属性配置类实例(自动进行注入)  和他@EnableConfigurationProperties对应
    public HttpEncodingAutoConfiguration(HttpEncodingProperties properties) {
        this.properties = properties;
    }

    @Bean // <bean id="方法名" class="返回值类型"></bean>
    // 判断当前Spring容器中是否有该bean配置 没有则生效
    @ConditionalOnMissingBean({CharacterEncodingFilter.class}) 
    public CharacterEncodingFilter characterEncodingFilter() {
        // 创建对象
        CharacterEncodingFilter filter = new OrderedCharacterEncodingFilter();
        // 设置属性【来自于属性配置类】
        filter.setEncoding(this.properties.getCharset().name());
        filter.setForceRequestEncoding(this.properties.shouldForce(Type.REQUEST));
        filter.setForceResponseEncoding(this.properties.shouldForce(Type.RESPONSE));
        return filter;
    }

    
  // .....
}

  • 属性配置类结构

    @ConfigurationProperties(
        prefix = "spring.http.encoding"
    )
    public class HttpEncodingProperties {
        public static final Charset DEFAULT_CHARSET = Charset.forName("UTF-8");
        private Charset charset;
        private Boolean force;
        private Boolean forceRequest;
        private Boolean forceResponse;
        private Map<Locale, Charset> mapping;
    
        public HttpEncodingProperties() {
            this.charset = DEFAULT_CHARSET;
        }
        // ....
    }
    

MyBatis实现的第三方自动配置 MyBatisAutoConfiguration

  • 发现了META-INF 有 spring.factories

在这里插入图片描述

  • 自动配置类的结构

    @Configuration 
    // 判断classpath下是否有下方两个类
    @ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
    // 判断数据源是否是一个单例
    @ConditionalOnSingleCandidate(DataSource.class)
    // 启用属性配置类
    @EnableConfigurationProperties({MybatisProperties.class})
    // 自动配置生效应该是在DataSourceAutoConfiguration MybatisLanguageDriverAutoConfiguration之后
    @AutoConfigureAfter({DataSourceAutoConfiguration.class, MybatisLanguageDriverAutoConfiguration.class})
    public class MybatisAutoConfiguration implements InitializingBean {
        
        private static final Logger logger = LoggerFactory.getLogger(MybatisAutoConfiguration.class);
        // 属性配置类的实例
        private final MybatisProperties properties;
        private final Interceptor[] interceptors;
        private final TypeHandler[] typeHandlers;
        private final LanguageDriver[] languageDrivers;
        private final ResourceLoader resourceLoader;
        private final DatabaseIdProvider databaseIdProvider;
        private final List<ConfigurationCustomizer> configurationCustomizers;
    
        // 提供了构造方法 注入了属性配置类
        public MybatisAutoConfiguration(MybatisProperties properties, ObjectProvider<Interceptor[]> interceptorsProvider, ObjectProvider<TypeHandler[]> typeHandlersProvider, ObjectProvider<LanguageDriver[]> languageDriversProvider, ResourceLoader resourceLoader, ObjectProvider<DatabaseIdProvider> databaseIdProvider, ObjectProvider<List<ConfigurationCustomizer>> configurationCustomizersProvider) {
            this.properties = properties;
            this.interceptors = (Interceptor[])interceptorsProvider.getIfAvailable();
            this.typeHandlers = (TypeHandler[])typeHandlersProvider.getIfAvailable();
            this.languageDrivers = (LanguageDriver[])languageDriversProvider.getIfAvailable();
            this.resourceLoader = resourceLoader;
            this.databaseIdProvider = (DatabaseIdProvider)databaseIdProvider.getIfAvailable();
            this.configurationCustomizers = (List)configurationCustomizersProvider.getIfAvailable();
        }
    
        public void afterPropertiesSet() {
            this.checkConfigFileExists();
        }
    
        private void checkConfigFileExists() {
            if (this.properties.isCheckConfigLocation() && StringUtils.hasText(this.properties.getConfigLocation())) {
                Resource resource = this.resourceLoader.getResource(this.properties.getConfigLocation());
                Assert.state(resource.exists(), "Cannot find config location: " + resource + " (please add config file or check your Mybatis configuration)");
            }
    
        }
    
        // 没有该bean则创建bean
        @Bean
        @ConditionalOnMissingBean 
        public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
            // 创建SqlSessionFactoryBean对象
            SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
            factory.setDataSource(dataSource);
            factory.setVfs(SpringBootVFS.class);
            // 判断属性配置类中是否有 mybatis的核心配置文件路径
            if (StringUtils.hasText(this.properties.getConfigLocation())) {
                factory.setConfigLocation(this.resourceLoader.getResource(this.properties.getConfigLocation()));
            }
    
            this.applyConfiguration(factory);
            if (this.properties.getConfigurationProperties() != null) {
                factory.setConfigurationProperties(this.properties.getConfigurationProperties());
            }
    
            if (!ObjectUtils.isEmpty(this.interceptors)) {
                factory.setPlugins(this.interceptors);
            }
    
            if (this.databaseIdProvider != null) {
                factory.setDatabaseIdProvider(this.databaseIdProvider);
            }
    
            if (StringUtils.hasLength(this.properties.getTypeAliasesPackage())) {
                factory.setTypeAliasesPackage(this.properties.getTypeAliasesPackage());
            }
    
            if (this.properties.getTypeAliasesSuperType() != null) {
                factory.setTypeAliasesSuperType(this.properties.getTypeAliasesSuperType());
            }
    
            if (StringUtils.hasLength(this.properties.getTypeHandlersPackage())) {
                factory.setTypeHandlersPackage(this.properties.getTypeHandlersPackage());
            }
    
            if (!ObjectUtils.isEmpty(this.typeHandlers)) {
                factory.setTypeHandlers(this.typeHandlers);
            }
    
            if (!ObjectUtils.isEmpty(this.properties.resolveMapperLocations())) {
                factory.setMapperLocations(this.properties.resolveMapperLocations());
            }
    
            Set<String> factoryPropertyNames = (Set)Stream.of((new BeanWrapperImpl(SqlSessionFactoryBean.class)).getPropertyDescriptors()).map(FeatureDescriptor::getName).collect(Collectors.toSet());
            Class<? extends LanguageDriver> defaultLanguageDriver = this.properties.getDefaultScriptingLanguageDriver();
            if (factoryPropertyNames.contains("scriptingLanguageDrivers") && !ObjectUtils.isEmpty(this.languageDrivers)) {
                factory.setScriptingLanguageDrivers(this.languageDrivers);
                if (defaultLanguageDriver == null && this.languageDrivers.length == 1) {
                    defaultLanguageDriver = this.languageDrivers[0].getClass();
                }
            }
    
            if (factoryPropertyNames.contains("defaultScriptingLanguageDriver")) {
                factory.setDefaultScriptingLanguageDriver(defaultLanguageDriver);
            }
    		
            // 从SqlSessionFactoryBean中获取一个对象(SqlSessionFactory)
            return factory.getObject();
        }
    
    }
    
    
  • MyBatis属性配置类结构

    @ConfigurationProperties(
        prefix = "mybatis"
    )
    public class MybatisProperties {
        public static final String MYBATIS_PREFIX = "mybatis";
        private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
        private String configLocation;
        private String[] mapperLocations;
        private String typeAliasesPackage;
        private Class<?> typeAliasesSuperType;
        private String typeHandlersPackage;
        private boolean checkConfigLocation = false;
        private ExecutorType executorType;
        private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;
        private Properties configurationProperties;
        @NestedConfigurationProperty
        private Configuration configuration;
    
        public MybatisProperties() {
        }
        // ....
    }
    

3. 手动实现一个自动配置

需求介绍

需求:模仿MyBatis的自动配置实现以下功能。

我们开发了一个框架hello,这个框架有一个类HelloService(类似于MyBatis中的SqlSession、SqlSessionFactory…)。第三方想使用我们这个框架:

  • 如果没有Spring的话

    // 是一个狠狠狠厉害的功能类
    public class HelloService{
    	private String msg;
    	public String hello(){
    		return "Hello "+msg;
    	}
    	// ....
    }
    // ----------------------------------------
    HelloService helloService = new HelloService();
    helloService.setMsg("World");
    String msg = helloService.hello(); // Hello World
    
  • 利用Spring的IoC

    <bean id="helloService" class="xxx">
    	<property name="msg" value="xxx"></property>
    </bean>
    
    public class XxxController{
    	@Resource
    	private HelloServicce helloService;
    }
    

我们希望给客户更好的体验,未来客户使用我们的框架,只需要导入我们提供的starter[autoconfigure],然后客户就可以直接使用,而不用进行任何配置。

或者如果客户需要一些调整,例如:更改msg的值信息

允许客户在application.yml中直接通过:

hello:
	service:
		msg: xxx

实现步骤

  1. 创建Maven项目命名为:hello-spring-boot-autoconfigure

  2. 导入依赖 springboot提供的自动配置包

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <!-- 此版本未来可以改动 牵一发而动全身 -->
        <version>1.5.22.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    
    
    <!-- Compile dependencies -->
    <dependency>
    	<groupId>org.springframework.boot</groupId>
    	<artifactId>spring-boot-autoconfigure</artifactId>
    </dependency>
    
  3. 提供属性配置类

    /**
     * 从配置文件中读取信息
     */
    @ConfigurationProperties(
            prefix = "hello.service"
    )
    public class HelloProperties {
        private final String DEFAULT_MSG_VALUE = "World";
        private String msg;
    
        public HelloProperties(){
            this.msg = DEFAULT_MSG_VALUE;
        }
    
        public String getMsg() {
            return msg;
        }
    
        public void setMsg(String msg) {
            this.msg = msg;
        }
    }
    
    
  4. 提供自动配置类

    @Configuration
    @ConditionalOnClass({HelloService.class})
    @EnableConfigurationProperties(HelloProperties.class)
    public class HelloAutoConfiguration {
    
        private final HelloProperties helloProperties;
    
        public HelloAutoConfiguration(HelloProperties helloProperties){
            this.helloProperties = helloProperties;
        }
    
        @Bean
        @ConditionalOnMissingBean
        public HelloService helloService(){
            HelloService helloService = new HelloService();
            if(StringUtils.hasText(this.helloProperties.getMsg())){
                helloService.setMsg(this.helloProperties.getMsg());
            }
            return helloService;
        }
    
    }
    
  5. 在META-INF中准备spring.factories然后进行启用自动配置

    # Auto Configure
    org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
    cn.hello.spring.boot.autoconfigure.HelloAutoConfiguration
    
  6. 将项目进行打包 提供给对应的starter或者直接供给客户使用

补充:如果希望在IDEA中能够编写有提示,可以在自动配置包中添加spring-configuration-metadata.json文件

{
  "properties": [
    {
      "name": "hello.service.msg",
      "type": "java.lang.String",
      "description": "A NX Framework msg.",
      "sourceType": "cn.hello.spring.boot.autoconfigure.HelloProperties",
      "defaultValue": "World"
    }
  ],
  "hints": []
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Spring Boot初识-2 的相关文章

随机推荐

  • BeyondCompare 破解(试用期重置)

    将安装日期改为未来的日期 beyond compare 安装后会在 C Users 计算机名 AppData Roaming BCompare 目录下生成一个 ini文件 记录 安装的时间 和 最近一次打开软件的时间 只要超过30天就会提示
  • X64处理器架构

    X64处理器架构 翻译的windbg帮助文档 X64处理器架构 X64 架构是一个向后兼容的扩展的 x86 提供了和 x86 相同的 32 位模式和一个新的 64 位模式 术语 x64 包括 AMD 64 和 Intel64 他们的指令集基
  • Spring在代码中获取bean的几种方式

    Spring在代码中获取bean的几种方式 方法一 在初始化时保存ApplicationContext对象 方法二 通过Spring提供的utils类获取ApplicationContext对象 方法三 继承自抽象类ApplicationO
  • 黑客一般是如何入侵电脑的?

    1 无论什么站 无论什么语言 我要渗透 第一件事就是扫目录 最好一下扫出个上传点 直接上传 shell 诸位不要笑 有时候你花很久搞一个站 最后发现有个现成的上传点 而且很容易猜到 不过这种情况发生在 asp 居多 2 asp aspx M
  • CV计算机视觉核心07-目标检测yolo v2、v3(yolo初始版本的v0和v1版本代码)

    CV计算机视觉核心07 目标检测 设计检测类算法的output层 可用已知条件有 1 检测问题的输出是什么 怎么用数字来表示 输入是一个矩阵 输出是 x y w h 其中x和y表示目标的左上角坐标 w和h表示目标的长和宽 因此输出是用四个这
  • 【NLP】维基百科中文数据训练word2vec词向量模型——基于gensim库

    前言 本篇主要是基于gensim 库中的 Word2Vec 模型 使用维基百科中文数据训练word2vec 词向量模型 大体步骤如下 数据预处理 模型的训练 模型的测试 准备条件 Windows10 64位 Python3 6 并安装 ge
  • ‘git‘ 不是内部或外部命令,也不是可运行的程序 或批处理文件。

    1 cmd报错内容 C Users 27104 Desktop gt git clone https github com tianyucoder 200826 ajax git 不是内部或外部命令 也不是可运行的程序 或批处理文件 2 原
  • range()函数

    range 函数 创建一个整数列表 一般用于for循环当中 1 语法 range start stop step start 计数从start开始 默认为0 range 9 和range 0 9 是一样的 stop 计数到stop为止 但不
  • 通用智能面临巨大掣肘,国产AIGC还在寻找光明

    无论技术有多先进 符合商业规律才能笑到最后 数科星球 原创 作者丨苑晶 编辑丨十里香 AI GC背后充满了故事 在一家家企业手握巨额融资之时 人们耳边再次响起了警钟 诚然 在新的浪潮之下 符合商业规律的企业才能笑到最后 在国外竞品大踏步前行
  • 关于项目管理的知识点

    转自 http blog joycode com mvm 感觉写的挺好 推荐大家看一下 1 你们的项目组使用源代码管理工具了么 应该用 VSS CVS PVCS ClearCase CCC Harvest FireFly都可以 我的选择是V
  • 【目的:windows下VS2017/2022配置使用opengl - 初探-创建一个空窗口】

    目的 windows下VS2017 2022配置使用opengl 初探 创建一个空窗口 环境 系统 Win10 环境 VS2017 64bit 步骤 windows下visualstudio下使用opengl 搭建配置环境并测试窗口 1 o
  • vue3.0---使用computed来获取vuex里数据

    不再是vue2 0里什么mapGetter mapState那些复杂的获取方式 vue3 0里直接使用computed就可以调用vuex里的数据了 喜大普奔 同时注意 一点 不可以直接使用useStore 方法里的state对象 因为在输出
  • css将文字置于图片上的方法

    我们在开发的时候 有大量的场景需要将文字至于图片之上 如图 以上是将 空山新雨后 天气晚来秋 加在图片之上 对于大多数情况 我们都可以将图片作为背景图引入 但有些时候不能将图片作为背景图引入 这个时候就要用到其他的方法 以下我们提供三种方法
  • MyBatis的lazy-loading是什么?

    MyBatis的lazy loading是什么 MyBatis的lazy loading 延迟加载 是一种数据查询策略 它允许仅在需要时才从数据库中获取相关联的数据 这是通过创建 Java 代理对象来实现的 该代理对象在真正需要相关对象时将
  • linux命令——man

    Shell 也称为终端或壳 用户与 Linux 系统的交互 常见执行Linux命令的格式是这样的 命令名称 命令参数 命令对象 注意 命令名称 命令参数 命令对象之间请用空格键分隔 命令对象一般是指要处理的文件 目录 用户等资源 而命令参数
  • Linux下搭建第一个区块链网络(FISCO BCOS)

    Linux下搭建第一个区块链网络 FISCO BCOS 概述 搭建单群组FISCO BCOS联盟链 配置及使用控制台 部署及调用HelloWorld合约 概述 FISCO BCOS是由国内企业主导研发 对外开源 安全可控的企业级金融联盟链底
  • Error:JAVA_HOME is not set and could not be found 解决般的法

    很多人按照网上的各类教程搭建hadoop 但经常在安装好了后 启动hadoop时出现各类的错误 本文就 Error JAVA HOME is not set and could not be found 这一错误提出解决办法 针对这个错误
  • 10.1~10.3国庆节技术沉淀

    国庆节没怎么学习 玩了一天 宿舍玩游戏两天 一次循环完成百钱白鸡 关键就在于先人工化简一下两个方程式 23456789的各位之和怎么求 现在也不会 好吧 现在会了 不太理解 求整数各位之和 author zlb date 10 3 impo
  • 2020年“金九银十”的面试宝典:腾讯,字节等大厂面试真题汇总

    前言 职场的金九银十跳槽季火热进行中 不同的是 今年的竞争比往年会更加激烈一些 形式更加严峻一些 对于求职者来说 面试是一道坎 很多人会恐惧面试 即使是工作很多年的老鸟 也可能存在面试焦虑 大家多多少少可能都听到或看到一些信息 就是好多公司
  • Spring Boot初识-2

    Spring Boot初识 2 1 整合Redis Spring传统的整合Redis 导入jedis包 利用IoC和DI帮你实现Jedis连接实例的管理 原本 JedisPool JedisPoolConfig 主机地址 数据库索引 密码