导读

首发于公众号: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

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目录下

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个域

通配符说明:

  • * 表示所有值。 例如:在分的字段上设置 *,表示每一分钟都会触发。
  • ? 表示不指定值。使用的场景为不需要关心当前设置这个字段的值。例如:要在每月的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到了吗相关推荐

  1. springboot starter工作原理_98,谈谈SpringBoot的工作原理

    对技术的探索,一切源于好奇心,保持好奇心,才能让人更年轻. 至今,我们已经有了很多创建SpringBoot项目的经验,比如我们要创建一个支持web开发的项目,我们只需要引入web-starter模块即 ...

  2. (超详细)MapReduce工作原理及基础编程

    MapReduce工作原理及基础编程(代码见文章后半部分) JunLeon--go big or go home 目录 MapReduce工作原理及基础编程(代码见文章后半部分) 一.MapReduc ...

  3. 数字信号处理(FIR滤波器的设计与原理及基础知识)

    FIR滤波器的设计与原理及基础知识 有限长单位脉冲响应(FIR)滤波器的设计方法 线性相位FIR滤波器的特点: 幅度特性: 窗函数设计法 窗口函数对理想特性的影响: 梳状滤波器 有限长单位脉冲响应(F ...

  4. html5的基本工作原理,HTML5基础开发教程

    HTML5基础开发教程 编辑 锁定 讨论 上传视频 <HTML5基础开发教程 >是2013年5月 出版的图书.主要面向高等院校学生,以及没有开发经验或者仅有少量程序设计基础的读者,因此书中 ...

  5. 跳帧的计算机原理,光电鼠标基础知识浅解(22页)-原创力文档

    光电鼠标基础知识浅解(1) 内容概要 关键词:光电 鼠标 导言:介绍光电鼠标工作的基本原理及构成部件,作一般性知识了解 光电鼠标的工作原理与参数 光电鼠标的内部构成 光电鼠标的外部设计 讨论 与传统的 ...

  6. 调试器工作原理之一——基础篇

    转自 http://blog.csdn.net/gqb_driver/article/details/13988001 英文原文:Eli Bendersky  翻译:伯乐在线- 陈舸 本文是一系列探究 ...

  7. 计算机原理寄存器基础知识,微机原理——基础知识及计算机基本组成

    微机原理基础 期末复习要求 理解Bit byte word doubleword 等基本概念 计算机常用的数制和编码 十进制.二进制.十六进制的运算和转换 常用的ASCII码:数字.大小写英文字母的A ...

  8. 计算机原理---网络基础知识

    路由器 路由器(Router)是连接因特网中各局域网.广域网的设备,是互联网的主要结点设备.它会根据信道的情况自动选择和设定路由,以最佳路径,按前后顺序发送信号.路由器通过路由决定数据的转发.转发策略 ...

  9. 计算机打字工作内容,计算机基础知识打字入门

    <计算机基础知识打字入门>由会员分享,可在线阅读,更多相关<计算机基础知识打字入门(1页珍藏版)>请在人人文库网上搜索. 1.计算机基础打字入门对于初学者而言,其实应该把打字作 ...

最新文章

  1. c语言多线程转python多线程,真正的python 多线程!一个修饰符让你的多线程和C语言一样快...
  2. 《设计模式之禅》学习笔记(一)
  3. BZOJ3577 : 玩手机
  4. 正则表达式入门之使用元字符
  5. django orm_Django ORM简介
  6. 组装r730服务器,戴尔poweredge r730服务器配置及系统安装详解教程
  7. 【转】Delphi实现自动发贴和识别验证码 王泽宾
  8. ESP8266-01/01S配对阿里云生活物联网教程(超详细)
  9. 自制hdmi线一头改vga图_VGA连接线接口定义及引线焊接教程,VGA线不够长时可用网线代替?...
  10. 深度步态识别综述(二)
  11. 保险合同中的“不可抗辩条款”
  12. python百度地图热力图_利用百度地图API绘制微信好友分布热力图
  13. 2018铁三测评题write以及一些想送给你们的话
  14. 如何为word增加页码,且第一页不显示页码?
  15. 微软 bing 壁纸 每日一图 bing api
  16. excel 中vb组合框_在Excel 2010中修复组合框大小调整
  17. 中国人保为中环盛达环保科技集团承保产品责任险,为消费者保驾护航
  18. lol进入服务器后显示3秒白屏,LOL英雄联盟游戏大厅出现白屏的完美解决方法
  19. electron 打包后找不到module问题
  20. 友好城市(线性dp)

热门文章

  1. PC如何接管手机的双因子身份验证 靠的是英特尔的CPU
  2. tutorial_coreos 01-01-install 2015-05-27
  3. 搭建 Hadoop2.7.2 + Spark1.6环境
  4. Cisco 交换机密码重置步骤
  5. 在AD中批量添加多个用户帐号
  6. 了解***的初级阶段---网络信息探测技巧
  7. MySQL TEXT数据类型的最大长度
  8. sql,两个表关联,根据B表更新A表
  9. 无线网sdn服务器,什么是SDN,SDN网络与传统网络对比
  10. 高考 | 满分作文:《我们都是读“书”人》