MyBatis笔记二:配置

MyBatis笔记二:配置

1.全局配置

1.properites

这个配置主要是引入我们的 properites 配置文件的:

1
2
3
4
5
6
7
8
9
10
11
12
13
<properties resource="db.properties"/>

<environments default="development">
<environment id="development">
<transactionManager type="JDBC"/>
<dataSource type="POOLED">
<property name="driver" value="${driver}"/>
<property name="url" value="${url}"/>
<property name="username" value="${username}"/>
<property name="password" value="${password}"/>
</dataSource>
</environment>
</environments>

可以看到我们使用 <properties resource="db.properties"/> 引入了我们的数据据库的配置文件,然后这个标签有两个属性 : resourceuri 第一种直接是引用项目下的文件。第二个就是引用网络路径的和我们本地文件系统的资源。

Read More

MyBatis笔记一:GettingStart

MyBatis笔记一:GettingStart

1.MyBatis优点

image

我们的工具和各种框架的作用就是为了我们操作数据库简洁,对于一些数据库的工具能帮我们少写一些处理异常等等的代码,但是他们并不是自动化的,很多的操作还是需要我们自己进行,所以我们的框架就帮我们把中间黑色的部分封装起来了,减少我们的负担,但是SQL也是重中之重,我们需要把这些东西自己来控制就有 MyBatis 这个半自动框架,以及我们需要学习更多的关于 HQL 的内容。

Read More

SpringCloud:Eureka服务注册与发现

SpringCloud:Eureka服务注册与发现

Eureka 其实就是一个 服务注册与发现的中心,也就是相当于我们前面做的一些生产者的服务需要注册到我们的注册中心,那么我们的消费者就不用把代码写死,而是可以去服务中心订阅对应的服务,获取服务的最新地址,并且进行逻辑解耦。

说的更简单一点它就相当于我们的 Dubbo 中的zookeeper 的功能就是用来服务发现的和注册的。他是一个CS架构的一个应用,也就是我们会有客户端和服务端,接下来就准备使用这个服务注册中心。

image

那么现在我们就只需要在我们以前的那个项目上在进行进一步的操作,也就是加上注册中心就好,那么现在就开始搭建!

Read More

SpringCloud:基础

SpringCloud:基础

SpringCloud 是微服务架构的一个实现框架,说他是一个框架更不如说他是一个生态,他包含了很多个技术,将这些技术组合起来形成我们的微服务架构应用。

image

1.SpringCloud vs Dubbo

image

最大区别:SpringCloud抛弃了Dubbo的RPC通信,采用的是基于HTTP的REST方式。
严格来说,这两种方式各有优劣。虽然从一定程度上来说,后者牺牲了服务调用的性能,但也避免了上面提到的原生RPC带来的问题。而且REST相比RPC更为灵活,服务提供方和调用方的依赖只依靠一纸契约,不存在代码级别的强依赖,这在强调快速演化的微服务环境下,显得更加合适。
很明显,Spring Cloud的功能比DUBBO更加强大,涵盖面更广,而且作为Spring的拳头项目,它也能够与Spring Framework、Spring Boot、Spring Data、Spring Batch等其他Spring项目完美融合,这些对于微服务而言是至关重要的。使用Dubbo构建的微服务架构就像组装电脑,各环节我们的选择自由度很高,但是最终结果很有可能因为一条内存质量不行就点不亮了,总是让人不怎么放心,但是如果你是一名高手,那这些都不是问题;而Spring Cloud就像品牌机,在Spring Source的整合下,做了大量的兼容性测试,保证了机器拥有更高的稳定性,但是如果要在使用非原装组件外的东西,就需要对其基础有足够的了解。

2.微服务搭建实例

我们准备了四个模块,然后这四个模块分别就是用来做统一项目管理的 parent 、一个公共的 api 比如通用的实体类 、一个服务提供者和一个服务消费者。

这样我们形成了一个简单的微服务架构的程序了,接下来就是一步一步的搭建这个框架,这里采用的是 Idea 来搭建项目。

1.创建parent工程

首先我们创建一个Maven项目,注意一点的就是再生成这个项目的时候我们的打包方式要选择 pom 而不是 jar 或者 war,然后这个项目会自动生成一堆的文件夹,其实我们只需要这个 pom 文件,因为只需要做版本控制,而不用写代码的地方。那么我们就删除那些 java 、test 文件夹。

image

那么现在我们的 parent 工程就创建好了,接着就是做一些版本依赖的处理了,我们就需要在pom文件中添加如下的内容。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
<?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>

<groupId>com.lwen</groupId>
<artifactId>parent</artifactId>
<packaging>pom</packaging>
<version>1.0-SNAPSHOT</version>

<!--我们的子模块-->
<modules>
<module>cloud-api</module>
<module>provider-dept-8001</module>
<module>consumer-dept-80</module>
</modules>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<junit.version>4.12</junit.version>
<log4j.version>1.2.17</log4j.version>
<lombok.version>1.16.18</lombok.version>
</properties>

<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Dalston.SR1</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>1.5.9.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.0.4</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.0.31</version>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
<version>1.2.3</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>${junit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
</dependencies>
</dependencyManagement>

<build>
<finalName>microservicecloud</finalName>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<delimiters>
<delimit>$</delimit>
</delimiters>
</configuration>
</plugin>
</plugins>
</build>
</project>

注意一点的就是因为我这个pom文件是所有工程都创建好的工程的 pom 所以说这里我的 子模块 是后来加上去的,可以直接删了后面真的在创建子模块的时候会自动生成这些东西。

2.创建公共的api

接着我们在我们创建好的 parent 工程上 右键创建一个新的 module 然后我们项目结构还是选择 Maven 注意一点的就是我们在创建项目的时候可以选择父工程,我们在这里就选择我们创建好的 parent 工程。

40582344-ddc006b0-61a5-11e8-8353-5aa96b5d168a

1527404295125

那么生成好的项目就会有这么一段文字:

1
2
3
4
5
<parent>
<artifactId>parent</artifactId>
<groupId>com.lwen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>

然后我们在里面加一些我们常用的依赖以后,我们的pom就会长成这个样子:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?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">
<parent>
<artifactId>parent</artifactId>
<groupId>com.lwen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<artifactId>cloud-api</artifactId>

<dependencies><!-- 当前Module需要用到的jar包,按自己需求添加,如果父类已经包含了,可以不用写版本号 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
</project>

好的,现在我们的基础配置已经配置好了,就可以在 api 中写代码了。我们这里需要共享的 api 其实就是我们的实体类,实际上还有很多,这里我们就仅仅拿实体类做例子。

创建一个 entries 包 然后创建一个实体类:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
package entries;


import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.Accessors;

import java.io.Serializable;

@NoArgsConstructor
@AllArgsConstructor
@Data
@Accessors(chain = true)
//必须实现序列化接口
public class Dept implements Serializable {
private Long deptno;
private String dname;
private String db_source;
}

由于我们上面添加了 小辣椒 的依赖,这里的实体类非常简单。

这步完成了就应该是这样的一个结构,然后我们就可以开始生产者的创建了。

3.生产者

生产者里面其实我们应该包含一个完整的 web 层,也就是说我们需要有完整的 Controller 、Service、Dao 然后我们的Controller是用来给后面的消费者调用的,因为我们的SpringCloud是基于Rest请求的嘛。

同理我们创建一个Maven项目,然后导入父工程,接着就是导入依赖:

1.导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://maven.apache.org/POM/4.0.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>parent</artifactId>
<groupId>com.lwen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>com.lwen</groupId>
<artifactId>provider-dept-8001</artifactId>


<dependencies>
<!-- 引入自己定义的api通用包,可以使用Dept部门Entity -->
<dependency>
<groupId>com.lwen</groupId>
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
</dependency>

<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
</dependency>
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-core</artifactId>
</dependency>
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>

2.配置springboot配置文件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
server:
port: 8001

spring:
application:
name: cloud-dept
datasource:
type: com.alibaba.druid.pool.DruidDataSource # 当前数据源操作类型
driver-class-name: org.gjt.mm.mysql.Driver # mysql驱动包
url: jdbc:mysql://localhost:3306/cloudDB01 # 数据库名称
username: root
password:
dbcp2:
min-idle: 5 # 数据库连接池的最小维持连接数
initial-size: 5 # 初始化连接数
max-total: 5 # 最大连接数
max-wait-millis: 200 # 等待连接获取的最大超时时间

mybatis:
configuration:
map-underscore-to-camel-case: true

3.dao

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
package lwen.dao;


import lwen.entries.Dept;
import org.apache.ibatis.annotations.Insert;
import org.apache.ibatis.annotations.Select;

import java.util.List;

public interface DeptDao {
@Select("select * from clouddb01.dept")
public List<Dept> findAll();

@Insert("insert into clouddb01.dept(name, db_name) values (#{name},database())")
boolean insertDept(Dept dept);
}

4.Service

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package lwen.service;

import lwen.dao.DeptDao;
import lwen.entries.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service
public class DeptService {
@Autowired
DeptDao deptDao;

public List<Dept> findAll() {
return deptDao.findAll();
}

public Boolean insertDept(Dept dept) {
return deptDao.insertDept(dept);
}
}

5.controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
package com.lwen.controller;

import entries.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import com.lwen.service.DeptService;

import java.util.List;

@RestController
public class DeptController {

@Autowired
DeptService deptService;

@GetMapping("/dep")
public List<Dept> list() {
return deptService.list();
}

@GetMapping("/dep/add")
public Integer insert(Dept dept) {
return deptService.add(dept);
}
}

4.消费者

同上创建一个module,完成消费者的编写。

消费者其实只有一个Controller,这是因为我们的真正的业务逻辑都被封装到我们的微服务中去了,所以说不存在后面的Service以及Dao。

1.导入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
<?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">
<parent>
<artifactId>parent</artifactId>
<groupId>com.lwen</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>

<groupId>com.lwen</groupId>
<artifactId>consumer-dept-80</artifactId>

<dependencies>
<dependency><!-- 自己定义的api -->
<groupId>com.lwen</groupId>
<artifactId>cloud-api</artifactId>
<version>${project.version}</version>
</dependency>
<!-- Ribbon相关 -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-ribbon</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- 修改后立即生效,热部署 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>springloaded</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
</dependencies>
</project>

2.配置文件

1
2
server:
port: 81

3.config

1
2
3
4
5
6
7
8
9
10
11
12
13
14
package com.lwen.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.client.RestTemplate;

@Configuration
public class BeanConfig {

@Bean
public RestTemplate restTemplate() {
return new RestTemplate();
}
}

这个地方我使用了 JavaConfig 配置了一个 RestTemplate 的Bean,然后这个东西其实就是和我们以前接触的 redisTemplate 以及 jdbc的一样,就是一个工具,用来简化操作的。这里就是简化我们的 rest 请求操作,相当于一个 Http 的客户端。

4.Controller

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.lwen.controller;


import entries.Dept;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.util.List;

@RestController
public class DeptController {

public static final String PREFIX_URL = "http://localhost:8001/";
@Autowired
RestTemplate restTemplate;



@GetMapping("/list")
public List list() {
return restTemplate.getForObject(PREFIX_URL + "dep", List.class);
}

@GetMapping("/dep/add")
public Integer add(Dept dept) {
return restTemplate.getForObject(PREFIX_URL + "dep/add",Integer.class);
}
}

好,现在我们的项目搭建完毕,目前的目录架构应该是这样的:

image

SpringCloud:微服务

1.微服务

微服务其实就是我们的以前的整个应用拆分的一个个小的应用服务,也就是我们的一个个模块。每一个微服务就是一个进程,运行在一个独立的进程之上,然后通过网络进行通讯互联。

2.微服务架构

微服务架构是一种架构模式,他是把传统的单体应用(All in one),拆分成多个项目独立的微服务,然后每一个为服务都是一个独立进程,拥有自己的独立的数据库。然后各个微服务的整合形成整个的微服务架构。

3.微服务的优缺点

1.优点:

  • 每一个服务就是一个聚焦一个功能
  • 单个服务开发简单
  • 服务解耦
  • 小而精

2.缺点:

  • 部署困难,部署依赖
  • 排查困难
  • 服务通讯的成本
  • 数据的一致性
  • 集成测试
  • 性能监控

4.微服务技术栈

微服务条目 技术
服务开发 Springboot、Spring、SpringMVC
服务配置与管理 Netflix公司的Archaius、阿里的Diamond等
服务注册与发现 Eureka、Consul、Zookeeper等
服务调用 Rest、RPC、gRPC
服务熔断器 Hystrix、Envoy等
负载均衡 Ribbon、Nginx等
服务接口调用(客户端调用服务的简化工具) Feign等
消息队列 Kafka、RabbitMQ、ActiveMQ等
服务配置中心管理 SpringCloudConfig、Che等
服务路由(API网关) Zuul
服务监控 Zabbix、Nagios、Metrics、Spectator等
全链路追踪 Zipkin,Brave、Dapper等
服务部署 Docker、OpenStack、Kubernetes等
数据流操作开发包 SpringCloud Stream(封装与Redis,Rabbit、Kafka等发送接收消息)
事件消息总线 Spring Cloud Bus

5.SpringCloud

这里我们的SpringCloud就是一个微服务架构的框架的具体实现了。同样的还有很多其他的微服务架构,比如现在非常出名的Dubbo 以及京东的 JSF 新浪的 Motai

SpringBoot 笔记(十三):运行流程

SpringBoot 笔记(十三):运行流程

几个重要的事件回调机制

配置在META-INF/spring.factories

ApplicationContextInitializer

SpringApplicationRunListener

只需要放在ioc容器中

ApplicationRunner

CommandLineRunner

1.启动流程:

1、创建SpringApplication对象

先 new 了这个对象,然后调用了他的 run 方法。

1. 创建对象

调用了initialize(sources)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
private void initialize(Object[] sources) {
//保存主配置类
if (sources != null && sources.length > 0) {
this.sources.addAll(Arrays.asList(sources));
}
//判断当前是否一个web应用
this.webEnvironment = deduceWebEnvironment();
//从类路径下找到META-INF/spring.factories配置的所有ApplicationContextInitializer;然后保存起来
setInitializers((Collection) getSpringFactoriesInstances(
ApplicationContextInitializer.class));
//从类路径下找到ETA-INF/spring.factories配置的所有ApplicationListener
setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));
//从多个配置类中找到有main方法的主配置类,也就是我们的主类。
this.mainApplicationClass = deduceMainApplicationClass();
}

2、运行run方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
public ConfigurableApplicationContext run(String... args) {
StopWatch stopWatch = new StopWatch();
stopWatch.start();
ConfigurableApplicationContext context = null;
FailureAnalyzers analyzers = null;
configureHeadlessProperty();

//获取SpringApplicationRunListeners;从类路径下META-INF/spring.factories
SpringApplicationRunListeners listeners = getRunListeners(args);
//回调所有的获取SpringApplicationRunListener.starting()方法
listeners.starting();
try {
//封装命令行参数
ApplicationArguments applicationArguments = new DefaultApplicationArguments(
args);
//准备环境
ConfigurableEnvironment environment = prepareEnvironment(listeners,
applicationArguments);
//创建环境完成后回调SpringApplicationRunListener.environmentPrepared();表示环境准备完成

Banner printedBanner = printBanner(environment);

//创建ApplicationContext;决定创建web的ioc还是普通的ioc
context = createApplicationContext();

analyzers = new FailureAnalyzers(context);
//准备上下文环境;将environment保存到ioc中;而且applyInitializers();
//applyInitializers():回调之前保存的所有的ApplicationContextInitializer的initialize方法
//回调所有的SpringApplicationRunListener的contextPrepared();
//
prepareContext(context, environment, listeners, applicationArguments,
printedBanner);
//prepareContext运行完成以后回调所有的SpringApplicationRunListener的contextLoaded();

//刷新容器;ioc容器初始化(如果是web应用还会创建嵌入式的Tomcat)
//扫描,创建,加载所有组件的地方;(配置类,组件,自动配置)
refreshContext(context);
//从ioc容器中获取所有的ApplicationRunner和CommandLineRunner进行回调
//ApplicationRunner先回调,CommandLineRunner再回调
afterRefresh(context, applicationArguments);
//所有的SpringApplicationRunListener回调finished方法
listeners.finished(context, null);
stopWatch.stop();
if (this.logStartupInfo) {
new StartupInfoLogger(this.mainApplicationClass)
.logStarted(getApplicationLog(), stopWatch);
}
//整个SpringBoot应用启动完成以后返回启动的ioc容器;
return context;
}
catch (Throwable ex) {
handleRunFailure(context, listeners, analyzers, ex);
throw new IllegalStateException(ex);
}
}

2、事件监听机制

配置在META-INF/spring.factories

ApplicationContextInitializer

1
2
3
4
5
6
7
public class HelloApplicationContextInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext applicationContext) {
System.out.println("ApplicationContextInitializer...initialize..."+applicationContext);
}
}

SpringApplicationRunListener

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
public class HelloSpringApplicationRunListener implements SpringApplicationRunListener {

//必须有的构造器
public HelloSpringApplicationRunListener(SpringApplication application, String[] args){

}

@Override
public void starting() {
System.out.println("SpringApplicationRunListener...starting...");
}

@Override
public void environmentPrepared(ConfigurableEnvironment environment) {
Object o = environment.getSystemProperties().get("os.name");
System.out.println("SpringApplicationRunListener...environmentPrepared.."+o);
}

@Override
public void contextPrepared(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextPrepared...");
}

@Override
public void contextLoaded(ConfigurableApplicationContext context) {
System.out.println("SpringApplicationRunListener...contextLoaded...");
}

@Override
public void finished(ConfigurableApplicationContext context, Throwable exception) {
System.out.println("SpringApplicationRunListener...finished...");
}
}

配置(META-INF/spring.factories)

1
2
3
4
5
org.springframework.context.ApplicationContextInitializer=\
com.atguigu.springboot.listener.HelloApplicationContextInitializer

org.springframework.boot.SpringApplicationRunListener=\
com.atguigu.springboot.listener.HelloSpringApplicationRunListener

只需要放在ioc容器中

ApplicationRunner

1
2
3
4
5
6
7
@Component
public class HelloApplicationRunner implements ApplicationRunner {
@Override
public void run(ApplicationArguments args) throws Exception {
System.out.println("ApplicationRunner...run....");
}
}

CommandLineRunner

1
2
3
4
5
6
7
@Component
public class HelloCommandLineRunner implements CommandLineRunner {
@Override
public void run(String... args) throws Exception {
System.out.println("CommandLineRunner...run..."+ Arrays.asList(args));
}
}

3.自定义starter

starter:

1、这个场景需要使用到的依赖

2、如何编写自动配置

1
2
3
4
5
6
7
8
9
10
11
12
13
@Configuration  //指定这个类是一个配置类
@ConditionalOnXXX //在指定条件成立的情况下自动配置类生效
@AutoConfigureAfter //指定自动配置类的顺序
@Bean //给容器中添加组件

@ConfigurationPropertie //结合相关xxxProperties类来绑定相关的配置
@EnableConfigurationProperties //让xxxProperties生效加入到容器中

自动配置类要能加载
将需要启动就加载的自动配置类,配置在META-INF/spring.factories
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration,\
org.springframework.boot.autoconfigure.aop.AopAutoConfiguration,\

3、模式:

启动器只用来做依赖导入;专门来写一个自动配置模块;

启动器依赖自动配置;别人只需要引入启动器(starter)

mybatis-spring-boot-starter;自定义启动器名-spring-boot-starter

步骤:

1)、启动器模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<?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>

<groupId>com.atguigu.starter</groupId>
<artifactId>atguigu-spring-boot-starter</artifactId>
<version>1.0-SNAPSHOT</version>

<!--启动器-->
<dependencies>

<!--引入自动配置模块-->
<dependency>
<groupId>com.atguigu.starter</groupId>
<artifactId>atguigu-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>

</project>

2)、自动配置模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?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>

<groupId>com.atguigu.starter</groupId>
<artifactId>atguigu-spring-boot-starter-autoconfigurer</artifactId>
<version>0.0.1-SNAPSHOT</version>
<packaging>jar</packaging>

<name>atguigu-spring-boot-starter-autoconfigurer</name>
<description>Demo project for Spring Boot</description>

<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.10.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>

<dependencies>

<!--引入spring-boot-starter;所有starter的基本配置-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter</artifactId>
</dependency>

</dependencies>



</project>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
package com.atguigu.starter;

import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "atguigu.hello")
public class HelloProperties {

private String prefix;
private String suffix;

public String getPrefix() {
return prefix;
}

public void setPrefix(String prefix) {
this.prefix = prefix;
}

public String getSuffix() {
return suffix;
}

public void setSuffix(String suffix) {
this.suffix = suffix;
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
package com.atguigu.starter;

public class HelloService {

HelloProperties helloProperties;

public HelloProperties getHelloProperties() {
return helloProperties;
}

public void setHelloProperties(HelloProperties helloProperties) {
this.helloProperties = helloProperties;
}

public String sayHellAtguigu(String name){
return helloProperties.getPrefix()+"-" +name + helloProperties.getSuffix();
}
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.atguigu.starter;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@ConditionalOnWebApplication //web应用才生效
@EnableConfigurationProperties(HelloProperties.class)
public class HelloServiceAutoConfiguration {

@Autowired
HelloProperties helloProperties;
@Bean
public HelloService helloService(){
HelloService service = new HelloService();
service.setHelloProperties(helloProperties);
return service;
}
}

更多SpringBoot整合示例

https://github.com/spring-projects/spring-boot/tree/master/spring-boot-samples

SpringBoot 笔记(十二):数据访问

SpringBoot 笔记(十二):数据访问

1、JDBC

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
1
2
3
4
5
6
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.15.22:3306/jdbc
driver-class-name: com.mysql.jdbc.Driver

1.默认情况下:

​ 1. 用org.apache.tomcat.jdbc.pool.DataSource作为数据源;

​ 2. 数据源的相关配置都在DataSourceProperties里面;

2.自动配置原理:

org.springframework.boot.autoconfigure.jdbc包下就是进行自动配置的包:

1、数据库连接池

参考 DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池,可以使用spring.datasource.type指定自定义的数据源类型

2、创建数据源

SpringBoot默认可以支持:org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {

@Bean
public DataSource dataSource(DataSourceProperties properties) {
//使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
return properties.initializeDataSourceBuilder().build();
}

}

3、DataSourceInitializer:ApplicationListener

一个监听器,主要用于sql脚本的运行

​ 作用:

​ 1)、runSchemaScripts();运行建表语句;

​ 2)、runDataScripts();运行插入数据的sql语句;

默认只需要将文件命名为: schema-*.sql 或者 data-*.sql 默认规则:schema.sql,schema-all.sql

当然我们也可以在配置文件中指定,然后就加载指定的sql 脚本,这里是一个 list 也就是脚本可以指定多个。

1
2
schema:
- classpath:department.sql

2、整合Druid数据源

1.配置 yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring.datasource.initialSize:5
spring.datasource.minIdle:5
spring.datasource.maxActive:20
spring.datasource.maxlait:60800
spring.datasource.timeBetweenEvictionRunsMillis:60000
spring.datasource.minEvictableIdleTimeMillis:300000
spring.datasource.validationQuery:SELECT 1 FROM DUAL
spring.datasource.testWhileIdle:true
spring.datasource.testOnBorrow:false
spring.datasource.testOnReturn:false
spring.datasource.poolPreparedStatements:true
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,‘walL“用于防火墙
spring.datasource.filters:stat,wall,log4j
spring.datasource.maxPoolPreparedStatementPerConnectionSize:20
spring.datasource.useGTobalDataSourceStat:true
spring.datasource.connectionProperties:druid.stat.mergeSql=true;druid.stat.slowsqlMillis=5e0

上面的配置文件中的数据实际上我们没用上,这里我们需要创建一个 DruidConfig 然后和当前的配置文件绑定。

2.JavaConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

@Configuration
public class DruidConfig {

@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
//配置Druid的监控
//1、配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();

initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//默认就是允许所有访问
initParams.put("deny","192.168.15.21");

bean.setInitParameters(initParams);
return bean;
}


//2、配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());

Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");

bean.setInitParameters(initParams);

bean.setUrlPatterns(Arrays.asList("/*"));

return bean;
}
}

3、整合MyBatis

1
2
3
4
5
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>

1、注解版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//指定这是一个操作数据库的mapper
@Mapper
public interface DepartmentMapper {

@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);

@Delete("delete from department where id=#{id}")
public int deleteDeptById(Integer id);

@Options(useGeneratedKeys = true,keyProperty = "id") //这是为了获取自动增长的id
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);

@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}

2.自定义配置

自定义MyBatis的配置规则,给容器中添加一个ConfigurationCustomizer;

1
2
3
4
5
6
7
8
9
10
11
12
13
@org.springframework.context.annotation.Configuration
public class MyBatisConfig {

@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer(){
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}

使用MapperScan批量扫描所有的Mapper接口,这样的话我们就不用在Mapper接口上写 @Mapper 注解了。就属于批量的注解了这些注解。

1
2
3
4
5
6
7
@MapperScan(value = "com.springboot.mapper")
@SpringBootApplication
public class SpringBootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMybatisApplication.class, args);
}
}

3、配置文件版

1
2
3
mybatis:
config-location: classpath:mybatis/mybatis-config.xml 指定全局配置文件的位置
mapper-locations: classpath:mybatis/mapper/*.xml 指定sql映射文件的位置

更多使用参照 http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/

4、整合SpringData JPA

1)、SpringData简介

2)、整合SpringData JPA

JPA:ORM(Object Relational Mapping);

1)、编写一个实体类(bean)和数据表进行映射,并且配置好映射关系;

1
2
3
4
5
6
7
8
9
10
11
12
13
//使用JPA注解配置映射关系
@Entity //告诉JPA这是一个实体类(和数据表映射的类)
@Table(name = "tbl_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user;
public class User {

@Id //这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
private Integer id;

@Column(name = "last_name",length = 50) //这是和数据表对应的一个列
private String lastName;
@Column //省略默认列名就是属性名
private String email;

2)、编写一个Dao接口来操作实体类对应的数据表(Repository)

1
2
3
4
//继承JpaRepository来完成对数据库的操作
public interface UserRepository extends JpaRepository<User,Integer> {
}

3)、基本的配置JpaProperties

1
2
3
4
5
6
7
spring:  
jpa:
hibernate:
# 更新或者创建数据表结构
ddl-auto: update
# 控制台显示SQL
show-sql: true

SpringBoot 笔记(十二):数据访问

SpringBoot 笔记(十二):数据访问

1、JDBC

1
2
3
4
5
6
7
8
9
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
1
2
3
4
5
6
spring:
datasource:
username: root
password: 123456
url: jdbc:mysql://192.168.15.22:3306/jdbc
driver-class-name: com.mysql.jdbc.Driver

1.默认情况下:

​ 1. 用org.apache.tomcat.jdbc.pool.DataSource作为数据源;

​ 2. 数据源的相关配置都在DataSourceProperties里面;

2.自动配置原理:

org.springframework.boot.autoconfigure.jdbc包下就是进行自动配置的包:

1、数据库连接池

参考 DataSourceConfiguration,根据配置创建数据源,默认使用Tomcat连接池,可以使用spring.datasource.type指定自定义的数据源类型

2、创建数据源

SpringBoot默认可以支持:org.apache.tomcat.jdbc.pool.DataSource、HikariDataSource、BasicDataSource

1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* Generic DataSource configuration.
*/
@ConditionalOnMissingBean(DataSource.class)
@ConditionalOnProperty(name = "spring.datasource.type")
static class Generic {

@Bean
public DataSource dataSource(DataSourceProperties properties) {
//使用DataSourceBuilder创建数据源,利用反射创建响应type的数据源,并且绑定相关属性
return properties.initializeDataSourceBuilder().build();
}

}

3、DataSourceInitializer:ApplicationListener

一个监听器,主要用于sql脚本的运行

​ 作用:

​ 1)、runSchemaScripts();运行建表语句;

​ 2)、runDataScripts();运行插入数据的sql语句;

默认只需要将文件命名为: schema-*.sql 或者 data-*.sql 默认规则:schema.sql,schema-all.sql

当然我们也可以在配置文件中指定,然后就加载指定的sql 脚本,这里是一个 list 也就是脚本可以指定多个。

1
2
schema:
- classpath:department.sql

2、整合Druid数据源

1.配置 yml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
spring.datasource.initialSize:5
spring.datasource.minIdle:5
spring.datasource.maxActive:20
spring.datasource.maxlait:60800
spring.datasource.timeBetweenEvictionRunsMillis:60000
spring.datasource.minEvictableIdleTimeMillis:300000
spring.datasource.validationQuery:SELECT 1 FROM DUAL
spring.datasource.testWhileIdle:true
spring.datasource.testOnBorrow:false
spring.datasource.testOnReturn:false
spring.datasource.poolPreparedStatements:true
#配置监控统计拦截的filters,去掉后监控界面sql无法统计,‘walL“用于防火墙
spring.datasource.filters:stat,wall,log4j
spring.datasource.maxPoolPreparedStatementPerConnectionSize:20
spring.datasource.useGTobalDataSourceStat:true
spring.datasource.connectionProperties:druid.stat.mergeSql=true;druid.stat.slowsqlMillis=5e0

上面的配置文件中的数据实际上我们没用上,这里我们需要创建一个 DruidConfig 然后和当前的配置文件绑定。

2.JavaConfig

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

@Configuration
public class DruidConfig {

@ConfigurationProperties(prefix = "spring.datasource")
@Bean
public DataSource druid(){
return new DruidDataSource();
}
//配置Druid的监控
//1、配置一个管理后台的Servlet
@Bean
public ServletRegistrationBean statViewServlet(){
ServletRegistrationBean bean = new ServletRegistrationBean(new StatViewServlet(), "/druid/*");
Map<String,String> initParams = new HashMap<>();

initParams.put("loginUsername","admin");
initParams.put("loginPassword","123456");
initParams.put("allow","");//默认就是允许所有访问
initParams.put("deny","192.168.15.21");

bean.setInitParameters(initParams);
return bean;
}


//2、配置一个web监控的filter
@Bean
public FilterRegistrationBean webStatFilter(){
FilterRegistrationBean bean = new FilterRegistrationBean();
bean.setFilter(new WebStatFilter());

Map<String,String> initParams = new HashMap<>();
initParams.put("exclusions","*.js,*.css,/druid/*");

bean.setInitParameters(initParams);

bean.setUrlPatterns(Arrays.asList("/*"));

return bean;
}
}

3、整合MyBatis

1
2
3
4
5
<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>1.3.1</version>
</dependency>

1、注解版

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//指定这是一个操作数据库的mapper
@Mapper
public interface DepartmentMapper {

@Select("select * from department where id=#{id}")
public Department getDeptById(Integer id);

@Delete("delete from department where id=#{id}")
public int deleteDeptById(Integer id);

@Options(useGeneratedKeys = true,keyProperty = "id") //这是为了获取自动增长的id
@Insert("insert into department(departmentName) values(#{departmentName})")
public int insertDept(Department department);

@Update("update department set departmentName=#{departmentName} where id=#{id}")
public int updateDept(Department department);
}

2.自定义配置

自定义MyBatis的配置规则,给容器中添加一个ConfigurationCustomizer;

1
2
3
4
5
6
7
8
9
10
11
12
13
@org.springframework.context.annotation.Configuration
public class MyBatisConfig {

@Bean
public ConfigurationCustomizer configurationCustomizer(){
return new ConfigurationCustomizer(){
@Override
public void customize(Configuration configuration) {
configuration.setMapUnderscoreToCamelCase(true);
}
};
}
}

使用MapperScan批量扫描所有的Mapper接口,这样的话我们就不用在Mapper接口上写 @Mapper 注解了。就属于批量的注解了这些注解。

1
2
3
4
5
6
7
@MapperScan(value = "com.springboot.mapper")
@SpringBootApplication
public class SpringBootMybatisApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootMybatisApplication.class, args);
}
}

3、配置文件版

1
2
3
mybatis:
config-location: classpath:mybatis/mybatis-config.xml 指定全局配置文件的位置
mapper-locations: classpath:mybatis/mapper/*.xml 指定sql映射文件的位置

更多使用参照 http://www.mybatis.org/spring-boot-starter/mybatis-spring-boot-autoconfigure/

4、整合SpringData JPA

1)、SpringData简介

2)、整合SpringData JPA

JPA:ORM(Object Relational Mapping);

1)、编写一个实体类(bean)和数据表进行映射,并且配置好映射关系;

1
2
3
4
5
6
7
8
9
10
11
12
13
//使用JPA注解配置映射关系
@Entity //告诉JPA这是一个实体类(和数据表映射的类)
@Table(name = "tbl_user") //@Table来指定和哪个数据表对应;如果省略默认表名就是user;
public class User {

@Id //这是一个主键
@GeneratedValue(strategy = GenerationType.IDENTITY)//自增主键
private Integer id;

@Column(name = "last_name",length = 50) //这是和数据表对应的一个列
private String lastName;
@Column //省略默认列名就是属性名
private String email;

2)、编写一个Dao接口来操作实体类对应的数据表(Repository)

1
2
3
4
//继承JpaRepository来完成对数据库的操作
public interface UserRepository extends JpaRepository<User,Integer> {
}

3)、基本的配置JpaProperties

1
2
3
4
5
6
7
spring:  
jpa:
hibernate:
# 更新或者创建数据表结构
ddl-auto: update
# 控制台显示SQL
show-sql: true