springboot3.0自动配置

news/2024/10/20 21:00:10

目标

本文主要介绍springboot3.0是如何创建一个可以进行自动配置的jar包的

自动配置的定义是,一个jar包里面定义了一些spring的bean,当导入这个jar包的时候会自动将这些bean导入进去

方法

创建 AutoConfiguration.imports 文件

创建目录 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports

在该文件里面写入自动配置类的全限域名,例如:cn.hellozjf.game.pcr.common.CommonAutoConfiguration

创建自动配置类

代码内容如下:

package cn.hellozjf.game.pcr.common;import cn.hellozjf.game.pcr.common.config.WebDriverAutoConfiguration;
import cn.hellozjf.game.pcr.common.config.WebDriverConfig;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Import;@Import({WebDriverAutoConfiguration.class})
@EnableConfigurationProperties({WebDriverConfig.class})
public class CommonAutoConfiguration {}

其中,WebDriverAutoConfiguration 定义了自动配置时会导入的 bean,WebDriverConfig 定义了自动配置时需要读取的配置文件

WebDriverAutoConfiguration

这个类里面定义了各种需要导入的 bean

package cn.hellozjf.game.pcr.common.config;import cn.hellozjf.game.pcr.common.service.IWebDriverService;
import cn.hellozjf.game.pcr.common.service.WebDriverServiceImpl;
import lombok.AllArgsConstructor;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;@AllArgsConstructor
public class WebDriverAutoConfiguration {private final WebDriverConfig webDriverConfig;@Bean@ConditionalOnMissingBean(IWebDriverService.class)public IWebDriverService webDriverService() {return new WebDriverServiceImpl(webDriverConfig);}
}

如上面的代码所示,它会在构造的时候将 WebDriverConfig 配置信息全部导入进来,如果在初始化的时候发现没有定义 IWebDriverService 这个 bean,那么就会实例化这个 bean

WebDriverConfig

它的代码如下所示

package cn.hellozjf.game.pcr.common.config;import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "webdriver")
public class WebDriverConfig {private Boolean headless;private String proxy;private String driverKey;private String driverValue;
}

它对应配置文件中的内容如下

IWebDriverService

这是 bean 的定义基类,代码如下

package cn.hellozjf.game.pcr.common.service;import org.openqa.selenium.WebElement;
import org.springframework.beans.factory.InitializingBean;import java.util.List;/*** web浏览器操作服务*/
public interface IWebDriverService extends InitializingBean {/*** 初始化*/void init();/*** 退出浏览器*/void quit();/*** 执行 JS 脚本* @param script*/void executeScript(String script);/*** 通过执行 JS 脚本,获取网页元素* @param script* @return*/WebElement findByExecuteScript(String script);/*** 从网页元素中,通过 JS 脚本获取该元素里面的字符串数据* @param webElement* @param script* @return*/String getStrByExecuteScript(WebElement webElement, String script);/*** 根据 CSS 选择器查找网页元素* @param selector* @return*/List<WebElement> findByCssSelector(String selector);/*** 在某个网页元素下,根据 CSS 选择器查找网页元素* @param webElement* @param selector* @return*/List<WebElement> findByCssSelector(WebElement webElement, String selector);/*** 根据 ID 选择器查找网页元素* @param selector* @return*/List<WebElement> findByIdSelector(String selector);/*** 在某个网页元素下,根据 ID 选择器查找网页元素* @param webElement* @param selector* @return*/List<WebElement> findByIdSelector(WebElement webElement, String selector);/*** 根据标签查找网页元素* @param tag* @return*/List<WebElement> findByTag(String tag);/*** 打开网页* @param url*/void openUrl(String url);/*** 判断打开页面操作是否完成* @return*/boolean isOpenComplete();/*** 阻塞进程,直到页面元素出现,或者超过timeout秒* @param element* @param timeout*/void waitUntilElementExist(String element, int timeout);/*** 不需要实现 afterPropertiesSet(),我也不知道这有啥用,照着抄就对了* @throws Exception*/@Overridedefault void afterPropertiesSet() throws Exception {}
}

WebDriverServiceImpl

这是 IWebDriverService 的实现类,内容如下

package cn.hellozjf.game.pcr.common.service;import cn.hellozjf.game.pcr.common.config.WebDriverConfig;
import cn.hellozjf.game.pcr.common.util.OSUtil;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.openqa.selenium.By;
import org.openqa.selenium.JavascriptExecutor;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.WebElement;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.chrome.ChromeOptions;
import org.openqa.selenium.support.ui.ExpectedConditions;
import org.openqa.selenium.support.ui.WebDriverWait;
import org.springframework.util.StringUtils;import java.time.Duration;
import java.util.List;@Slf4j
@RequiredArgsConstructor
public class WebDriverServiceImpl implements IWebDriverService {private final WebDriverConfig webDriverConfig;private boolean bInit = false;private WebDriver driver;private JavascriptExecutor js;@Overridepublic void init() {if (bInit) {log.error("WebDriverService已经初始化");return;}// 设置 ChromeDriver 的路径System.setProperty(webDriverConfig.getDriverKey(), webDriverConfig.getDriverValue());ChromeOptions options = new ChromeOptions();// 获取 driver 和 js 变量if (StringUtils.hasLength(webDriverConfig.getProxy())) {// 说明需要走代理options.addArguments("--proxy-server=" + webDriverConfig.getProxy());}// 设置无界面if (webDriverConfig.getHeadless()) {options.addArguments("--headless");}if (OSUtil.isLinux()) {options.addArguments("--no-sandbox"); // 适用于Linux环境options.addArguments("--disable-dev-shm-usage"); // 适用于Linux环境}// 创建 WebDriver 实例driver = new ChromeDriver(options);js = (JavascriptExecutor) driver;bInit = true;}@Overridepublic void quit() {checkInit();driver.quit();bInit = false;}@Overridepublic void executeScript(String script) {checkInit();js.executeScript(script);}@Overridepublic WebElement findByExecuteScript(String script) {checkInit();return (WebElement) js.executeScript(script);}@Overridepublic String getStrByExecuteScript(WebElement webElement, String script) {return (String) js.executeScript(script, webElement);}@Overridepublic List<WebElement> findByCssSelector(String selector) {checkInit();List<WebElement> webElementList = driver.findElements(By.cssSelector(selector));return webElementList;}@Overridepublic List<WebElement> findByCssSelector(WebElement webElement, String selector) {// todo 为啥这里不用 checkInit?return webElement.findElements(By.cssSelector(selector));}@Overridepublic List<WebElement> findByIdSelector(String selector) {checkInit();List<WebElement> webElementList = driver.findElements(By.id(selector));return webElementList;}@Overridepublic List<WebElement> findByIdSelector(WebElement webElement, String selector) {// todo 为啥这里不用 checkInit?return webElement.findElements(By.id(selector));}@Overridepublic List<WebElement> findByTag(String tag) {checkInit();List<WebElement> webElementList = driver.findElements(By.tagName(tag));return webElementList;}@SneakyThrows@Overridepublic void openUrl(String url) {checkInit();// 打开网页driver.get(url);while (!isOpenComplete()) {// 页面还没有打开,等待 1 秒Thread.sleep(1000);}log.debug("open {} success", url);}@Overridepublic boolean isOpenComplete() {// 使用 JavaScript 检查页面加载状态,确保网页打开之后才执行后续的操作String readyState = (String) js.executeScript("return document.readyState");return "complete".equals(readyState);}@Overridepublic void waitUntilElementExist(String element, int timeout) {checkInit();WebDriverWait wait = new WebDriverWait(driver, Duration.ofSeconds(timeout));wait.until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector(element)));}private void checkInit() {if (!bInit) {throw new RuntimeException("WebDriverService还未初始化");}}
}

流程说明

当我在其他项目中导入了这个 jar

那么这个 jar 包里面的 META-INF/spring/AutoConfiguration.imports 就会被 spring 容器扫描到,然后就回去加载自动配置类CommonAutoConfiguration

因为CommonAutoConfigruation引用了WebDriverConfig,所以就会读取application.yml中的配置

因为CommonAutoConfiguration导入了WebDriverAutoConfiguration,所以就会加载WebDriverAutoConfiguration,并且创建出一个IWebDriverService的bean,这个bean的内容会根据配置进行初始化

最后其它项目就能获取到这个bean,并进行使用了

IWebDriverService webDriverService = SpringUtil.getBean(IWebDriverService.class);
webDriverService.init();

后话

本文是我在等待gradle下载依赖时候编写,依赖下载太耗时间了,等的我心很烦,所以本文写的也就意思一下

这个自动配置我是参考pigx实现的,有兴趣的读者还是研究pigx的源码更好,我的代码也就我自己的项目用用,写的对不对也不知道呢

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈,一经查实,立即删除!

相关文章

java 常见异常,及解决方案

异常体系图常见异常: 1、NullPointerException 空指针异常:访问一个空对象的属性或者方法时会出现 解决:提前进行判空处理 2、IOException IO流异常:IO,即:input, output,在读写磁盘文件、网络内容的时候经常会生的一种异常 解决:捕获 IOException 并处理或重新抛出 3、…

简单使用pyinstaller

pyinstaller介绍 PyInstaller 用于将 Python 程序打包成独立的可执行文件(EXE),以便于在没有 Python 环境的计算机上运行。 -F参数 -F 参数是 PyInstaller 的一个简写,用于生成单个可执行文件。它与 --onefile 参数的作用相同。当使用 -F 参数时,PyInstaller 会将所有依赖…

Codeforces Round 980 (Div. 2)

糖丸了,什么沟史比赛 A.Profitable Interest Rate初始有 \(a\) 个硬币,可以花费硬币开通盈利账户与非盈利账户开通盈利账户需要至少花费 \(b\) 个金币 开通非盈利账户没有限制 每在非盈利账户花费 \(x\) 元,盈利账户的限制 \(b\) 就减少 \(2x\) 元求最大的在盈利账户上的花费…

黑马JavaWeb-day01

Web:全球广域网,也称为万维网(www World Wide Web),能够通过浏览器访问的网站。 web网站的工作流程:网页由哪些部分组成:文字、图片、音频、视频、超链接 我们看到的网页背后的本质:前端代码 前端代码是如何转化成用户眼中的网页?:通过浏览器的解析和渲染转化成用户看到…

count(*)、count(1)哪个更快?面试必问:通宵整理的十道经典MySQL必问面试题

一、你是如何理解Count(*)和Count(1)的? 这两个并没有区别,不要觉得 count() 会查出全部字段,而 count(1) 不会。所以 count() 会更慢,你觉得 MySQL 作者会这么做吗? 可以很明确地告诉你们 count() 和 count(1) 是一样的,而正确有区别的是 count(字段)。如果你 count() 的…

重构案例:将纯HTML/JS项目迁移到Webpack

我们已经了解了许多关于 Webpack 的知识,但要完全熟练掌握它并非易事。一个很好的学习方法是通过实际项目练习。当我们对 Webpack 的配置有了足够的理解后,就可以尝试重构一些项目。本次我选择了一个纯HTML/JS的PC项目进行重构,项目位于 GitHub 上,非常感谢该项目的贡献者。…

最小体积拉取git仓库并保持可更新

对于超大型的git 仓库不需要提交只是拉取代码进行查看并希望保持代码更新,那么使用depth不仅能得到极小体积的仓库还能大大提速拉取时间对于超大型的git 仓库不需要提交只是拉取代码进行查看并希望保持代码更新,那么使用depth不仅能得到极小体积的仓库还能大大提速拉取时间 拉…

2024-2025-1 20241308 《计算机基础与程序设计》第四周学习总结

作业信息 这个作业属于哪个课程 https://edu.cnblogs.com/campus/besti/2024-2025-1-CFAP 这个作业要求在哪里 https://www.cnblogs.com/rocedu/p/9577842.html#WEEK04 这个作业的目标 <门电路 组合电路,逻辑电路 冯诺依曼结构 CPU,内存,IO管理 嵌入式系统,并行结构 物理…