手写SpringBoot(三)之自动配置

系列文章目录

手写SpringBoot(一)之简易版SpringBoot
手写SpringBoot(二)之动态切换Servlet容器
手写SpringBoot(三)之自动配置
手写SpringBoot(四)之bean动态加载

手写SpringBoot(三)之自动配置

文章目录

  • 系列文章目录
    • 手写SpringBoot(三)之自动配置

本节主要讲解SpringBoot的自动配置

回想一下,在用原生Spring aop功能的时候,需要哪些配置?

  1. 引入aspectjweaver jar包

  2. 定义切面

  3. 配置切面

  4. 开启aop功能

为什么在SpringBoot中,只需要引入spring-boot-starter-aop就可以直接使用aop功能?

那是因为SpringBoot定义了AOP配置类,帮我们完成了这些工作。

spring-boot-auto-configure jar包中有很多SpringBoot帮我们配置好的类,其中就有AopAutoConfiguration,提供自动开启aop等功能


现在来写一个简易版的Springboot自动配置

当我们新增了AopConfiguration配置类后,需要在MySpringBootApplication中显示import该类,如果AutoConfiguration配置类很多的情况,就要在import标签上面引入很多类。

利用ImportSelector接口,可以将需要加载的类在selectImports方法中,返回该类的全限定名称。

public class MyImportSelector implements DeferredImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {return new String[0];}
}

在该方法中,可以显示的将需要引入的配置类全路径全部加载一个数组中,然后返回,再通过@MySpringBootApplication Import 该MyImportSelector类就可以加载MyImportSelector中返回的类。

这样实现的弊端,

  1. 在代码中写死加载的类,需要新增时,则需要动代码。
  2. 无法通过外部配置来动态加载所需要的bean。

这里我们利用java spi机制来实现动态加载

Java SPI(Service Provider Interface)是Java官方提供的一种服务发现机制,它允许在运行时动态地加载实现特定接口的类,而不需要在代码中显式地指定该类,从而实现解耦和灵活性

  1. 定义一个特定的接口类 AutoConfiguration
  2. 在resource文件夹下新建META-INF/services文件夹,在该services文件夹下新建AutoConfiguration全限定名的文件。
  3. 在AutoConfiguration全限定名的文件下配置需要加载的类全限定名称。
  4. 在MyImportSelector中实现加载java spi机制的类]
  5. 将@MySpringBootApplication 中的Import标签改为引入MyImportSelector

AutoConfiguration接口定义

package cn.axj.springboot.my.config;/**
* 该类仅是一个标识作用
*/
public interface AutoConfiguration {
}

新建AutoConfiguration文件,cn.axj.springboot.my.config.AutoConfiguration, AutoConfiguration中配置如下

cn.axj.springboot.my.config.WebServerAutoConfiguration
cn.axj.springboot.my.config.AopAutoConfiguration

此时WebServerAutoConfiguration和AopAutoConfiguration需要实现AutoConfiguration

MyImportSelector实现

package cn.axj.springboot.my.config;import org.springframework.context.annotation.DeferredImportSelector;
import org.springframework.core.type.AnnotationMetadata;import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;public class MyImportSelector implements DeferredImportSelector {@Overridepublic String[] selectImports(AnnotationMetadata importingClassMetadata) {/*** 主要这里加载的是所有命名为cn.axj.springboot.my.config.AutoConfiguration的文件下的定义的类,不仅仅指该spring-boot jar包.* 其他jar包只要在resources目录下定义了AutoConfiguration的类,都会被加载进来。* 这里可以提供动态扩展能力。*/ServiceLoader<AutoConfiguration> serviceLoader = ServiceLoader.load(AutoConfiguration.class);List<String> list = new ArrayList<>();for (AutoConfiguration autoConfiguration : serviceLoader) {list.add(autoConfiguration.getClass().getName());}return list.toArray(new String[0]);}
}

MySpringBootApplication中改造

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Configuration
@ComponentScan
@Target(ElementType.TYPE)
@Import(MyImportSelector.class)
public @interface MySpringBootApplication {
}

当前结构图
在这里插入图片描述

启动user-service模块,并在MySpringApplication 中容器创建完成后,打开debug。
在这里插入图片描述

可以看到AopAutoConfiguration 和 WebServerAutoConfiguration 均加载到了容器中。


当其他三方组件也想整合进springboot怎么办?由于其他组件无法获取到AutoConfiguration接口,所以需要将AutoConfiguration接口提出来,专门弄一个jar包供三方组件使用。

新建模块 my-spring-boot-configuration,并将AutoConfiguration类迁移过去。

在my-spring-boot模块中引入 my-spring-boot-configuration
在这里插入图片描述

项目结构如上


下面来构建mybatis 整合springboot的jar包

spring整合mybatis 主要是整合SqlSessionFactoryBean,将这个bean交给Spring管理

SqlSessionFactoryBean 主要设置DataSourceMapperLocationConfigLocaltion等信息。

新建my-mybatis-spring-boot-starter模块

  1. 引入依赖jar包
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><parent><groupId>cn.axj</groupId><artifactId>spring-boot-base</artifactId><version>1.0-SNAPSHOT</version></parent><artifactId>my-mybatis-spring-boot-starter</artifactId><properties><maven.compiler.source>8</maven.compiler.source><maven.compiler.target>8</maven.compiler.target><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><dependencies><!-- MyBatis --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis</artifactId><version>3.5.9</version></dependency><!-- MyBatis-Spring 整合包 --><dependency><groupId>org.mybatis</groupId><artifactId>mybatis-spring</artifactId><version>2.0.4</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.3.18</version></dependency><dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.2.19</version></dependency><dependency><groupId>cn.axj</groupId><artifactId>my-spring-boot-configuration</artifactId><version>1.0-SNAPSHOT</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-jdbc</artifactId><version>5.3.18</version></dependency></dependencies></project>
  1. 创建自动配置的MybatisAutoConfiguration
package cn.axj.mybatis.springboot.config;import cn.axj.springboot.my.config.AutoConfiguration;
import com.alibaba.druid.pool.DruidDataSource;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;import javax.sql.DataSource;
import java.io.IOException;@Configuration
public class MyBatisAutoConfiguration implements AutoConfiguration {@Beanpublic DataSource dataSource(){DruidDataSource druidDataSource = new DruidDataSource();druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");druidDataSource.setUsername("root");druidDataSource.setPassword("123456");druidDataSource.setUrl("jdbc:mysql://192.168.56.102:3306/springtest?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC");return druidDataSource;}@Beanpublic SqlSessionFactoryBean sqlSessionFactory() throws IOException {SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();PathMatchingResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver();sqlSessionFactoryBean.setDataSource(dataSource());sqlSessionFactoryBean.setConfigLocation(resourcePatternResolver.getResource("classpath:mybatis-config.xml"));sqlSessionFactoryBean.setMapperLocations(resourcePatternResolver.getResources("classpath:mapper/*Mapper.xml"));return sqlSessionFactoryBean;}
}

为了简便,将数据源这些信息写死,这些信息可以提供配置类,给用户使用。

  1. 在resources目录下创建mybatis-config.xml
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE configurationPUBLIC "-//mybatis.org//DTD Config 3.0//EN""http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration></configuration>
  1. 创建自动配置的文件路径META-INF/services,并创建文件cn.axj.springboot.my.config.AutoConfiguration,并将MyBatisAutoConfiguration的全限定名称配置进去
cn.axj.mybatis.springboot.config.MyBatisAutoConfiguration

下面开始测试

在user-service模块中引入my-mybatis-spring-boot-starter,并引入mysql连接包

<dependency><groupId>cn.axj</groupId><artifactId>my-mybatis-spring-boot-starter</artifactId><version>1.0-SNAPSHOT</version>
</dependency><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><version>8.0.33</version>
</dependency>
  1. 创建Model包,并创建User
package cn.axj.user.model;public class User {private Integer id;private String username;...省略get set 方法@Overridepublic String toString() {return "User{" +"id=" + id +", username='" +username + '\'' +'}';}
}
  1. 创建mapper包,并新增UserMapper
package cn.axj.user.mapper;import cn.axj.user.model.User;
import org.apache.ibatis.annotations.Mapper;@Mapper
public interface UserMapper {User selectById(Integer id);
}
  1. 在resources目录下创建mapper文件,并创建UserMapper.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="cn.axj.user.mapper.UserMapper"><select id="selectById" resultType="cn.axj.user.model.User">select id,username from user where id = #{id}</select>
</mapper>
  1. 改造UserService,引入UserMapper查询User
package cn.axj.user.service;import cn.axj.user.mapper.UserMapper;
import cn.axj.user.model.User;
import org.springframework.stereotype.Service;import javax.annotation.Resource;@Service
public class UserService {@ResourceUserMapper userMapper;public User test(Integer id){User user = userMapper.selectById(id);return user;}
}
  1. 改造TestController,查询返回User对象
package cn.axj.user.controller;import cn.axj.user.service.UserService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;import javax.annotation.Resource;@RestController
public class TestController {@Resourceprivate UserService userService;@GetMapping(value = "/test")public String test(Integer id){return userService.test(id).toString();}
}

这里由于没有配置HttpMessageConverter,无法将对象转换成字符串形式,所以用了toString()方法。

  1. 在UserApplication主类上,新增@MapperScan(“cn.axj.user.mapper”),扫描mapper文件。

这个问题,我在MyBatisAutoConfiguration中配置MapperScannerConfigurer,但是无法生效,mybatis不会去扫描响应的包,并生成代理对象,不知道什么原因,但是加在主类上就可以?难道mybatis将SqlSessionFactoryBean交给Spring容器后,就不自己扫描了吗?

项目结构图如下

在这里插入图片描述

至此,启动项目。这里记得引入默认的tomcat 容器,不然会无法启动。

通过浏览器访问 localhost:8080/test?id=1 或者 id = 2

在这里插入图片描述

可以看到整合mybatis成功,成功返回数据。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/781878.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

企业培训系统功能介绍

在当今知识经济时代&#xff0c;企业的竞争力在很大程度上取决于员工的专业能力和综合素质。为了适应不断变化的市场需求和技术进步&#xff0c;企业需要对员工进行持续有效的培训。一个高效的企业培训系统对企业人才培训至关重要。以下介绍一下企业培训系统的主要功能&#xf…

电脑文件msvcp120.dll丢失的解决方法详细分析,找多种靠谱方法修复

遇到msvcp120.dll文件丢失的问题实际上不算罕见&#xff0c;这往往是由于我们频繁使用电脑而导致的意外删除&#xff0c;或者是电脑受到病毒感染。当这类情况发生时&#xff0c;msvcp120.dll文件可能会被错误地移除或损坏&#xff0c;这便需要我们去进行修复。接下来&#xff0…

【系统架构师】-第18章-安全架构设计

(1)信息泄露&#xff1a;信息被泄露或透露给某个非授权的实体。 (2)破坏信息的完整性&#xff1a;数据被非授权地进行增删、修改或破坏而受到损失。 (3)拒绝服务&#xff1a;对信息或其他资源的合法访问被无条件地阻止。 (4)非法使用(非授权访问):某一资源被某个非授权的人或…

FA模型切换Stage模型组件切换之ServiceAbility切换DataAbility切换

ServiceAbility切换 FA模型中的ServiceAbility对应Stage模型中的ServiceExtensionAbility。Stage模型下的ServiceExtensionAbility为系统API&#xff0c;只有系统应用才可以创建。因此&#xff0c;FA模型的ServiceAbility的切换&#xff0c;对于系统应用和三方应用策略有所不同…

实践笔记-harbor搭建(版本:2.9.0)

harbor搭建 1.下载安装包&#xff08;版本&#xff1a;2.9.0&#xff09;2.修改配置文件3.安装4.访问harbor5.可能用得上的命令: 环境&#xff1a;centos7 1.下载安装包&#xff08;版本&#xff1a;2.9.0&#xff09; 网盘资源&#xff1a;https://pan.baidu.com/s/1fcoJIa4x…

Linux部署Sonarqube+Gogs+Jenkins(一)

Linux部署SonarqubeGogsJenkins 一、1.Linux安装JDK11环境1. 本地进行上传2. 进入到/usr/java目录&#xff0c;并且进行解压3. 配置文件/etc/profile&#xff0c;配置环境变量4.让对应的配置文件生效5. 验证 二、Linux安装Python环境三、Linux安装Jenkins环境1、/usr目录下创建…

发表SCI论文对文凭有什么要求吗?SCI学历要求

sci论文是学术水平很高的文章&#xff0c;往往要通过课题研究&#xff0c;才能撰写出论文内容来。可以说作者没有一定的文凭&#xff0c;完不成sci论文的撰写&#xff0c;就不能发表。但这不代表文凭是sci论文发表的限制条件&#xff0c;实际上sci期刊对作者文凭没有要求&#…

WEPE系统安装纯净版window11教程(包含pe内系统安装方法)

目录 一.安装u盘启动盘 1.1制作安装系统引导盘 1.2下载保存windows镜像 1.3根据自己电脑品牌查询进入BIOS设置的方法 1.4我们成功进入了PE 二.重装系统 2.1遇到问题 2.2重新来到这个界面 三.PE中基本软件的作用 四.学习声明 今天不敲代码&#xff0c;今天来讲讲We P…

ubuntu 安装 cloudcompare(两种方法)

方法一 &#xff1a;从 snap 安装 &#xff08;推荐&#xff09; 安装简单&#xff0c;基本上功能都有&#xff08;读写保存las&#xff0c;pcd&#xff0c;标注等&#xff09; 安装&#xff1a; sudo apt-get update sudo apt install snap sudo snap install cloudcompare…

Node | Node.js 版本升级

目录 Step1&#xff1a;下载 Step2&#xff1a;安装 Step3&#xff1a;换源 发现其他博客说的 n 模块不太行&#xff0c;所以老老实实地手动安装 Step1&#xff1a;下载 Node 中文官网&#xff1a;https://nodejs.cn/download 点击后&#xff0c;将会下载得到一个 .msi 文件…

WIFI驱动移植实验:配置 Linux 内核

一. 简介 前面文章删除了Linux内核源码&#xff08;NXP官方的kernel内核源码&#xff09;自带的 WIFI驱动。 WIFI驱动移植实验&#xff1a;删除Linux内核自带的 RTL8192CU 驱动-CSDN博客 将正点原子提供的 rtl8188EUS驱动源码添加到 kernel内核源码中。文章如下&#xff1a…

PID算法控制5840-31ZY编码器直流减速电机旋转特定角度(一)

模块分析 在本工程中&#xff0c;使用stm32做主控芯片输出PWM波&#xff0c;TB6112做电源驱动带动5840-31ZY编码器直流减速电机旋转特定角度 有如下模块 TB6112驱动模块 TB6112是性能优于常见L298N的一款电机驱动芯片&#xff0c;体积更小效率更高发热少 其接线如图&#x…

HarmonyOs开发:轮播图Banner组件封装与使用

前言 轮播图在每个项目中都很常见&#xff0c;鸿蒙中在容器组件中也提供了Swiper组件&#xff0c;用于子组件滑动轮播显示&#xff0c;和前端的使用起来也是异曲同工&#xff0c;我们先看下基本的用法。 Swiper() {ForEach(["1", "2", "3", &quo…

每日一题(反转链表)

给你单链表的头节点 head &#xff0c;请你反转链表&#xff0c;并返回反转后的链表。 206. 反转链表 - 力扣&#xff08;LeetCode&#xff09; 示例 1&#xff1a; 输入&#xff1a;head [1,2,3,4,5] 输出&#xff1a;[5,4,3,2,1] 思路一 运用迭代的算法&#xff0c;把头指针…

【智能算法】晶体结构算法(CryStAl)原理及实现

目录 1.背景2.算法原理2.1算法思想2.2算法过程 3.结果展示4.参考文献 1.背景 2021年&#xff0c;S Talatahari等人受到晶体自然结构启发&#xff0c;提出了晶体构造算法&#xff08;Crystal Structure Algorithm , CryStAl&#xff09;。 2.算法原理 2.1算法思想 CryStAl受…

Unity Mobile Notifications推送问题

1.在部分机型点击通知弹窗进不去游戏 把这里改成自己的Activity 2.推送的时候没有横幅跟icon红点 主要是第一句话 注册的时候选项可以选择 defaultNotificationChannel new AndroidNotificationChannel(“default_channel”, “Default Channel”, “For Generic notifica…

一文教你如何轻松领取阿里云优惠券

随着云计算技术的飞速发展&#xff0c;越来越多的企业和个人选择使用阿里云作为他们的云服务提供商。为了吸引更多的用户上云&#xff0c;阿里云推出了各种优惠券和促销活动。本文将教大家如何轻松领取阿里云优惠券&#xff0c;以便在购买阿里云产品和服务时享受更多优惠。 一、…

WinServer启用Hyper-V新建虚拟机没有网络、无法开启增强模式、开启远程连接功能

没有网络问题如下&#xff1a; 原因&#xff1a;没有在Hyper-V中新增交换机 操作—虚拟交换机管理器—新建虚拟网络交换机-外部-允许管理员操作系统共享此网络适配器 无法开启增强模式&#xff1a; 开启远程连接功能 或者&#xff1a;

C++:你真的了解匿名对象的生命周期吗?

初步了解匿名对象生命周期 1. 提出问题2. 模拟验证3. 得出结论 不知道有没有人和我一样&#xff0c;在vector的模拟实现部分对于resize接口的实现有一些疑问。 void resize(size_t n , const T& val T()) {if (n > size()){reserve(n);for (size_t i size(); i <…

Kafka开发实录

前言 最近我总是在做大胆的事情&#xff0c;莫不是少年也需要冲冲冲&#xff0c;明明我不是这样的人啊&#xff0c;难不成这就是命运&#xff0c;来自命运石之门的选择&#xff01;废话不多说&#xff0c;本次是Kafka的实战篇&#xff0c;为什么这篇这么快呢&#xff1f;看了开…