springboot starter工作原理_springboot基础知识集结,你get到了吗
导读
首发于公众号:JAVA大贼船,原创不易,喜欢的读者可以关注一下哦!一个分享java学习资源,实战经验和技术文章的公众号!
一、SpringBoot的特点
Spring Boot 主要目标是:
- 为所有 Spring 的开发者提供一个非常快速的、广泛接受的入门体验
- 开箱即用(启动器starter-其实就是SpringBoot提供的一个jar包),但通过自己设置参数(.properties),即可快速摆脱这种方式。
- 提供了一些大型项目中常见的非功能性特性,如内嵌服务器、安全、指标,健康检测、外部化配置等
- 绝对没有代码生成,也无需 XML 配置。
更多细节,可以到官网查看。
二、 SpringBoot的核心功能
- 起步依赖
起步依赖本质上是一个Maven项目对象模型(Project Object Model,POM),定义了对其他库的传递依赖,这些东西加在一起即支持某项功能。
简单的说,起步依赖就是将具备某种功能的坐标打包到一起,并提供一些默认的功能。 - 自动配置
Spring Boot的自动配置是一个运行时(更准确地说,是应用程序启动时)的过程,考虑了众多因素,才决定Spring配置应该用哪个,不该用哪个。该过程是Spring自动完成的。
三、SpringBoot原理分析
起步依赖原理分析
分析spring-boot-starter-parent
按住Ctrl点击pom.xml中的spring-boot-starter-parent,跳转到了spring-boot-starter-parent的pom.xml,xml配置如下(只摘抄了部分重点配置):
<parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-dependencies</artifactId><version>2.2.2.RELEASE</version><relativePath>../../spring-boot-dependencies</relativePath></parent>
按住Ctrl点击pom.xml中的spring-boot-starter-dependencies,跳转到了spring-boot-starter-dependencies的pom.xml,xml配置如下(只摘抄了部分重点配置):
<properties><activemq.version>5.15.11</activemq.version><antlr2.version>2.7.7</antlr2.version><appengine-sdk.version>1.9.77</appengine-sdk.version><artemis.version>2.10.1</artemis.version><aspectj.version>1.9.5</aspectj.version><assertj.version>3.13.2</assertj.version><atomikos.version>4.0.6</atomikos.version><awaitility.version>4.0.1</awaitility.version><bitronix.version>2.1.4</bitronix.version><build-helper-maven-plugin.version>3.0.0</build-helper-maven-plugin.version>... ... ...
</properties><dependencyManagement><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot</artifactId><version>2.2.2.RELEASE</version></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-test</artifactId><version>2.2.2.RELEASE</version></dependency>... ... ...</dependencies>
</dependencyManagement><build><pluginManagement><plugins><plugin><groupId>org.apache.johnzon</groupId><artifactId>johnzon-maven-plugin</artifactId><version>${johnzon.version}</version></plugin><plugin><groupId>org.jetbrains.kotlin</groupId><artifactId>kotlin-maven-plugin</artifactId><version>${kotlin.version}</version></plugin>... ... ...</plugins></pluginManagement>
</build>
从上面的spring-boot-starter-dependencies的pom.xml中可以发现,一部分坐标的版本、依赖管理、插件管理已经定义好,所以我们的SpringBoot工程继承spring-boot-starter-parent后已经具备版本锁定等配置了。所以起步依赖的作用就是进行依赖的传递。spring-boot-starter-web分析源码也是一样,可自行查看
四、自动配置原理解析
按住Ctrl点击查看启动类MySpringBootApplication上的注解@SpringBootApplication
@SpringBootApplication
public class TestApplication {public static void main(String[] args) {SpringApplication.run(TestApplication.class);}
}
@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 {.....
}
- @SpringBootConfiguration:等同与@Configuration,既标注该类是Spring的一个配置类
- @EnableAutoConfiguration:SpringBoot自动配置功能开启
@EnableAutoConfiguration源码
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@AutoConfigurationPackage
@Import(AutoConfigurationImportSelector.class)
public @interface EnableAutoConfiguration {... ... ...
}
- @Import(AutoConfigurationImportSelector.class) 导入了AutoConfigurationImportSelector类
按住Ctrl点击查看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 List<String> getCandidateConfigurations(AnnotationMetadata metadata, AnnotationAttributes attributes) {List<String> configurations = SpringFactoriesLoader.loadFactoryNames(getSpringFactoriesLoaderFactoryClass(),getBeanClassLoader());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;}
其中,**SpringFactoriesLoader.loadFactoryNames **方法的作用就是从META-INF/spring.factories文件中读取指定类对应的类名称列表
![image-20200702165539519](../so
![](/assets/blank.gif)
spring.factories 文件中有关自动配置的配置信息如下:
... ... ...# Auto Configure
org.springframework.boot.autoconfigure.EnableAutoConfiguration=
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,
org.springframework.boot.autoconfigure.amqp.RabbitAutoConfiguration,
org.springframework.boot.autoconfigure.batch.BatchAutoConfiguration,
org.springframework.boot.autoconfigure.cache.CacheAutoConfiguration,
org.springframework.boot.autoconfigure.cassandra.CassandraAutoConfiguration,
org.springframework.boot.autoconfigure.cloud.CloudServiceConnectorsAutoConfiguration,... ... ...
上面配置文件存在大量的以Configuration为结尾的类名称,这些类就是存有自动配置信息的类,而SpringApplication在获取这些类名后再加载
- 源码示例
以ServletWebServerFactoryAutoConfiguration为例来分析源码:
//声明这个类是一个配置类
@Configuration(proxyBeanMethods = false)
@AutoConfigureOrder(Ordered.HIGHEST_PRECEDENCE)
//判断你是否引入了相关依赖,引入依赖后该条件成立,当前类的配置才会生效
@ConditionalOnClass(ServletRequest.class)
//满足项目的类是是Type.SERVLET类型,也就是一个普通web工程
@ConditionalOnWebApplication(type = Type.SERVLET)
@EnableConfigurationProperties(ServerProperties.class)
@Import({ ServletWebServerFactoryAutoConfiguration.BeanPostProcessorsRegistrar.class,ServletWebServerFactoryConfiguration.EmbeddedTomcat.class,ServletWebServerFactoryConfiguration.EmbeddedJetty.class,ServletWebServerFactoryConfiguration.EmbeddedUndertow.class })
public class ServletWebServerFactoryAutoConfiguration {... ... ...
}
@EnableConfigurationProperties(ServerProperties.class) 代表加载ServerProperties服务器配置属性类
进入ServerProperties.class源码如下:
@ConfigurationProperties(prefix = "server", ignoreUnknownFields = true)
public class ServerProperties {/*** Server HTTP port.*/private Integer port;/*** Network address to which the server should bind.*/private InetAddress address;... ... ...}
prefix = "server" 表示SpringBoot配置文件中的前缀,SpringBoot会将配置文件中以server开始的属性映射到该类的字段中。
@ComponentScan
源码翻译:
配置组件扫描的指令。提供了类似与
<context:component-scan>
标签的作用
通过basePackageClasses或者basePackages属性来指定要扫描的包。如果没有指定这些属性,那么将从声明这个注解的类所在的包开始,扫描包及子包
而@SpringBootApplication注解声明的类就是main函数所在的启动类,因此扫描的包是该类所在包及其子包。因此,一般启动类会放在一个比较前的包目录中。
五、SpringBoot的配置文件
SpringBoot是基于约定的,所以很多配置都有默认值,但如果想使用自己的配置替换默认配置的话,就可以使用application.properties或者application.yml(application.yaml)进行配置。SpringBoot默认会从Resources目录下加载application.properties或application.yml(application.yaml)文件。
application.yml配置文件
语法示例
普通数据:
- 语法: key: value
- 示例代码:
- name: test
- 注意:value之前有一个空格
对象数据:
- 语法:
key:
key1: value1
key2: value2
或者:
key: {key1: value1,key2: value2} - 示例代码:
- person:
name: test
age: 18
addr: shenzhen#或者
person: {name: test,age: 18,addr: shenzhen} - 注意:key1前面的空格个数不限定,在yml语法中,相同缩进代表同一个级别
Map数据 :
同上面的对象写法
数组(List、Set)数据:
- 语法:
key:
- value1
- value2
或者:
key: [value1,value2] - 示例代码:
- city:
- shenzhen
- shanghai
- shandong
- chongqing#或者
city: [shenzhen,shanghai,shandong,chongqing]#集合中的元素是对象形式
student:
- name: zhangsan
age: 18
score: 100
- name: lisi
age: 28
score: 88
- name: wangwu
age: 38
score: 90 - 注意:value1与之间的 - 之间存在一个空格
SpringBoot多环境配置
在实际开发的过程中,项目会经历很多的阶段(开发->测试->上线),每个阶段的配置也会不同,例如:端口、上下文根、数据库等,那么这个时候为了方便在不同的环境之间切换,SpringBoot提供了多环境配置,简单示例如下:
application-dev.properties
#开发环境#设置内嵌Tomcat默认端口号
server.port=8080
application-product.properties
#生产环境#配置内嵌Tomcat默认端口号
server.port=80
application-test.properties
#测试环境#配置内嵌Tomcat端口号
server.port=8081
● 在总配置文件application.properties进行环境的激活
#SpringBoot的总配置文件#激活开发环境
#spring.profiles.active=dev#激活测试环境
#spring.profiles.active=test#激活生产环境
spring.profiles.active=product
六、 SpringBoot配置信息的查询
SpringBoot的官方文档:https://docs.spring.io/spring-boot/docs/2.0.1.RELEASE/reference/htmlsingle/#common-application-properties
例如:
# EMBEDDED SERVER CONFIGURATION (ServerProperties)
server.port=8080 # Server HTTP port.
server.servlet.context-path= # Context path of the application.
server.servlet.path=/ # Path of the main dispatcher servlet.
那么可以通过配置application.poperties 或者 application.yml 来修改SpringBoot的默认配置
例如:
application.yml文件
server:port: 6666
七、springboot读取配置文件方式
@PropertySource配合@value使用
引入Druid连接池依赖:
<dependency><groupId>com.alibaba</groupId><artifactId>druid</artifactId><version>1.1.6</version>
</dependency>
创建一个jdbc.properties文件,编写jdbc属性:
jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/test
jdbc.username=root
jdbc.password=root
然后编写代码:
@Configuration
@PropertySource("classpath:jdbc.properties")
public class JdbcConfig {@Value("${jdbc.url}")String url;@Value("${jdbc.driverClassName}")String driverClassName;@Value("${jdbc.username}")String username;@Value("${jdbc.password}")String password;@Beanpublic DataSource dataSource() {DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(url);dataSource.setDriverClassName(driverClassName);dataSource.setUsername(username);dataSource.setPassword(password);return dataSource;}
}
解读:
@Configuration
:声明我们JdbcConfig
是一个配置类@PropertySource
:指定属性文件的路径是:classpath:jdbc.properties
若此例jdbc的属性放在application.yml,那么可以不使用@PropertySource
,@Value
默认读取;- 通过
@Value
为属性注入值 - 通过@Bean将
dataSource()
方法声明为一个注册Bean的方法,Spring会自动调用该方法,将方法的返回值加入Spring容器中。
@ConfigurationProperties使用
在上面的案例中,我们实验了java配置方式。不过属性注入使用的是@Value注解。这种方式虽然可行,但是不够强大,因为它只能注入基本类型值。
在SpringBoot中,提供了一种新的属性注入方式,支持各种java基本数据类型及复杂类型的注入。
新建一个类,用来进行属性注入:
@ConfigurationProperties(prefix = "jdbc")
public class JdbcProperties {private String url;private String driverClassName;private String username;private String password;// ... 略// getters 和 setters
}
- 在类上通过@ConfigurationProperties注解声明当前类为属性读取类
prefix="jdbc"
读取属性文件中,前缀为jdbc的值。- 在类上定义各个属性,名称必须与属性文件中
jdbc.
后面部分一致 - 需要注意的是,这里并没有指定属性文件的地址,所以我们需要把jdbc.properties名称改为application.properties,这是SpringBoot默认读取的属性文件名:
在JdbcConfig中使用这个属性:
@Configuration
@EnableConfigurationProperties(JdbcProperties.class)
public class JdbcConfig {//@Autowired注入//private JdbcProperties prop;//构造函数注入//private JdbcProperties prop;//public JdbcConfig(Jdbcproperties prop){//this.prop = prop;}//声明有@Bean的方法参数注入@Beanpublic DataSource dataSource(JdbcProperties jdbc) {DruidDataSource dataSource = new DruidDataSource();dataSource.setUrl(jdbc.getUrl());dataSource.setDriverClassName(jdbc.getDriverClassName());dataSource.setUsername(jdbc.getUsername());dataSource.setPassword(jdbc.getPassword());return dataSource;}
}
- 通过
@EnableConfigurationProperties(JdbcProperties.class)
来声明要使用JdbcProperties
这个类的对象 - 然后使用@Autowired注入或构造函数注入或声明有@Bean的方法参数注入
@ConfigurationProperties更优雅的注入
如果一些属性只有一个Bean需要使用,那就无需将其注入到一个类(JdbcProperties)中。而是直接在需要的地方声明即可:
@Configuration
public class JdbcConfig {@Bean// 声明要注入的属性前缀,SpringBoot会自动把相关属性通过set方法注入到DataSource中,前提是该类必须有对应属性的set方法!@ConfigurationProperties(prefix = "jdbc")public DataSource dataSource() {DruidDataSource dataSource = new DruidDataSource();return dataSource;}
}
直接把@ConfigurationProperties(prefix = "jdbc")
声明在需要使用的@Bean
的方法上,然后SpringBoot就会自动调用这个Bean(此处是DataSource)的set方法,然后完成注入。使用的前提是:该类必须有对应属性的set方法!
八、SpringBoot事务管理
SpringBoot 使用事务非常简单,底层依然采用的是Spring本身提供的事务管理
• 在入口类中使用注解 @EnableTransactionManagement 开启事务支持
• 在访问数据库的Service方法上添加注解 @Transactional 即可
例如
@SpringBootApplication
@EnableTransactionManagement //SpringBoot开启事务的支持
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}@Override
@Transactional //添加此注解说明该方法添加的事务管理
public int update(Student student) {int updateCount = studentMapper.updateByPrimaryKeySelective(student);System.out.println("更新结果:" + updateCount);//在此构造一个除数为0的异常,测试事务是否起作用int a = 10/0;return updateCount;
}
九、SpringBoot打包方式
SpringBoot打war包部署
1.程序入口类需扩展继承 SpringBootServletInitializer类并覆盖configure方法(这是使用外置tomcat打包)
@SpringBootApplication
public class Application extends SpringBootServletInitializer{public static void main(String[] args) {SpringApplication.run(Application.class, args);}@Overrideprotected SpringApplicationBuilder configure(SpringApplicationBuilder builder) {
//参数为当前Spring Boot启动类Application.classreturn builder.sources(Application.class);}
}
2.在 pom.xml中添加(修改)打包方式为war
<packaging>war</packaging>
3.在 pom.xml中配置springboot打包的插件(默认自动加)
<!--SpringBoot 的打包插件-->
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
4.在pom.xml中配置将配置文件编译到类路径
<!--mybatis的mapper.xml--><resource><directory>src/main/java</directory><includes><include>**/*.xml</include></includes></resource><!--src/main/resources下的所有配置文件编译到classes下面去--><resource><directory>src/main/resources</directory><includes><include>**/*.*</include></includes></resource><resource><!--源文件位置--><directory>src/main/webapp</directory><!--编译到META-INF/resources,该目录不能随便写--><targetPath>META-INF/resources</targetPath><includes><!--要把哪些文件编译过去,**表示webapp目录及子目录,*.*表示所有--><include>**/*.*</include></includes></resource>
5.在pom.xml的build标签下通过finalName指定打war包的名字
<!--指定打war包的名字-->
<finalName>JavaDemo-springboot-war</finalName>
6.通过Maven package命令打war包到target目录下
![](/assets/blank.gif)
![](/assets/blank.gif)
7、将target目录下生成的war包拷贝到tomcat的webapps目录,并启动tomcat,大功告成!
SpringBoot打Jar包部署
1.在 pom.xml中添加(修改)打包方式为war
<packaging>war</packaging>
2.在 pom.xml中配置springboot打包的插件(默认自动加)
<!--SpringBoot 的打包插件-->
<plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
3、通过maven- package命令打包
4、通过java -jar jar包名称命令运行
十、定时任务@Scheduled注解使用
cron表达式语法
[秒] [分] [小时] [日] [月] [周] [年]
注:[年]不是必须的域,可以省略[年],则一共6个域
![](/assets/blank.gif)
通配符说明:
*
表示所有值。 例如:在分的字段上设置 *,表示每一分钟都会触发。?
表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的10号触发一个操作,但不关心是周几,所以需要周位置的那个字段设置为”?” 具体设置为 0 0 0 10 * ?-
表示区间。例如 在小时上设置 “10-12”,表示 10,11,12点都会触发。,
表示指定多个值,例如在周字段上设置 “MON,WED,FRI” 表示周一,周三和周五触发/
用于递增触发。如在秒上面设置”5/15” 表示从5秒开始,每增15秒触发(5,20,35,50)。 在月字段上设置’1/3’所示每月1号开始,每隔三天触发一次。L
表示最后的意思。在日字段设置上,表示当月的最后一天(依据当前月份,如果是二月还会依据是否是润年[leap]), 在周字段上表示星期六,相当于”7”或”SAT”。如果在”L”前加上数字,则表示该数据的最后一个。例如在周字段上设置”6L”这样的格式,则表示“本月最后一个星期五”W
表示离指定日期的最近那个工作日(周一至周五). 例如在日字段上置”15W”,表示离每月15号最近的那个工作日触发。如果15号正好是周六,则找最近的周五(14号)触发, 如果15号是周未,则找最近的下周一(16号)触发.如果15号正好在工作日(周一至周五),则就在该天触发。如果指定格式为 “1W”,它则表示每月1号往后最近的工作日触发。如果1号正是周六,则将在3号下周一触发。(注,”W”前只能设置具体的数字,不允许区间”-“)。#
序号(表示每月的第几个周几),例如在周字段上设置”6#3”表示在每月的第三个周六.注意如果指定”#5”,正好第五周没有周六,则不会触发该配置(用在母亲节和父亲节再合适不过了) ;小提示:’L’和 ‘W’可以一组合使用。如果在日字段上设置”LW”,则表示在本月的最后一个工作日触发;周字段的设置,若使用英文字母是不区分大小写的,即MON与mon相同。
示例
在启动类开启计划任务
@EnableScheduling//开启计划任务 表达式参考http://cron.qqe2.com/
public class Application {public static void main(String[] args) {SpringApplication.run(Application.class, args);}}
服务类
//@PostConstruct该注解被用来修饰一个非静态的void()方法。被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次。PostConstruct在构造函数之后执行,init()方法之前执行。
//该注解的方法在整个Bean初始化中的执行顺序:
//Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)@PostConstruct@Overridepublic void init() {initAccessToken();}/*** 初始化AccessToken 一小时执行一次*/@Scheduled(cron = "0 0 0/1 * * ?")@Overridepublic void initAccessToken() {log.error("<====初始化 AccessToken 一分钟一次 !==>");try {WxParament.ACCESS_TOKEN = GetToken.getAccessToken(ymlParament.getH_app_id(), ymlParament.getH_app_secret());} catch (Exception e) {log.error("<====initAccessToken初始化失败!==>" + e);e.printStackTrace();}log.info("<====初始化initAccessToken成功,值为==>" + WxParament.ACCESS_TOKEN);}
springboot starter工作原理_springboot基础知识集结,你get到了吗相关推荐
- springboot starter工作原理_98,谈谈SpringBoot的工作原理
对技术的探索,一切源于好奇心,保持好奇心,才能让人更年轻. 至今,我们已经有了很多创建SpringBoot项目的经验,比如我们要创建一个支持web开发的项目,我们只需要引入web-starter模块即 ...
- (超详细)MapReduce工作原理及基础编程
MapReduce工作原理及基础编程(代码见文章后半部分) JunLeon--go big or go home 目录 MapReduce工作原理及基础编程(代码见文章后半部分) 一.MapReduc ...
- 数字信号处理(FIR滤波器的设计与原理及基础知识)
FIR滤波器的设计与原理及基础知识 有限长单位脉冲响应(FIR)滤波器的设计方法 线性相位FIR滤波器的特点: 幅度特性: 窗函数设计法 窗口函数对理想特性的影响: 梳状滤波器 有限长单位脉冲响应(F ...
- html5的基本工作原理,HTML5基础开发教程
HTML5基础开发教程 编辑 锁定 讨论 上传视频 <HTML5基础开发教程 >是2013年5月 出版的图书.主要面向高等院校学生,以及没有开发经验或者仅有少量程序设计基础的读者,因此书中 ...
- 跳帧的计算机原理,光电鼠标基础知识浅解(22页)-原创力文档
光电鼠标基础知识浅解(1) 内容概要 关键词:光电 鼠标 导言:介绍光电鼠标工作的基本原理及构成部件,作一般性知识了解 光电鼠标的工作原理与参数 光电鼠标的内部构成 光电鼠标的外部设计 讨论 与传统的 ...
- 调试器工作原理之一——基础篇
转自 http://blog.csdn.net/gqb_driver/article/details/13988001 英文原文:Eli Bendersky 翻译:伯乐在线- 陈舸 本文是一系列探究 ...
- 计算机原理寄存器基础知识,微机原理——基础知识及计算机基本组成
微机原理基础 期末复习要求 理解Bit byte word doubleword 等基本概念 计算机常用的数制和编码 十进制.二进制.十六进制的运算和转换 常用的ASCII码:数字.大小写英文字母的A ...
- 计算机原理---网络基础知识
路由器 路由器(Router)是连接因特网中各局域网.广域网的设备,是互联网的主要结点设备.它会根据信道的情况自动选择和设定路由,以最佳路径,按前后顺序发送信号.路由器通过路由决定数据的转发.转发策略 ...
- 计算机打字工作内容,计算机基础知识打字入门
<计算机基础知识打字入门>由会员分享,可在线阅读,更多相关<计算机基础知识打字入门(1页珍藏版)>请在人人文库网上搜索. 1.计算机基础打字入门对于初学者而言,其实应该把打字作 ...
最新文章
- c语言多线程转python多线程,真正的python 多线程!一个修饰符让你的多线程和C语言一样快...
- 《设计模式之禅》学习笔记(一)
- BZOJ3577 : 玩手机
- 正则表达式入门之使用元字符
- django orm_Django ORM简介
- 组装r730服务器,戴尔poweredge r730服务器配置及系统安装详解教程
- 【转】Delphi实现自动发贴和识别验证码 王泽宾
- ESP8266-01/01S配对阿里云生活物联网教程(超详细)
- 自制hdmi线一头改vga图_VGA连接线接口定义及引线焊接教程,VGA线不够长时可用网线代替?...
- 深度步态识别综述(二)
- 保险合同中的“不可抗辩条款”
- python百度地图热力图_利用百度地图API绘制微信好友分布热力图
- 2018铁三测评题write以及一些想送给你们的话
- 如何为word增加页码,且第一页不显示页码?
- 微软 bing 壁纸 每日一图 bing api
- excel 中vb组合框_在Excel 2010中修复组合框大小调整
- 中国人保为中环盛达环保科技集团承保产品责任险,为消费者保驾护航
- lol进入服务器后显示3秒白屏,LOL英雄联盟游戏大厅出现白屏的完美解决方法
- electron 打包后找不到module问题
- 友好城市(线性dp)
热门文章
- PC如何接管手机的双因子身份验证 靠的是英特尔的CPU
- tutorial_coreos 01-01-install 2015-05-27
- 搭建 Hadoop2.7.2 + Spark1.6环境
- Cisco 交换机密码重置步骤
- 在AD中批量添加多个用户帐号
- 了解***的初级阶段---网络信息探测技巧
- MySQL TEXT数据类型的最大长度
- sql,两个表关联,根据B表更新A表
- 无线网sdn服务器,什么是SDN,SDN网络与传统网络对比
- 高考 | 满分作文:《我们都是读“书”人》