spring-boot自动配置的原理及实现
我们在使用spring-boot的时候会发现这个框架用起来是真的非常的简单,我们只需要在它的一个名为application的外化配置文件中配一些私人化的属性,其他一些比较公共的配置都消失了,这其中就是spring-boot的自动配置功能在起作用。
当我们留意到spring-boot的依赖的时候我们会发现,spring本身支持的一些主流框架的的artifactId的名字一般叫spring-boot-starter-xxx,而一些spring-boot官方没做支持的一些框架为了能够使用spring-boot这个框架自身做了相关的支持,例如我们常用的持久层框架mybatis为了能在spring-boot里使用,本身就提供了一个叫mybatis-spring-boot-starter的依赖,这个共有的starter就是实现自动配置的关键。
我们在ssm框架中整合mybatis框架是如果你是使用的java配置类的方式来整合的话,需要配置数据源,和一个sqlSessionFactoryBean的这样一个bean,而到了spring-boot中则不再需要去配置相关的一些东西,并不是这些配置就消失了,而是说spring的自动配置帮你做了这些工作。下面本文会解释一下mybatis-plus的自动实现的过程,之后会提供自己写一个实现快递查询的的依赖和他的starter。
spring-boot 会扫描读取依赖中位于resources里的 META-INF/spring.factories文件,我们找到mybatis-plus-boot-starter的这个文件
点开之后我们会看到这样一个文件
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.baomidou.mybatisplus.autoconfigure.MybatisPlusAutoConfiguration
这个文件的的代码上面一行是由spring提供的,EnableAutoConfiguration,简单的翻译就是说能够自动配置的文件路径,后``面则是一个文件的全路径,接着点开
@Configuration
@ConditionalOnClass({SqlSessionFactory.class, SqlSessionFactoryBean.class})
@ConditionalOnSingleCandidate(DataSource.class)
@EnableConfigurationProperties({MybatisPlusProperties.class})
@AutoConfigureAfter({DataSourceAutoConfiguration.class})
public class MybatisPlusAutoConfiguration implements InitializingBean {private static final Logger logger = LoggerFactory.getLogger(MybatisPlusAutoConfiguration.class);private final MybatisPlusProperties 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;private final List<MybatisPlusPropertiesCustomizer> mybatisPlusPropertiesCustomizers;private final ApplicationContext applicationContext;
我们会看到这个类上的五个注解:
第一个是标注这个类是一个配置类,第二第三个注解的意思是spring中引用了里面的文件才会生成这个bean,第四个注解这是支出要引入的字段的位置,第五个注解是说在加载配置的类之后再加载当前类。接着我们点开第四个注解后面的文件
@ConfigurationProperties(prefix = "mybatis-plus"
)
public class MybatisPlusProperties {private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();private String configLocation;private String[] mapperLocations = new String[]{"classpath*:/mapper/**/*.xml"};private String typeAliasesPackage;private Class<?> typeAliasesSuperType;private String typeHandlersPackage;private boolean checkConfigLocation = false;private ExecutorType executorType;private Class<? extends LanguageDriver> defaultScriptingLanguageDriver;private Properties configurationProperties;
这个类里面只有一个注解标明了,这个类回去读取,外化配置文件中以什么开头的那些配置,这里是说这个类回去读取application.yml或者application.properties文件中以mybatis-plus开头的配置,这个类里面的字段大家看上去很眼熟了,就是我们ssm中集成mybatis需要配置的一些配置了,有的是写死的是因为spring有一个理念叫做约定优于配置,有些东西必须要放在那个地方,所以这些东西大家都一样,所以就不需要设置了,但有些东西,比如你连接数据库的一些url,root,password还有你自己建的项目结构各有不同,所以集中放在了application.yml或者application.properties文件中,这就是spring-boot的另一个特点,外化配置。最后我们看一下yml的配置
mybatis-plus:mapper-locations: classpath:mappers/**/*.xmlconfiguration:map-underscore-to-camel-case: truelog-impl: org.apache.ibatis.logging.slf4j.Slf4jImpltype-aliases-package: com.woniuxy.boot.mybatisplusdemo.model
这些以mybatis-plus:开头的配置就会被填入文件,这样才完成了对你的mybatis的集成。
下面是一个自己写一个能接入spring-boot的快递查询的项目,具体的细节就不多赘述,只是说让自己亲身体会一下这个过程的实现。
类似于spring-boot依赖mybatis-plus-boot-starter,mybatis-plus-boot-starter再依赖于mybatis-plus,这样的结构,我们先写一个kuaidiniao的项目安装到本地仓库,我们只需创建一个quickstart的mvn项目,无需添加任何依赖,只需写三个java类
package com.woniuxy.tool;public class ExprsTrackConfig {/*** 用户key*/private String userKey;/*** 用户密码*/private String userSecret;/*** 请求地址*/private String apiUrl;public String getUserKey() {return userKey;}public void setUserKey(String userKey) {this.userKey = userKey;}public String getUserSecret() {return userSecret;}public void setUserSecret(String userSecret) {this.userSecret = userSecret;}public String getApiUrl() {return apiUrl;}public void setApiUrl(String apiUrl) {this.apiUrl = apiUrl;}
}
package com.woniuxy.tool;import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.HashMap;
import java.util.Map;/**** 快递鸟物流轨迹即时查询接口** @技术QQ群: 456320272* @see: http://www.kdniao.com/YundanChaxunAPI.aspx* @copyright: 深圳市快金数据技术服务有限公司** DEMO中的电商ID与私钥仅限测试使用,正式环境请单独注册账号* 单日超过500单查询量,建议接入我方物流轨迹订阅推送接口** ID和Key请到官网申请:http://www.kdniao.com/ServiceApply.aspx*/
public class KuaiDiNiaoQueryAPI {//电商IDprivate String EBusinessID;//电商加密私钥,快递鸟提供,注意保管,不要泄漏private String AppKey;//请求urlprivate String ReqURL;public KuaiDiNiaoQueryAPI(ExprsTrackConfig config){this.EBusinessID=config.getUserKey();this.AppKey=config.getUserSecret();this.ReqURL=config.getApiUrl();}/*** Json方式 查询订单物流轨迹* @param expCode 物流公司的编码* @param expNo 物流号* @return 查询结果* @throws Exception*/public String getOrderTracesByJson(String expCode, String expNo) throws Exception{String requestData= "{'OrderCode':'','ShipperCode':'" + expCode + "','LogisticCode':'" + expNo + "'}";Map<String, String> params = new HashMap<String, String>();params.put("RequestData", urlEncoder(requestData, "UTF-8"));params.put("EBusinessID", EBusinessID);params.put("RequestType", "1002");String dataSign=encrypt(requestData, AppKey, "UTF-8");params.put("DataSign", urlEncoder(dataSign, "UTF-8"));params.put("DataType", "2");String result=sendPost(ReqURL, params);//根据公司业务处理返回的信息......return result;}/*** MD5加密* @param str 内容* @param charset 编码方式* @throws Exception*/@SuppressWarnings("unused")private String MD5(String str, String charset) throws Exception {MessageDigest md = MessageDigest.getInstance("MD5");md.update(str.getBytes(charset));byte[] result = md.digest();StringBuffer sb = new StringBuffer(32);for (int i = 0; i < result.length; i++) {int val = result[i] & 0xff;if (val <= 0xf) {sb.append("0");}sb.append(Integer.toHexString(val));}return sb.toString().toLowerCase();}/*** base64编码* @param str 内容* @param charset 编码方式* @throws UnsupportedEncodingException*/private String base64(String str, String charset) throws UnsupportedEncodingException {String encoded = base64Encode(str.getBytes(charset));return encoded;}@SuppressWarnings("unused")private String urlEncoder(String str, String charset) throws UnsupportedEncodingException{String result = URLEncoder.encode(str, charset);return result;}/*** 电商Sign签名生成* @param content 内容* @param keyValue Appkey* @param charset 编码方式* @throws UnsupportedEncodingException ,Exception* @return DataSign签名*/@SuppressWarnings("unused")private String encrypt (String content, String keyValue, String charset) throws UnsupportedEncodingException, Exception{if (keyValue != null){return base64(MD5(content + keyValue, charset), charset);}return base64(MD5(content, charset), charset);}/*** 向指定 URL 发送POST方法的请求* @param url 发送请求的 URL* @param params 请求的参数集合* @return 远程资源的响应结果*/@SuppressWarnings("unused")private String sendPost(String url, Map<String, String> params) {OutputStreamWriter out = null;BufferedReader in = null;StringBuilder result = new StringBuilder();try {URL realUrl = new URL(url);HttpURLConnection conn =(HttpURLConnection) realUrl.openConnection();// 发送POST请求必须设置如下两行conn.setDoOutput(true);conn.setDoInput(true);// POST方法conn.setRequestMethod("POST");// 设置通用的请求属性conn.setRequestProperty("accept", "*/*");conn.setRequestProperty("connection", "Keep-Alive");conn.setRequestProperty("user-agent","Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)");conn.setRequestProperty("Content-Type", "application/x-www-form-urlencoded");conn.connect();// 获取URLConnection对象对应的输出流out = new OutputStreamWriter(conn.getOutputStream(), "UTF-8");// 发送请求参数if (params != null) {StringBuilder param = new StringBuilder();for (Map.Entry<String, String> entry : params.entrySet()) {if(param.length()>0){param.append("&");}param.append(entry.getKey());param.append("=");param.append(entry.getValue());//System.out.println(entry.getKey()+":"+entry.getValue());}//System.out.println("param:"+param.toString());out.write(param.toString());}// flush输出流的缓冲out.flush();// 定义BufferedReader输入流来读取URL的响应in = new BufferedReader(new InputStreamReader(conn.getInputStream(), "UTF-8"));String line;while ((line = in.readLine()) != null) {result.append(line);}} catch (Exception e) {e.printStackTrace();}//使用finally块来关闭输出流、输入流finally{try{if(out!=null){out.close();}if(in!=null){in.close();}}catch(IOException ex){ex.printStackTrace();}}return result.toString();}private static char[] base64EncodeChars = new char[] {'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H','I', 'J', 'K', 'L', 'M', 'N', 'O', 'P','Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X','Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f','g', 'h', 'i', 'j', 'k', 'l', 'm', 'n','o', 'p', 'q', 'r', 's', 't', 'u', 'v','w', 'x', 'y', 'z', '0', '1', '2', '3','4', '5', '6', '7', '8', '9', '+', '/' };public static String base64Encode(byte[] data) {StringBuffer sb = new StringBuffer();int len = data.length;int i = 0;int b1, b2, b3;while (i < len) {b1 = data[i++] & 0xff;if (i == len){sb.append(base64EncodeChars[b1 >>> 2]);sb.append(base64EncodeChars[(b1 & 0x3) << 4]);sb.append("==");break;}b2 = data[i++] & 0xff;if (i == len){sb.append(base64EncodeChars[b1 >>> 2]);sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);sb.append("=");break;}b3 = data[i++] & 0xff;sb.append(base64EncodeChars[b1 >>> 2]);sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);sb.append(base64EncodeChars[b3 & 0x3f]);}return sb.toString();}
}
package com.woniuxy.tool;public enum ShipperEnum {SF("顺丰速运","SF"),HTKY("百世快递","HTKY"),ZTO("中通快递","ZTO"),STO("申通快递","STO"),YTO("圆通速递","YTO"),YD("韵达速递","YD"),EMS("EMS","EMS"),HHTT("天天快递","HHTT"),JD("京东快递","JD"),UC("优速快递","UC"),DBL("德邦快递","DBL"),ZJS("宅急送","ZJS");private String name;private String code;ShipperEnum(String name,String code){this.name=name;this.code=code;}}
这里是一些支持查询的快递公司。然后直接安装即可
然后写一个kuaidiniao-spring-boot-starter的项目
同样的是新建一个quickstart的mvn项目,这里需要导入一些spring-boot相关的依赖,才能使用spring-boot提供的注解,让自己的文件被扫描到,先贴依赖`
org.springframework.boot
spring-boot-starter
${spring-boot.version}
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-autoconfigure</artifactId><version>${spring-boot.version}</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><version>${spring-boot.version}</version><optional>true</optional></dependency><dependency><groupId>com.woniuxy.tool</groupId><artifactId>kuaidiniao</artifactId><version>1.0-SNAPSHOT</version></dependency>
`
最后一个是之前写的kuaidiniao的依赖也要导进来,参照mybatis-plus的做法,我们在先写两个java类
package com.woniuxy.tool.config;import com.woniuxy.tool.ExprsTrackConfig;
import com.woniuxy.tool.KuaiDiNiaoQueryAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;@Configuration//标记配置类
@EnableConfigurationProperties(KuaidiniaoProperties.class)//关联一个属性类
public class KuaidiniaoAutoConfiguration {//外化配置读入该配置属性类@Autowiredprivate KuaidiniaoProperties kuaidiniaoProperties;@Beanpublic KuaiDiNiaoQueryAPI kuaiDiNiaoQueryAPI(){ExprsTrackConfig config = new ExprsTrackConfig();config.setApiUrl(kuaidiniaoProperties.getApiUrl());config.setUserKey(kuaidiniaoProperties.getUserKey());config.setUserSecret(kuaidiniaoProperties.getUserSecret());KuaiDiNiaoQueryAPI api = new KuaiDiNiaoQueryAPI(config);return api;}}
package com.woniuxy.tool.config;import org.springframework.boot.context.properties.ConfigurationProperties;@ConfigurationProperties(prefix = "kuaidiniao")
public class KuaidiniaoProperties {/*** 用户key*/private String userKey;/*** 用户密码*/private String userSecret;/*** 请求地址*/private String apiUrl;public String getUserKey() {return userKey;}public void setUserKey(String userKey) {this.userKey = userKey;}public String getUserSecret() {return userSecret;}public void setUserSecret(String userSecret) {this.userSecret = userSecret;}public String getApiUrl() {return apiUrl;}public void setApiUrl(String apiUrl) {this.apiUrl = apiUrl;}
}
然后非常重要的一点,我们在resources里新建一个名为META-INF的文件夹,里面建一个spring.factories的文件写上我们之前看到的类似的代码,指向我们自己写的自动配置类
# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
com.woniuxy.tool.config.KuaidiniaoAutoConfiguration
这些写完之后,安装到本地即可。
最后新建一个spring-boot的项目,在application文件中写上kuaidiniao使用所需的url,user-key,user-secret
kuaidiniao:api-url: http://api.kdniao.com/Ebusiness/EbusinessOrderHandle.aspxuser-key: 1663user-secret: 0d253737-fc22-4064-87cd-
里面的key和secret都修改过,需要使用可以自己去网址申请http://www.kdniao.com/ServiceApply.aspx
然后调用即可
package com.woniuxy.boot.mybatisplusdemo.controller;import com.woniuxy.tool.KuaiDiNiaoQueryAPI;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;@RestController
public class KuaiDiNiaoTestController {@Autowiredprivate KuaiDiNiaoQueryAPI api;@GetMapping("/kuaidi")public String getKuaidi(String expCode,String expNo) throws Exception {return api.getOrderTracesByJson(expCode,expNo);}}
开服,按照之前的 SF(“顺丰速运”,“SF”),
HTKY(“百世快递”,“HTKY”),
ZTO(“中通快递”,“ZTO”),
STO(“申通快递”,“STO”),
YTO(“圆通速递”,“YTO”),
YD(“韵达速递”,“YD”),
EMS(“EMS”,“EMS”),
HHTT(“天天快递”,“HHTT”),
JD(“京东快递”,“JD”),
UC(“优速快递”,“UC”),
DBL(“德邦快递”,“DBL”),
ZJS(“宅急送”,“ZJS”);使用restfultool,即可完成测试。
spring-boot自动配置的原理及实现相关推荐
- springboot自动配置原理_今日份学习之Spring Boot自动配置实现原理
通过前面章节的学习,我们掌握了使用Spring Boot框架进行实际应用开发的方法.在使用Spring Boot 的过程中,我们时常会为一些看似简单,但实际上蕴藏了强大功能的实现而惊呼,下面就让我们来 ...
- Spring Boot 自动配置的原理、核心注解以及利用自动配置实现了自定义 Starter 组件
本章内容 自定义属性快速入门 外化配置 自动配置 自定义创建 Starter 组件 摘录:读书是读完这些文字还要好好用心去想想,写书也一样,做任何事也一样 图 2 第二章目录结构图 第 2 章 Spr ...
- Spring boot 自动配置工作原理
自动配置工作原理
- Spring Boot - 自动配置实现原理
文章目录 Pre @SpringBootApplication 注解 @ComponentScan 注解 @SpringBootConfiguration 注解 @EnableAutoConfigur ...
- Spring Boot自动配置原理
要了解Spring Boot的自动配置首先我需要先了解Spring Boot的两个机制,一个是配置文件如何进入到系统变成属性,二是如何将这些属性加入到容器中. 首先我们需要有一个组件,这个组件中的属性 ...
- Spring Boot自动配置原理分析
一.写在前面 随着时间的迁移Spring Boot 越来越多的出现在Java 后端程序员的视野中,Spring Boot 之所以会那么流行,很大的一个原因是自身集成了很多的Bean,简化了传统Srin ...
- 芋道 Spring Boot 自动配置原理
转载自 芋道 Spring Boot 自动配置原理 1. 概述 友情提示:因为本文是分享 Spring Boot 自动配置的原理,所以需要胖友有使用过 Spring Boot 的经验.如果还没使用过 ...
- Spring Boot - 自动配置实例解读
文章目录 Pre 启用 debug=true输出自动配置 HttpEncodingAutoConfiguration 什么情况下,Spring Boot 会自动装配 HttpEncodingAutoC ...
- Spring Boot 自动配置的 “魔法” 是如何实现的?
转载自 Spring Boot 自动配置的 "魔法" 是如何实现的? Spring Boot是Spring旗下众多的子项目之一,其理念是约定优于配置,它通过实现了自动配置(大多数 ...
- Spring Boot自动配置原理、实战
Spring Boot自动配置原理 Spring Boot的自动配置注解是@EnableAutoConfiguration, 从上面的@Import的类可以找到下面自动加载自动配置的映射. org.s ...
最新文章
- Relay IR表示
- 脚本1)启动jetty的脚本
- centos mate桌面_CentOS 7安装桌面汇总
- 全球及中国汽车涂料市场盈利预测与发展策略分析报告2022版
- 百度地图api公交路线,IE下跳转百度地图后中文变成乱码的解决办法
- CSS 基础入门语法
- linux 变量c file代表的内容.,LinuxC编程基础--mak.ppt
- Matlab Tricks(二十八)—— 笛卡尔积的实现
- 如何降低BI系统建设的风险
- python web框架【补充】自定义web框架
- 如何打造自动驾驶的数据闭环
- matlab能替代几何画板吗,比几何画板更强大的工具软件GeoGebra,数学老师值得拥有...
- 重庆计算机c语言二级成绩查询,历届重庆市计算机C语言二级考试试题及答案.pdf...
- kux格式怎么转换成mp3_kux格式怎么转换成mp4?快速转换格式的方法
- 包含WebRoot的Web工程在Eclipse中的搭建和配置
- 计算机如何取消自动关机,电脑怎么设置自动关机及取消自动关机
- glassfish java环境_CentOS安装JDK和安装Glassfish
- 最新 --》》如何推销自己
- 计算机自动关机启机唤醒设置,电脑在哪设置定时关机(如何设置电脑的自动关机和自动开机)...
- excel数据表转成insert语句插入数据库