所有图片使用github图床
@ -6,30 +6,27 @@ tags=["java", "spring"]
|
||||
category="java"
|
||||
serie="spring学习"
|
||||
---
|
||||
[id]:2018-08-12_1
|
||||
[type]:javaee
|
||||
[tag]:java,spring
|
||||
|
||||
  spring是为了解决企业级应用开发的复杂性而创建的,spring最根本的使命是:简化Java开发。为降低开发复杂性有以下四种关键策略。
|
||||
  spring 是为了解决企业级应用开发的复杂性而创建的,spring 最根本的使命是:简化 Java 开发。为降低开发复杂性有以下四种关键策略。
|
||||
|
||||
- 基于POJO的轻量级和最小侵入性编程
|
||||
- 基于 POJO 的轻量级和最小侵入性编程
|
||||
- 通过依赖注入和面向接口实现松耦合
|
||||
- 基于切面和惯例进行声明式编程
|
||||
- 通过切面和模板减少样板式代码
|
||||
|
||||
#### 1.依赖注入
|
||||
|
||||
  假设类A依赖类B,通常做法是在类A中声明类B,然后使用,这样一方面具有极高的耦合性,将类A与类B绑定在一起;另一方面也让单元测试变得很困难,无法在A外部获得B的执行情况。
|
||||
  假设类 A 依赖类 B,通常做法是在类 A 中声明类 B,然后使用,这样一方面具有极高的耦合性,将类 A 与类 B 绑定在一起;另一方面也让单元测试变得很困难,无法在 A 外部获得 B 的执行情况。
|
||||
|
||||
  通过依赖注入,对象的依赖管理将不用对象本身来管理,将由一个第三方组件在创建对象时设定,依赖关系将被自动注入到对应的对象中去。
|
||||
|
||||
#### 2.创建应用上下文
|
||||
|
||||
- `ClassPathXmlApplicationContext()`从类路径创建
|
||||
- `FileSystemXmlApplicationContext()`读取文件系统下的xml配置
|
||||
- `XmlWebApplicationContext()` 读取web应用下的XML配置文件并装载上下文定义
|
||||
- `FileSystemXmlApplicationContext()`读取文件系统下的 xml 配置
|
||||
- `XmlWebApplicationContext()` 读取 web 应用下的 XML 配置文件并装载上下文定义
|
||||
|
||||
#### 3.声明Bean
|
||||
#### 3.声明 Bean
|
||||
|
||||
1. 最简单
|
||||
|
||||
@ -46,66 +43,66 @@ serie="spring学习"
|
||||
|
||||
3. 通过工厂方法创建
|
||||
|
||||
如果想声明的Bean没有一个公开的构造函数,通过factory-method属性来装配工厂生产的Bean
|
||||
如果想声明的 Bean 没有一个公开的构造函数,通过 factory-method 属性来装配工厂生产的 Bean
|
||||
|
||||
```xml
|
||||
<bean id="bean1" class="com.example.class" factory-method="getInstance"/>//getInstance为获取实例的静态方法。
|
||||
```
|
||||
|
||||
#### 4.Bean的作用域
|
||||
#### 4.Bean 的作用域
|
||||
|
||||
所有Spring Bean默认都是单例的。通过配置scope属性为prototype可每次请求产生一个新的实例。
|
||||
所有 Spring Bean 默认都是单例的。通过配置 scope 属性为 prototype 可每次请求产生一个新的实例。
|
||||
|
||||
```xml
|
||||
<bean id="bean3" class="com.example.class" scope="prototype">
|
||||
```
|
||||
|
||||
scope可选值:
|
||||
scope 可选值:
|
||||
|
||||
- `singleton`:每个容器中,一个Bean对象只有一个实例。(**默认**)
|
||||
- `singleton`:每个容器中,一个 Bean 对象只有一个实例。(**默认**)
|
||||
- `prototype`:允许实例化任意次 ,每次请求都会创建新的
|
||||
- `request`:作用域为一次http请求
|
||||
- `session`:作用域为一个http session会话
|
||||
- `global-session`:作用域为一个全局http session,仅在Protlet上下文中有效
|
||||
- `request`:作用域为一次 http 请求
|
||||
- `session`:作用域为一个 http session 会话
|
||||
- `global-session`:作用域为一个全局 http session,仅在 Protlet 上下文中有效
|
||||
|
||||
#### 5.初始化和销毁Bean
|
||||
#### 5.初始化和销毁 Bean
|
||||
|
||||
当实例化需要执行初始化操作,或者销毁时需要执行清理工作。两种实现方式:
|
||||
当实例化需要执行初始化操作,或者销毁时需要执行清理工作。两种实现方式:
|
||||
|
||||
1. xml配置,类中编写初始化方法和销毁方法,在bean中定义。
|
||||
1. xml 配置,类中编写初始化方法和销毁方法,在 bean 中定义。
|
||||
|
||||
```xml
|
||||
<bean id="bean4" class="com.example.Class" init-method="start" destroy-method="destroy"/>
|
||||
```
|
||||
|
||||
也可在Beans中定义默认初始化和销毁方法。
|
||||
也可在 Beans 中定义默认初始化和销毁方法。
|
||||
|
||||
```xml
|
||||
<beans . . . default-init-method="" default-destroy-method=""/>
|
||||
```
|
||||
|
||||
2. 实现`InitializingBean `和`DisposableBean`接口
|
||||
2. 实现`InitializingBean`和`DisposableBean`接口
|
||||
|
||||
#### 6.setter注入
|
||||
#### 6.setter 注入
|
||||
|
||||
在bean中使用`<property>`元素配置属性,使用方法类似于`<constructor-arg>`
|
||||
在 bean 中使用`<property>`元素配置属性,使用方法类似于`<constructor-arg>`
|
||||
|
||||
```xml
|
||||
<property name="name" value="fxg"/> //注入基本数据类型
|
||||
<property name="sex" ref="sex"/> //注入类
|
||||
```
|
||||
|
||||
可使用p简写,**-ref**后缀说明装配的是一个引用
|
||||
可使用 p 简写,**-ref**后缀说明装配的是一个引用
|
||||
|
||||
```xml
|
||||
<bean id="bean5" class="com.example.class"
|
||||
p:name="fxb"
|
||||
<bean id="bean5" class="com.example.class"
|
||||
p:name="fxb"
|
||||
p:sex-ref="sex"/>
|
||||
```
|
||||
|
||||
#### 7.注入内部Bean
|
||||
#### 7.注入内部 Bean
|
||||
|
||||
既定义其他Bean内部的Bean,避免共享问题,可在属性节点或者构造器参数节点上使用。
|
||||
既定义其他 Bean 内部的 Bean,避免共享问题,可在属性节点或者构造器参数节点上使用。
|
||||
|
||||
```xml
|
||||
<property name="sex">
|
||||
@ -118,12 +115,12 @@ scope可选值:
|
||||
|
||||
#### 8.装配集合
|
||||
|
||||
| 集合元素 | 用途 |
|
||||
| ---------------- | ------------------------------ |
|
||||
| \<list\> | 装配list类型,允许重复 |
|
||||
| \<set\> | set,不能重复 |
|
||||
| \<map\> | map类型 |
|
||||
| \<props\> | properties类型,键值都为String |
|
||||
| 集合元素 | 用途 |
|
||||
| --------- | -------------------------------- |
|
||||
| \<list\> | 装配 list 类型,允许重复 |
|
||||
| \<set\> | set,不能重复 |
|
||||
| \<map\> | map 类型 |
|
||||
| \<props\> | properties 类型,键值都为 String |
|
||||
|
||||
- list
|
||||
|
||||
@ -146,7 +143,7 @@ scope可选值:
|
||||
</set>
|
||||
```
|
||||
|
||||
用法和list相同,只是不能重复
|
||||
用法和 list 相同,只是不能重复
|
||||
|
||||
- Map
|
||||
|
||||
@ -156,13 +153,13 @@ scope可选值:
|
||||
</map>
|
||||
```
|
||||
|
||||
entry元素由一个key,一个value组成,分别有两种形式。
|
||||
entry 元素由一个 key,一个 value 组成,分别有两种形式。
|
||||
|
||||
| key | 键为String |
|
||||
| :-------- | -------------- |
|
||||
| key-ref | 键为Bean的引用 |
|
||||
| value | 值为String |
|
||||
| value-ref | 值为Bean的引用 |
|
||||
| key | 键为 String |
|
||||
| :-------- | ---------------- |
|
||||
| key-ref | 键为 Bean 的引用 |
|
||||
| value | 值为 String |
|
||||
| value-ref | 值为 Bean 的引用 |
|
||||
|
||||
- props
|
||||
|
||||
@ -172,11 +169,10 @@ scope可选值:
|
||||
</props>
|
||||
```
|
||||
|
||||
键值都是String
|
||||
键值都是 String
|
||||
|
||||
#### 9.装配空值
|
||||
|
||||
```xml
|
||||
<property name="name"><null/></property>
|
||||
```
|
||||
|
||||
|
@ -6,32 +6,33 @@ tags=["java", "spring"]
|
||||
category="java"
|
||||
serie="spring学习"
|
||||
---
|
||||
|
||||
## 一、自动装配
|
||||
|
||||
### 1、四种类型的自动装配
|
||||
|
||||
| 类型 | 解释 | xml配置 |
|
||||
| ---------- | ------------------------------------ | ---------------------------------------------- |
|
||||
| byName | 根据Bean的name或者id | \<bean id="bean" class="…" autowire="byName"/> |
|
||||
| ByType | 根据Bean类型自动装配 | \<bean id="bean" class="…" autowire="byType"/> |
|
||||
| contructor | 根据Bean的构造器入参具有相同类型 | 同上 |
|
||||
| Autodetect | 首先使用contructor,失败再尝试byType | 同上 |
|
||||
| 类型 | 解释 | xml 配置 |
|
||||
| ---------- | -------------------------------------- | ---------------------------------------------- |
|
||||
| byName | 根据 Bean 的 name 或者 id | \<bean id="bean" class="…" autowire="byName"/> |
|
||||
| ByType | 根据 Bean 类型自动装配 | \<bean id="bean" class="…" autowire="byType"/> |
|
||||
| contructor | 根据 Bean 的构造器入参具有相同类型 | 同上 |
|
||||
| Autodetect | 首先使用 contructor,失败再尝试 byType | 同上 |
|
||||
|
||||
  byType在出现多个匹配项时不会自动选择一个然是报错,为避免报错,有两种办法:1.使用\<bean>元素的primary属性,设置为首选Bean,但所有bean的默认primary都是true,因此我们需要将所有非首选Bean设置为false;2.将Bean的`autowire-candidate`熟悉设置为**false **,取消 这个Bean的候选资格,这个Bean便不会自动注入了。
|
||||
  byType 在出现多个匹配项时不会自动选择一个然是报错,为避免报错,有两种办法:1.使用\<bean>元素的 primary 属性,设置为首选 Bean,但所有 bean 的默认 primary 都是 true,因此我们需要将所有非首选 Bean 设置为**false**;2.将 Bean 的`autowire-candidate`熟悉设置为**false**,取消 这个 Bean 的候选资格,这个 Bean 便不会自动注入了。
|
||||
|
||||
  contructor自动装配和byType有一样的局限性,当发现多个Bean匹配某个构造器入参时,Spring不会尝试选择其中一个;此外,如果一个类有多个构造器都满足自动装配的条件,Spring也不会猜测哪个更合适使用。
|
||||
  contructor 自动装配和 byType 有一样的局限性,当发现多个 Bean 匹配某个构造器入参时,Spring 不会尝试选择其中一个;此外,如果一个类有多个构造器都满足自动装配的条件,Spring 也不会猜测哪个更合适使用。
|
||||
|
||||
### 2、默认自动装配
|
||||
|
||||
  如果需要为Spring应用上下文中的每个Bean(或者其中的大多数)配置相同的autowire属性,可以在根元素\<beans>上增加一个default-autowire属性,默认该属性设置为none。该属性只应用于指定配置文件中的所有Bean,并不是Spring上下文中的所有Bean。
|
||||
  如果需要为 Spring 应用上下文中的每个 Bean(或者其中的大多数)配置相同的 autowire 属性,可以在根元素\<beans>上增加一个 default-autowire 属性,默认该属性设置为 none。该属性只应用于指定配置文件中的所有 Bean,并不是 Spring 上下文中的所有 Bean。
|
||||
|
||||
### 3、混合使用自动装配和显式装配
|
||||
|
||||
  当我们对某个Bean使用了自动装配策略,并不代表我们不能对该Bean的某些属性进行显示装配,任然可以为任意一个属性配置\<property>元素,显式装配将会覆盖自动装配。**但是**当使用constructor自动装配策略时,我们必须让Spring自动装配构造器所有入参,不能使用\<constructor-arg>元素进行混合。
|
||||
  当我们对某个 Bean 使用了自动装配策略,并不代表我们不能对该 Bean 的某些属性进行显示装配,任然可以为任意一个属性配置\<property>元素,显式装配将会覆盖自动装配。**但是**当使用 constructor 自动装配策略时,我们必须让 Spring 自动装配构造器所有入参,不能使用\<constructor-arg>元素进行混合。
|
||||
|
||||
## 二、注解装配
|
||||
|
||||
  从Spring2.5开始,可以使用注解自动装配Bean的属性,使用注解允许更细粒度的自动装配,可选择性的标注某一个属性来对其应用自动装配。Spring容器默认禁用注解装配,需要在Spring配置中启用,最简单的启用方式是使用Spring的context命令空间配置中的`<context:annotation-config>`,如下所示:
|
||||
  从 Spring2.5 开始,可以使用注解自动装配 Bean 的属性,使用注解允许更细粒度的自动装配,可选择性的标注某一个属性来对其应用自动装配。Spring 容器默认禁用注解装配,需要在 Spring 配置中启用,最简单的启用方式是使用 Spring 的 context 命令空间配置中的`<context:annotation-config>`,如下所示:
|
||||
|
||||
```xml
|
||||
<beans ...>
|
||||
@ -40,32 +41,32 @@ serie="spring学习"
|
||||
</beans>
|
||||
```
|
||||
|
||||
  Spring3支持几种不同的用于自动装配的注解:
|
||||
  Spring3 支持几种不同的用于自动装配的注解:
|
||||
|
||||
- Spring自带的@Autowired注解
|
||||
- JSR-330的@Inject注解
|
||||
- JSR-250的@Resource注解
|
||||
- Spring 自带的@Autowired 注解
|
||||
- JSR-330 的@Inject 注解
|
||||
- JSR-250 的@Resource 注解
|
||||
|
||||
### 1、使用@Autowired
|
||||
|
||||
  @Autowired用于对被注解对象启动ByType的自动装配,可用于以下对象:
|
||||
  @Autowired 用于对被注解对象启动 ByType 的自动装配,可用于以下对象:
|
||||
|
||||
- 类属性,即使私有属性也能注入
|
||||
- set方法
|
||||
- set 方法
|
||||
- 构造器
|
||||
- 任意需要装配Bean的方法
|
||||
- 任意需要装配 Bean 的方法
|
||||
|
||||
在使用@Autowired时有两种情况会出错:没有匹配的Bean和存在多个匹配的Bean,但是都有对应的解决方法。
|
||||
在使用@Autowired 时有两种情况会出错:没有匹配的 Bean 和存在多个匹配的 Bean,但是都有对应的解决方法。
|
||||
|
||||
- 当没有匹配Bean时,自动装配会抛出NoSuchBeanDefinitionException,如果不想抛出可使用required属性,设置为false来配置可选的自动装配,即装配失败就不进行装配,不会报错。
|
||||
- 当没有匹配 Bean 时,自动装配会抛出 NoSuchBeanDefinitionException,如果不想抛出可使用 required 属性,设置为 false 来配置可选的自动装配,即装配失败就不进行装配,不会报错。
|
||||
|
||||
```java
|
||||
@Autowired(required=false)
|
||||
```
|
||||
|
||||
当使用构造器配置时,只有一个构造器可以将required属性设置为true,其他都只能设置为false。此外,当使用注解标注多个构造器时,Spring会从所有满足装配条件的构造器中选择入参最多的那个。
|
||||
当使用构造器配置时,只有一个构造器可以将 required 属性设置为 true,其他都只能设置为 false。此外,当使用注解标注多个构造器时,Spring 会从所有满足装配条件的构造器中选择入参最多的那个。
|
||||
|
||||
- 当存在多个Bean满足装配条件时,Spring也会抛出NoSuchBeanDefinitionException错误,为了选择指定的Bean,我们可以使用@Qualifier注解进行筛选:
|
||||
- 当存在多个 Bean 满足装配条件时,Spring 也会抛出 NoSuchBeanDefinitionException 错误,为了选择指定的 Bean,我们可以使用@Qualifier 注解进行筛选:
|
||||
|
||||
```java
|
||||
@Autowired
|
||||
@ -73,7 +74,7 @@ serie="spring学习"
|
||||
private TestClass testClass;
|
||||
```
|
||||
|
||||
除了通过Bean的ID来缩小选择范围,我们还可以通过直接在Bean上使用qualifier来缩小范围,限制Bean的类型,xml如下:
|
||||
除了通过 Bean 的 ID 来缩小选择范围,我们还可以通过直接在 Bean 上使用 qualifier 来缩小范围,限制 Bean 的类型,xml 如下:
|
||||
|
||||
```xml
|
||||
<bean class="com.test.xxx">
|
||||
@ -90,7 +91,7 @@ serie="spring学习"
|
||||
|
||||
还可以创建**自定义限定器(Qualifier)**
|
||||
|
||||
  创建自定义限定器只需要使用@Qualifier注解作为它的源注解即可,如下创建了一个Stringed限定器:
|
||||
  创建自定义限定器只需要使用@Qualifier 注解作为它的源注解即可,如下创建了一个 Stringed 限定器:
|
||||
|
||||
```java
|
||||
@Target({ElementType.FIELD,ElementType.PARAMETER,ElementType.TYPE})
|
||||
@ -99,7 +100,7 @@ serie="spring学习"
|
||||
public @interface Stringed{}
|
||||
```
|
||||
|
||||
然后使用它注解一个Bean:
|
||||
然后使用它注解一个 Bean:
|
||||
|
||||
```java
|
||||
@Stringed
|
||||
@ -114,15 +115,15 @@ serie="spring学习"
|
||||
private Guitar guitar;
|
||||
```
|
||||
|
||||
### 2、使用@Inject自动注入
|
||||
### 2、使用@Inject 自动注入
|
||||
|
||||
  为统一各种依赖注入框架的编程模型,JCP(Java Community Process)发布的Java依赖注入规范,被称为JSR-330,从Spring3开始,Spring已经开始兼容该依赖注入模型。
|
||||
  为统一各种依赖注入框架的编程模型,JCP(Java Community Process)发布的 Java 依赖注入规范,被称为 JSR-330,从 Spring3 开始,Spring 已经开始兼容该依赖注入模型。
|
||||
|
||||
  和@Autowired一样,@Inject可以用来自动装配属性、方法和构造器。但是@Inject没有required属性,因此依赖关系必须存在,如不存在将抛出异常。
|
||||
  和@Autowired 一样,@Inject 可以用来自动装配属性、方法和构造器。但是@Inject 没有 required 属性,因此依赖关系必须存在,如不存在将抛出异常。
|
||||
|
||||
  JSR-330还提供另一种注入技巧,注入一个Provider。Provider接口可以实现Bean引用的延迟注入以及注入Bean的多个实例等功能。
|
||||
  JSR-330 还提供另一种注入技巧,注入一个 Provider。Provider 接口可以实现 Bean 引用的延迟注入以及注入 Bean 的多个实例等功能。
|
||||
|
||||
  例如我们有一个KnifeJuggler类需要注入一个或多个Knife实例,假设Knife Bean的作用域声明为prototype,下面的KnifeJuggler的构造器将获得多个Knife Bean:
|
||||
  例如我们有一个 KnifeJuggler 类需要注入一个或多个 Knife 实例,假设 Knife Bean 的作用域声明为 prototype,下面的 KnifeJuggler 的构造器将获得多个 Knife Bean:
|
||||
|
||||
```java
|
||||
private Set<Knife> knifes;
|
||||
@ -136,20 +137,20 @@ public KnifeJuggler(Provider<Knife> knifeProvider){
|
||||
}
|
||||
```
|
||||
|
||||
  相对于@Autowired所对应的@Qualifier,@Inject对应的是@Named注解。事实上JSR-330中也有@Qualifier注解,不过不建议直接使用,建议通过该注解来创建自定义的限定注解,和Spring的@Qualifier创建过程类似。
|
||||
  相对于@Autowired 所对应的@Qualifier,@Inject 对应的是@Named 注解。事实上 JSR-330 中也有@Qualifier 注解,不过不建议直接使用,建议通过该注解来创建自定义的限定注解,和 Spring 的@Qualifier 创建过程类似。
|
||||
|
||||
### 3、注解中使用表达式
|
||||
|
||||
  Spring3中引入的`@Value`属性可用来装配String类型的值和基本类型的值。借助SpEL表达式,@Value不光可以装配硬编码值还可以在运行期动态计算表达式并装配,例如下面的:
|
||||
  Spring3 中引入的`@Value`属性可用来装配 String 类型的值和基本类型的值。借助 SpEL 表达式,@Value 不光可以装配硬编码值还可以在运行期动态计算表达式并装配,例如下面的:
|
||||
|
||||
```java
|
||||
@Value("#{systemProperties.name}")
|
||||
private String name;
|
||||
```
|
||||
|
||||
## 三、自动检测Bean
|
||||
## 三、自动检测 Bean
|
||||
|
||||
  在Spring中使用上面说到的`<context:annotation-config>`,可以做到自动装配,但还是要在xml中申明Bean。Spring还有另一个元素`<context:component-scan>`,元素除了完成自动装配的功能,还允许Spring自动检测Bean和定义Bean ,用法如下:
|
||||
  在 Spring 中使用上面说到的`<context:annotation-config>`,可以做到自动装配,但还是要在 xml 中申明 Bean。Spring 还有另一个元素`<context:component-scan>`,元素除了完成自动装配的功能,还允许 Spring 自动检测 Bean 和定义 Bean ,用法如下:
|
||||
|
||||
```xml
|
||||
<beans ...>
|
||||
@ -160,18 +161,18 @@ private String name;
|
||||
|
||||
开启后支持如下注解:
|
||||
|
||||
| 注解 | 解释 |
|
||||
| ----------- | ------------------------------------ |
|
||||
| @Component | 通用的构造型注解,标识类为Spring组件 |
|
||||
| @Controller | 标识该类定义为Spring MVC controller |
|
||||
| @Repository | 标识该类定义为数据仓库 |
|
||||
| @Service | 标识该类定义为服务 |
|
||||
| 注解 | 解释 |
|
||||
| ----------- | -------------------------------------- |
|
||||
| @Component | 通用的构造型注解,标识类为 Spring 组件 |
|
||||
| @Controller | 标识该类定义为 Spring MVC controller |
|
||||
| @Repository | 标识该类定义为数据仓库 |
|
||||
| @Service | 标识该类定义为服务 |
|
||||
|
||||
  使用上述注解是Bean的ID默认为无限定类名。使用`@Component("name")`指定ID。
|
||||
  使用上述注解是 Bean 的 ID 默认为无限定类名。使用`@Component("name")`指定 ID。
|
||||
|
||||
### 1、过滤组建扫描
|
||||
|
||||
  通过为<context:component-scan >配置<context:include-filter>和<context:exclude-filter>子元素,我们可以随意调整扫描行为。下面的配置自动注册所有的TestInterface实现类:
|
||||
  通过为\<context:component-scan>配置<context:include-filter>和<context:exclude-filter>子元素,我们可以随意调整扫描行为。下面的配置自动注册所有的 TestInterface 实现类:
|
||||
|
||||
```xml
|
||||
<context:component-scan base-package="com.fxb.springtest">
|
||||
@ -180,27 +181,27 @@ private String name;
|
||||
</context:component-scan>
|
||||
```
|
||||
|
||||
其中的type和expression属性一起协作来定义组件扫描策略。type有以下值可选择:
|
||||
其中的 type 和 expression 属性一起协作来定义组件扫描策略。type 有以下值可选择:
|
||||
|
||||
| 过滤器类型 | 描述 |
|
||||
| ---------- | ------------------------------------------------------------ |
|
||||
| annotation | 过滤器扫描使用指定注解所标注的类。通过expression属性指定要扫描的注解 |
|
||||
| assignable | 过滤器扫描派生于expression属性所指定类型的那些类 |
|
||||
| aspectj | 过滤器扫描于expression属性所指定的AspectJ表达式所匹配的那些类 |
|
||||
| custom | 使用自定义的org.springframework.core.type.TypeFilter实现类,该类由expression属性指定 |
|
||||
| regex | 过滤器扫描类的名称与expression属性所指定的正则表达式所匹配的类 |
|
||||
| 过滤器类型 | 描述 |
|
||||
| ---------- | ---------------------------------------------------------------------------------------- |
|
||||
| annotation | 过滤器扫描使用指定注解所标注的类。通过 expression 属性指定要扫描的注解 |
|
||||
| assignable | 过滤器扫描派生于 expression 属性所指定类型的那些类 |
|
||||
| aspectj | 过滤器扫描于 expression 属性所指定的 AspectJ 表达式所匹配的那些类 |
|
||||
| custom | 使用自定义的 org.springframework.core.type.TypeFilter 实现类,该类由 expression 属性指定 |
|
||||
| regex | 过滤器扫描类的名称与 expression 属性所指定的正则表达式所匹配的类 |
|
||||
|
||||
  exclude-filter使用和include-filter类似,只是效果相反。
|
||||
  exclude-filter 使用和 include-filter 类似,只是效果相反。
|
||||
|
||||
## 四、使用Spring基于Java的配置
|
||||
## 四、使用 Spring 基于 Java 的配置
|
||||
|
||||
  在Spring3.0中几乎可以不使用XML而使用纯粹的Java代码来配置Spring应用。
|
||||
  在 Spring3.0 中几乎可以不使用 XML 而使用纯粹的 Java 代码来配置 Spring 应用。
|
||||
|
||||
- 首先还是需要极少量的XML来启用Java配置,就是上面说到的`<context:component-scan>`,该标签还会自动加载使用`@Configuration`注解所标识的类
|
||||
- 首先还是需要极少量的 XML 来启用 Java 配置,就是上面说到的`<context:component-scan>`,该标签还会自动加载使用`@Configuration`注解所标识的类
|
||||
|
||||
- @Configuration注解相当于XML配置中的\<beans>元素,这个注解将会告知Spring:这个类包含一个或多个Spring Bean的定义,这些定义是使用@Bean注解所标注的方法
|
||||
- @Configuration 注解相当于 XML 配置中的\<beans>元素,这个注解将会告知 Spring:这个类包含一个或多个 Spring Bean 的定义,这些定义是使用@Bean 注解所标注的方法
|
||||
|
||||
- 申明一个简单的Bean代码如下:
|
||||
- 申明一个简单的 Bean 代码如下:
|
||||
|
||||
```java
|
||||
@Configuration
|
||||
@ -212,14 +213,14 @@ private String name;
|
||||
}
|
||||
```
|
||||
|
||||
@Bean告知Spring这个方法将返回一个对象,该对象应该被注册为Spring应用上下文中的一个Bean,方法名作为该Bean的ID 。想要使用另一个Bean的引用也很简单,如下:
|
||||
@Bean 告知 Spring 这个方法将返回一个对象,该对象应该被注册为 Spring 应用上下文中的一个 Bean,方法名作为该 Bean 的 ID 。想要使用另一个 Bean 的引用也很简单,如下:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public Food duckFood(){
|
||||
return new DuckFood();
|
||||
}
|
||||
|
||||
|
||||
@Bean //通过方法名引用一个Bean,并不会创建一个新的实例
|
||||
public Animal duck(){
|
||||
return new Ducker(DuckFood());
|
||||
@ -228,4 +229,4 @@ private String name;
|
||||
|
||||
## 五、小结
|
||||
|
||||
  终于写完了spring 的最小化配置,对spring的各种注解也有了一些了解,再不是之前看到注解一脸莫名其妙了,虽然现在Springboot已经帮我们做了零XML配置,但觉得还是有必要了解下XML配置实现,这样对Java的配置实现理解也会更加深刻。
|
||||
  终于写完了 spring 的最小化配置,对 spring 的各种注解也有了一些了解,再不是之前看到注解一脸莫名其妙了,虽然现在 Springboot 已经帮我们做了零 XML 配置,但觉得还是有必要了解下 XML 配置实现,这样对 Java 的配置实现理解也会更加深刻。
|
||||
|
@ -7,36 +7,35 @@ category="java"
|
||||
serie="spring学习"
|
||||
---
|
||||
|
||||
|
||||
  Spring的基础是IOC和AOP,前面两节对IOC和DI做了简单总结,这里再对AOP进行一个学习总结,Spring基础就算有一个初步了解了。
|
||||
  Spring 的基础是 IOC 和 AOP,前面两节对 IOC 和 DI 做了简单总结,这里再对 AOP 进行一个学习总结,Spring 基础就算有一个初步了解了。
|
||||
|
||||
## 一.面向切面编程
|
||||
|
||||
  在软件开发中,我们可能需要一些跟业务无关但是又必须做的东西,比如日志,事务等,这些分布于应用中多处的功能被称为横切关注点,通常横切关注点从概念上是与应用的业务逻辑相分离的。如何将这些横切关注点与业务逻辑在代码层面进行分离,是面向切面编程(**AOP**)所要解决的。
|
||||
|
||||
横切关注点可以被描述为影响应用多处的功能,切面能够帮助我们模块化横切关注点。下图直观呈现了横切关注点的概念:
|
||||
横切关注点可以被描述为影响应用多处的功能,切面能够帮助我们模块化横切关注点。下图直观呈现了横切关注点的概念:
|
||||
|
||||
![横切关注点](./picFolder/切面示例.png)
|
||||
![横切关注点](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E9%9D%A2%E5%90%91%E5%88%87%E9%9D%A2%E7%9A%84spring/20190107100126.png)
|
||||
|
||||
途中CourseService,StudentService,MiscService都需要类似安全、事务这样的辅助功能,这些辅助功能就被称为横切关注点。
|
||||
图中 CourseService,StudentService,MiscService 都需要类似安全、事务这样的辅助功能,这些辅助功能就被称为横切关注点。
|
||||
|
||||
  **继承**和**委托**是最常见的实现重用通用功能的面向对象技术。但是如果在整个程序中使用相同的基类继承往往会导致一个脆弱的对象体系;而使用委托可能需要对委托对象进行复杂的调用。
|
||||
|
||||
切面提供了取代继承和委托的另一种选择,而且更加清晰简洁。在面向切面编程时,我们任然在一个地方定义通用功能,但是我们可以通过声明的方式定义这个功能以何种方式在何处应用,而无需修改受影响的类,受影响类完全感受不到切面的存在。
|
||||
  切面提供了取代继承和委托的另一种选择,而且更加清晰简洁。在面向切面编程时,我们任然在一个地方定义通用功能,但是我们可以通过声明的方式定义这个功能以何种方式在何处应用,而无需修改受影响的类,受影响类完全感受不到切面的存在。
|
||||
|
||||
## 二.AOP常用术语
|
||||
## 二.AOP 常用术语
|
||||
|
||||
  下面是AOP中常用的名词。
|
||||
  下面是 AOP 中常用的名词。
|
||||
|
||||
### 1. 通知(Advice)
|
||||
|
||||
  通知定义了切面是什么以及何时使用。出了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。Sping切面可以应用以下5种类型的通知。
|
||||
  通知定义了切面是什么以及何时使用。出了描述切面要完成的工作,通知还解决了何时执行这个工作的问题。Sping 切面可以应用以下 5 种类型的通知。
|
||||
|
||||
- **Before** 在方法被调用之前调用通知
|
||||
- **After** 在方法完成之后调用通知,无论方法执行是否成功
|
||||
- **After-returning** 在方法成功执行后调用通知
|
||||
- **After-throwing** 在方法抛出异常后调用通知
|
||||
- **Around** 通知包裹了被通知的方法,在被通知的方法调用前和调用后执行
|
||||
- **Before** 在方法被调用之前调用通知
|
||||
- **After** 在方法完成之后调用通知,无论方法执行是否成功
|
||||
- **After-returning** 在方法成功执行后调用通知
|
||||
- **After-throwing** 在方法抛出异常后调用通知
|
||||
- **Around** 通知包裹了被通知的方法,在被通知的方法调用前和调用后执行
|
||||
|
||||
###2.连接点(Joinpoint)
|
||||
|
||||
@ -44,7 +43,7 @@ serie="spring学习"
|
||||
|
||||
### 3.切点(Pointcut)
|
||||
|
||||
  切点定义了通知所要织入的一个或多个连接点。如果说通知定义了切面的“**什么**”和“**何时**”,那么切点就定义了“**何处**”。通常使用明确的类和方法名称来指定切点,或者利用正则表达式定义匹配的类和方法来指定这些切点。有些AOP框架允许我们创建动态的切点,可以更具运行时的策略来决定是否应用通知。
|
||||
  切点定义了通知所要织入的一个或多个连接点。如果说通知定义了切面的“**什么**”和“**何时**”,那么切点就定义了“**何处**”。通常使用明确的类和方法名称来指定切点,或者利用正则表达式定义匹配的类和方法来指定这些切点。有些 AOP 框架允许我们创建动态的切点,可以更具运行时的策略来决定是否应用通知。
|
||||
|
||||
### 4.切面(Aspect)
|
||||
|
||||
@ -58,48 +57,48 @@ serie="spring学习"
|
||||
|
||||
  织入是将切面应用到目标对象来创建新的代理对象的过程。切面在指定的连接点被织入到目标对象中,在目标对象的生命周期里有多个点可以进行织入。
|
||||
|
||||
- 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译期,比如AspectJ的织入编译期
|
||||
- 类加载期:切面在目标类加载到JVM时被织入。这种方式需要特殊的加载器,它可以在目标类被引入应用之前增强该目标类的字节码,例如AspectJ5的**LTW**(load-time weaving)
|
||||
- 运行期:切面在应用运行的某个时刻被织入。一般情况下AOP容器会为目标对象动态创建一个代理对象
|
||||
- 编译期:切面在目标类编译时被织入。这种方式需要特殊的编译期,比如 AspectJ 的织入编译期
|
||||
- 类加载期:切面在目标类加载到 JVM 时被织入。这种方式需要特殊的加载器,它可以在目标类被引入应用之前增强该目标类的字节码,例如 AspectJ5 的**LTW**(load-time weaving)
|
||||
- 运行期:切面在应用运行的某个时刻被织入。一般情况下 AOP 容器会为目标对象动态创建一个代理对象
|
||||
|
||||
##三.Spring AOP
|
||||
|
||||
  Spring在运行期通知对象,通过在代理类中包裹切面,Spring在运行期将切面织入到Spring管理的Bean中。代理类封装了目标类,并拦截被通知的方法的调用,再将调用转发给真正的目标Bean。由于Spring是基于动态代理,所有Spring只支持方法连接点,如果需要方法拦截之外的连接点拦截,我们可以利用Aspect来协助SpringAOP。
|
||||
  Spring 在运行期通知对象,通过在代理类中包裹切面,Spring 在运行期将切面织入到 Spring 管理的 Bean 中。代理类封装了目标类,并拦截被通知的方法的调用,再将调用转发给真正的目标 Bean。由于 Spring 是基于动态代理,所有 Spring 只支持方法连接点,如果需要方法拦截之外的连接点拦截,我们可以利用 Aspect 来协助 SpringAOP。
|
||||
|
||||
  Spring在运行期通知对象,通过在代理类中包裹切面,Spring在运行期将切面织入到Spring管理的Bean中。代理类封装了目标类,并拦截被通知的方法的调用,再将调用转发给真正的目标Bean。由于Spring是基于动态代理,所有Spring只支持方法连接点,如果需要方法拦截之外的连接点拦截,我们可以利用Aspect来协助SpringAOP。
|
||||
  Spring 在运行期通知对象,通过在代理类中包裹切面,Spring 在运行期将切面织入到 Spring 管理的 Bean 中。代理类封装了目标类,并拦截被通知的方法的调用,再将调用转发给真正的目标 Bean。由于 Spring 是基于动态代理,所有 Spring 只支持方法连接点,如果需要方法拦截之外的连接点拦截,我们可以利用 Aspect 来协助 SpringAOP。
|
||||
|
||||
### 1、定义切点
|
||||
|
||||
  在SpringAOP中,需要使用AspectJ的切点表达式语言来定义切点。Spring只支持AspectJ的部分切点指示器,如下表所示:
|
||||
  在 SpringAOP 中,需要使用 AspectJ 的切点表达式语言来定义切点。Spring 只支持 AspectJ 的部分切点指示器,如下表所示:
|
||||
|
||||
| AspectJ指示器 | 描述 |
|
||||
| ------------- | ------------------------------------------------------------ |
|
||||
| arg() | 限制连接点匹配参数为指定类型的执行方法 |
|
||||
| @args() | 限制连接点匹配参数由指定注解标注的执行方法 |
|
||||
| execution() | 用于匹配是连接点的执行方法 |
|
||||
| this() | 限制连接点匹配AOP代理的Bean引用为指导类型的类 |
|
||||
| target() | 限制连接点匹配目标对象为指定类型的类 |
|
||||
| @target() | 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解 |
|
||||
| within() | 限制连接点匹配指定的类型 |
|
||||
| @within() | 限制连接点匹配指定注解所标注的类型(当使用SpringAOP时,方法定义在由指定的注解所标注的类里) |
|
||||
| @annotation | 限制匹配带有指定注解连接点 |
|
||||
| bean() | 使用Bean ID或Bean名称作为参数来限制切点只匹配特定的Bean |
|
||||
| AspectJ 指示器 | 描述 |
|
||||
| -------------- | --------------------------------------------------------------------------------------------- |
|
||||
| arg() | 限制连接点匹配参数为指定类型的执行方法 |
|
||||
| @args() | 限制连接点匹配参数由指定注解标注的执行方法 |
|
||||
| execution() | 用于匹配是连接点的执行方法 |
|
||||
| this() | 限制连接点匹配 AOP 代理的 Bean 引用为指导类型的类 |
|
||||
| target() | 限制连接点匹配目标对象为指定类型的类 |
|
||||
| @target() | 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型的注解 |
|
||||
| within() | 限制连接点匹配指定的类型 |
|
||||
| @within() | 限制连接点匹配指定注解所标注的类型(当使用 SpringAOP 时,方法定义在由指定的注解所标注的类里) |
|
||||
| @annotation | 限制匹配带有指定注解连接点 |
|
||||
| bean() | 使用 Bean ID 或 Bean 名称作为参数来限制切点只匹配特定的 Bean |
|
||||
|
||||
 其中只有execution指示器是唯一的执行匹配,其他都是限制匹配。因此execution指示器是
|
||||
 其中只有 execution 指示器是唯一的执行匹配,其他都是限制匹配。因此 execution 指示器是
|
||||
|
||||
其中只有execution指示器是唯一的执行匹配,其他都是限制匹配。因此execution指示器是我们在编写切点定义时最主要使用的指示器。
|
||||
其中只有 execution 指示器是唯一的执行匹配,其他都是限制匹配。因此 execution 指示器是我们在编写切点定义时最主要使用的指示器。
|
||||
|
||||
### 2、编写切点
|
||||
|
||||
  假设我们要使用execution()指示器选择Hello类的sayHello()方法,表达式如下:
|
||||
  假设我们要使用 execution()指示器选择 Hello 类的 sayHello()方法,表达式如下:
|
||||
|
||||
```java
|
||||
execution(* com.test.Hello.sayHello(..))
|
||||
```
|
||||
|
||||
方法表达式以*** **号开始,说明不管方法返回值的类型。然后指定全限定类名和方法名。对于方法参数列表,我们使用(**)标识切点选择任意的sayHello()方法,无论方法入参是什么。
|
||||
方法表达式以**\* **号开始,说明不管方法返回值的类型。然后指定全限定类名和方法名。对于方法参数列表,我们使用(\*\*)标识切点选择任意的 sayHello()方法,无论方法入参是什么。
|
||||
|
||||
  同时我们可以使用&&(and),||(or),!(not)来连接指示器,如下所示:
|
||||
  同时我们可以使用 (and),||(or),!(not)来连接指示器,如下所示:
|
||||
|
||||
```java
|
||||
execution(* com.test.Hello.sayHello(..)) and !bean(xiaobu)
|
||||
@ -107,25 +106,25 @@ execution(* com.test.Hello.sayHello(..)) and !bean(xiaobu)
|
||||
|
||||
### 3、申明切面
|
||||
|
||||
  在经典Spring AOP中使用ProxyFactoryBean非常复杂,因此提供了申明式切面的选择,在Spring的AOP配置命名空间中有如下配置元素:
|
||||
  在经典 Spring AOP 中使用 ProxyFactoryBean 非常复杂,因此提供了申明式切面的选择,在 Spring 的 AOP 配置命名空间中有如下配置元素:
|
||||
|
||||
| AOP配置元素 | 描述 |
|
||||
| ------------------------------ | ----------------------------------------------------------- |
|
||||
| <aop:advisor > | 定义AOP通知器 |
|
||||
| <aop:after > | 定义AOP后置通知(无论被通知方法是否执行成功) |
|
||||
| <aop:after-returning > | 定义AOP after-returning通知 |
|
||||
| <aop:after-throwing > | 定义after-throwing |
|
||||
| <aop:around > | 定义AOP环绕通知 |
|
||||
| <aop:aspect > | 定义切面 |
|
||||
| <aop:aspectj-autoproxy > | 启用@AspectJ注解驱动的切面 |
|
||||
| <aop:before > | 定义AOP前置通知 |
|
||||
| <aop:config > | 顶层的AOP配置元素。大多数的<aop:* >元素必须包含在其中 |
|
||||
| <aop:declare-parents > | 为被通知的对象引入额外的接口,并透明的实现 |
|
||||
| <aop:pointcut > | 定义切点 |
|
||||
| AOP 配置元素 | 描述 |
|
||||
| ------------------------------ | -------------------------------------------------------------- |
|
||||
| <aop:advisor > | 定义 AOP 通知器 |
|
||||
| <aop:after > | 定义 AOP 后置通知(无论被通知方法是否执行成功) |
|
||||
| <aop:after-returning > | 定义 AOP after-returning 通知 |
|
||||
| <aop:after-throwing > | 定义 after-throwing |
|
||||
| <aop:around > | 定义 AOP 环绕通知 |
|
||||
| <aop:aspect > | 定义切面 |
|
||||
| <aop:aspectj-autoproxy > | 启用@AspectJ 注解驱动的切面 |
|
||||
| <aop:before > | 定义 AOP 前置通知 |
|
||||
| <aop:config > | 顶层的 AOP 配置元素。大多数的<aop:\* >元素必须包含在其中 |
|
||||
| <aop:declare-parents > | 为被通知的对象引入额外的接口,并透明的实现 |
|
||||
| <aop:pointcut > | 定义切点 |
|
||||
|
||||
### 4、实现
|
||||
|
||||
假设有一个演员类`Actor`,演员类中有一个表演方法`perform()`,然后还有一个观众类`Audience`,这两个类都在包`com.example.springtest`下,Audience类主要方法如下:
|
||||
假设有一个演员类`Actor`,演员类中有一个表演方法`perform()`,然后还有一个观众类`Audience`,这两个类都在包`com.example.springtest`下,Audience 类主要方法如下:
|
||||
|
||||
```java
|
||||
public class Audience{
|
||||
@ -141,13 +140,13 @@ public class Audience{
|
||||
public void demandRefund(){}
|
||||
//测试带参数
|
||||
public void dealString(String word){}
|
||||
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
#### a、xml配置实现
|
||||
#### a、xml 配置实现
|
||||
|
||||
  首先将Audience配置到springIOC中:
|
||||
  首先将 Audience 配置到 springIOC 中:
|
||||
|
||||
```xml
|
||||
<bean id="audience" class="com.example.springtest.Audience"/>
|
||||
@ -161,7 +160,7 @@ public class Audience{
|
||||
<!-- 申明切点 -->
|
||||
<aop:pointcut id="performance" expression="execution(* com.example.springtest.Performer.perform(..))"/>
|
||||
<!-- 声明传递参数切点 -->
|
||||
<aop:pointcut id="performanceStr" expression="execution(* com.example.springtest.Performer.performArg(String) and args(word))"/>
|
||||
<aop:pointcut id="performanceStr" expression="execution(* com.example.springtest.Performer.performArg(String) and args(word))"/>
|
||||
<!-- 前置通知 -->
|
||||
<aop:before pointcut-ref="performance" method="takeSeats"/>
|
||||
<!-- 执行成功通知 -->
|
||||
@ -169,18 +168,16 @@ public class Audience{
|
||||
<!-- 执行异常通知 -->
|
||||
<aop:after-throwing pointcut-ref="performance" method="demandRefund"/>
|
||||
<!-- 环绕通知 -->
|
||||
<aop:around pointcut-ref="performance" method="timing"/>
|
||||
<aop:around pointcut-ref="performance" method="timing"/>
|
||||
<!-- 传递参数 -->
|
||||
<aop:before pointcut-ref="performanceStr" arg-names="word" method="dealString"/>
|
||||
</aop:aspect>
|
||||
</aop:config>
|
||||
```
|
||||
|
||||
|
||||
|
||||
#### b、注解实现
|
||||
|
||||
直接在Audience类上加注解(Aspect注解并不能被spring自动发现并注册,要么写到xml中,要么使用@Aspectj注解或者加一个@Component注解),如下所示:
|
||||
直接在 Audience 类上加注解(Aspect 注解并不能被 spring 自动发现并注册,要么写到 xml 中,要么使用@Aspectj 注解或者加一个@Component 注解),如下所示:
|
||||
|
||||
```java
|
||||
@Aspect
|
||||
@ -188,29 +185,29 @@ public class Audience{
|
||||
//定义切点
|
||||
@Pointcut(execution(* com.example.springtest.Performer.perform(..)))
|
||||
public void perform(){}
|
||||
|
||||
|
||||
//定义带参数切点
|
||||
@Pointcut(execution(* com.example.springtest.Performer.performArg(String) and args(word)))
|
||||
public void performStr(String word){}
|
||||
|
||||
|
||||
//搬凳子
|
||||
@Before("perform()")
|
||||
public void takeSeats(){}
|
||||
|
||||
|
||||
//欢呼
|
||||
@AfterReturning("perform()")
|
||||
public void applaud(){}
|
||||
|
||||
|
||||
//计时,环绕通知需要一个ProceedingJoinPoint参数
|
||||
@Around("perform()")
|
||||
public void timing(ProceedingJoinPoint joinPoint){
|
||||
joinPoint.proceed();
|
||||
}
|
||||
|
||||
|
||||
//演砸了
|
||||
@AfterThrowing("perform()")
|
||||
public void demandRefund(){}
|
||||
|
||||
|
||||
//带参数
|
||||
@Before("performStr(word)")
|
||||
public void dealString(String word){}
|
||||
@ -219,13 +216,13 @@ public class Audience{
|
||||
|
||||
#### c、通过切面引入新功能
|
||||
|
||||
  既然可以用AOP为对象拥有的方法添加新功能,那为什么不能为对象增加新的方法呢?利用被称为**引入**的AOP概念,切面可以为Spring Bean添加新的方法,示例图如下:
|
||||
  既然可以用 AOP 为对象拥有的方法添加新功能,那为什么不能为对象增加新的方法呢?利用被称为**引入**的 AOP 概念,切面可以为 Spring Bean 添加新的方法,示例图如下:
|
||||
|
||||
![引入](./picFolder/引入新功能.png)
|
||||
![引入](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E9%9D%A2%E5%90%91%E5%88%87%E9%9D%A2%E7%9A%84spring/20190107100233.png)
|
||||
|
||||
当引入接口的方法被调用时,代理将此调用委托给实现了新接口的某个其他对象。实际上,Bean的实现被拆分到了多个类。
|
||||
当引入接口的方法被调用时,代理将此调用委托给实现了新接口的某个其他对象。实际上,Bean 的实现被拆分到了多个类。
|
||||
|
||||
- xml引入需要使用<aop:declare-parents >元素:
|
||||
- xml 引入需要使用<aop:declare-parents >元素:
|
||||
|
||||
```xml
|
||||
<aop:aspect>
|
||||
@ -235,7 +232,7 @@ public class Audience{
|
||||
</aop:aspect>
|
||||
```
|
||||
|
||||
顾名思义\<declare-parents>声明了此切面所通知的Bean在它的对象层次结构中有了新的父类型。其中types-matching指定增强的类;implement-interface指定实现新方法的接口;default-imple指定实现了implement-interface接口的实现类,也可以用delegate-ref来指定一个Bean的引用。
|
||||
顾名思义\<declare-parents>声明了此切面所通知的 Bean 在它的对象层次结构中有了新的父类型。其中 types-matching 指定增强的类;implement-interface 指定实现新方法的接口;default-imple 指定实现了 implement-interface 接口的实现类,也可以用 delegate-ref 来指定一个 Bean 的引用。
|
||||
|
||||
- 注解引入,通过`@DeclareParents`注解
|
||||
|
||||
@ -245,5 +242,4 @@ public class Audience{
|
||||
public static AddTestInterface addTestInterface;
|
||||
```
|
||||
|
||||
同xml实现一样,注解也由三部分组成:1、value属性相当于tpes-matching属性,标识被增强的类;2、defaultImpl等同于default-imple,指定接口的实现类;3、有@DeclareParents注解所标注的static属性指定了将被引入的接口。
|
||||
|
||||
同 xml 实现一样,注解也由三部分组成:1、value 属性相当于 tpes-matching 属性,标识被增强的类;2、defaultImpl 等同于 default-imple,指定接口的实现类;3、有@DeclareParents 注解所标注的 static 属性指定了将被引入的接口。
|
||||
|
Before Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 41 KiB |
Before Width: | Height: | Size: 29 KiB |
Before Width: | Height: | Size: 45 KiB |
Before Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 15 KiB |
@ -11,13 +11,13 @@ serie="spring boot学习"
|
||||
|
||||
### 1.选择 spring initializr
|
||||
|
||||
![1532967570728](./picFolder/1532967570728.png)
|
||||
![选择spring initializr](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springboot%E6%90%AD%E5%BB%BA/20190107100435.png)
|
||||
|
||||
next
|
||||
|
||||
#### 2.设置参数
|
||||
|
||||
![1532967772110](./picFolder/1532967772110.png)
|
||||
![设置参数](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springboot%E6%90%AD%E5%BB%BA/20190107100509.png)
|
||||
|
||||
next
|
||||
|
||||
@ -25,13 +25,13 @@ next
|
||||
|
||||
  在这里选择 spring boot 版本和 web 依赖(忽略 sql 的依赖,如有需要[点击这里](f),单独将 mybatis 的整合),后面也可手动编辑 pom 文件修改增加删除依赖
|
||||
|
||||
![1532967938985](./picFolder/1532967938985.png)
|
||||
![依赖选择](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springboot%E6%90%AD%E5%BB%BA/20190107100609.png)
|
||||
|
||||
这里我们选择 web 搭建一个简单的 REST 风格 demo。然后 next。
|
||||
|
||||
#### 4.设置项目存放地址
|
||||
|
||||
![1532968024509](./picFolder/1532968024509.png)
|
||||
![设置项目存放地址](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springboot%E6%90%AD%E5%BB%BA/20190107100653.png)
|
||||
|
||||
这样就成功构建了一个 springboot 项目。
|
||||
|
||||
@ -39,7 +39,7 @@ next
|
||||
|
||||
  现在新建一个 controller 包,包下新建一个 HelloController,创建之后项目目录结构如下:
|
||||
|
||||
![1532969025023](./picFolder/1532969025023.png)
|
||||
![项目目录结构](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springboot%E6%90%AD%E5%BB%BA/20190107100803.png)
|
||||
|
||||
HelloController 代码如下:
|
||||
|
||||
@ -54,4 +54,4 @@ public class HelloController{
|
||||
}
|
||||
```
|
||||
|
||||
然后运行项目,访问 localhost:8080/home/hello 即可看到 hello 字符串。
|
||||
然后运行项目,访问 [localhost:8080/home/hello](localhost:8080/home/hello) 即可看到 hello 字符串。
|
||||
|
Before Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 54 KiB |
@ -7,7 +7,7 @@ category="java"
|
||||
serie="spring boot学习"
|
||||
---
|
||||
|
||||
**说明 springboot 版本 2.0.3<br/>项目地址:[点击跳转](https://github.com/FleyX/demo-project/tree/master/springboot_spirngsecurity_demo)**
|
||||
**说明 springboot 版本 2.0.3<br/>源码地址:[点击跳转](https://github.com/FleyX/demo-project/tree/master/springboot_spirngsecurity_demo)**
|
||||
|
||||
## 一、 介绍
|
||||
|
||||
@ -77,7 +77,7 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
#### 2、 个性化登录,security 中的登录如下:
|
||||
|
||||
![登录过程](./picFolder/pic1.png)
|
||||
![登录过程](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springsecurity/20190107101026.png)
|
||||
|
||||
- security 需要一个 user 的实体类实现`UserDetails`接口,该实体类最后与系统中用户的实体类分开,代码如下:
|
||||
|
||||
|
@ -6,18 +6,16 @@ tags=["java", "spring","springboot","spring-security","security"]
|
||||
category="java"
|
||||
serie="spring boot学习"
|
||||
---
|
||||
[id]:2018-08-21
|
||||
[type]:javaee
|
||||
[tag]:java,spring,springsecurity,scurity
|
||||
|
||||
  紧接着上一篇,上一篇中登录验证都由security帮助我们完成了,如果我们想要增加一个验证码登录或者其它的自定义校验就没办法了,因此这一篇讲解如何实现这个功能。
|
||||
  紧接着上一篇,上一篇中登录验证都由 security 帮助我们完成了,如果我们想要增加一个验证码登录或者其它的自定义校验就没办法了,因此这一篇讲解如何实现这个功能。
|
||||
|
||||
##一、 实现自定义登录校验类
|
||||
|
||||
  继承UsernamePasswordAuthenticationFilter类来拓展登录校验,代码如下:
|
||||
  继承 UsernamePasswordAuthenticationFilter 类来拓展登录校验,代码如下:
|
||||
|
||||
```java
|
||||
public class MyUsernamePasswordAuthentication extends UsernamePasswordAuthenticationFilter{
|
||||
|
||||
|
||||
private Logger log = LoggerFactory.getLogger(this.getClass());
|
||||
|
||||
@Override
|
||||
@ -37,8 +35,9 @@ public class MyUsernamePasswordAuthentication extends UsernamePasswordAuthentica
|
||||
}
|
||||
```
|
||||
|
||||
##二、 将自定义登录配置到security中
|
||||
  编写自定义登录过滤器后,configure Bean修改为如下:
|
||||
##二、 将自定义登录配置到 security 中
|
||||
  编写自定义登录过滤器后,configure Bean 修改为如下:
|
||||
|
||||
```java
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
@ -84,7 +83,9 @@ public class MyUsernamePasswordAuthentication extends UsernamePasswordAuthentica
|
||||
.logoutSuccessHandler(myLogoutSuccessHandle);
|
||||
}
|
||||
```
|
||||
然后再编写Bean,代码如下:
|
||||
|
||||
然后再编写 Bean,代码如下:
|
||||
|
||||
```java
|
||||
@Bean
|
||||
public MyUsernamePasswordAuthentication myUsernamePasswordAuthentication(){
|
||||
@ -98,4 +99,5 @@ public MyUsernamePasswordAuthentication myUsernamePasswordAuthentication(){
|
||||
return myUsernamePasswordAuthentication;
|
||||
}
|
||||
```
|
||||
完成。
|
||||
|
||||
完成。
|
||||
|
@ -8,7 +8,8 @@ serie="spring boot学习"
|
||||
---
|
||||
|
||||
  这篇讲解如何自定义鉴权过程,实现根据数据库查询出的 url 和 method 是否匹配当前请求的 url 和 method 来决定有没有权限。security 鉴权过程如下:
|
||||
![鉴权流程](./picFolder/pic2.png)
|
||||
|
||||
![鉴权流程](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springsecurity/20190107101130.png)
|
||||
|
||||
## 一、 重写 metadataSource 类
|
||||
|
||||
@ -173,6 +174,7 @@ public class MyAccessDecisionManager implements AccessDecisionManager{
|
||||
```
|
||||
|
||||
## 三、 编写 MyFilterSecurityInterceptor 类
|
||||
|
||||
  该类继承 AbstractSecurityInterceptor 类,实现 Filter 接口,代码如下:
|
||||
|
||||
```java
|
||||
|
Before Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 87 KiB |
Before Width: | Height: | Size: 62 KiB |
Before Width: | Height: | Size: 117 KiB |
@ -9,7 +9,7 @@ serie="spring boot学习"
|
||||
|
||||
## 写在前面
|
||||
|
||||
  项目源代码在github,地址为:[https://github.com/FleyX/demo-project/tree/master/mybatis-test](https://github.com/FleyX/demo-project/tree/master/mybatis-test),有需要的自取。
|
||||
  项目源代码在 github,地址为:[https://github.com/FleyX/demo-project/tree/master/mybatis-test](https://github.com/FleyX/demo-project/tree/master/mybatis-test),有需要的自取。
|
||||
|
||||
  刚毕业的第一份工作是 java 开发,项目中需要用到 mybatis,特此记录学习过程,这只是一个简单 demo,mybatis 用法很多不可能全部写出来,有更复杂的需求建议查看 mybatis 的官方中文文档,[点击跳转](http://www.mybatis.org/mybatis-3/zh/index.html)。下面时项目环境/版本。
|
||||
|
||||
@ -98,9 +98,9 @@ serie="spring boot学习"
|
||||
|
||||
然后依照上面的 pom 文件,补齐缺少的依赖。接着创建包 entity,service 和 mybatis 映射文件夹 mapper,创建。为了方便配置将 application.properties 改成 application.yml。由于我们时 REST 接口,故不需要 static 和 templates 目录。修改完毕后的项目结构如下:
|
||||
|
||||
![项目结构](./picFolder/pic1.png)
|
||||
![项目结构](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E6%95%B0%E6%8D%AE%E5%BA%93/20190107101305.png)
|
||||
|
||||
修改启动类,增加`@MapperScan("com.example.mybatistest.dao")`,以自动扫描 dao 目录,避免每个 dao 都手动加`@Mapper`注解。代码如下:
|
||||
  修改启动类,增加`@MapperScan("com.example.mybatistest.dao")`,以自动扫描 dao 目录,避免每个 dao 都手动加`@Mapper`注解。代码如下:
|
||||
|
||||
```java
|
||||
@SpringBootApplication
|
||||
@ -331,15 +331,15 @@ public class UserController {
|
||||
|
||||
- 插入数据:
|
||||
|
||||
![插入](./picFolder/pic2.png)
|
||||
![插入](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E6%95%B0%E6%8D%AE%E5%BA%93/20190107101358.png)
|
||||
|
||||
- 查询数据
|
||||
|
||||
![查询](./picFolder/pic3.png)
|
||||
![查询](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E6%95%B0%E6%8D%AE%E5%BA%93/20190107101412.png)
|
||||
|
||||
- 分页查询
|
||||
|
||||
![分页查询](./picFolder/pic4.png)
|
||||
![分页查询](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E6%95%B0%E6%8D%AE%E5%BA%93/20190107101608.png)
|
||||
|
||||
## 4.注解编写 sql
|
||||
|
||||
|
Before Width: | Height: | Size: 7.5 KiB |
Before Width: | Height: | Size: 82 KiB |
Before Width: | Height: | Size: 37 KiB |
@ -37,7 +37,8 @@ spring:
|
||||
### 2. 创建生产者消费者
|
||||
|
||||
  springboot 中 activeMQ 的默认配置为**生产-消费者模式**,还有一种模式为**发布-订阅模式**后面再讲。项目目录如下:
|
||||
![项目目录](./picFolder/pic1.png)
|
||||
|
||||
![项目目录](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/20190107101724.png)
|
||||
|
||||
  首先编写配置类 Config.java,代码如下
|
||||
|
||||
@ -57,7 +58,8 @@ public class Config {
|
||||
```
|
||||
|
||||
上面的代码建立了两个消息队列 queue1,queue2,分别由 queue1 和 queue2 这两个 Bean 注入到 Spring 容器中。程序运行后会在 activeMQ 的管理页面->queue 中看到如下:
|
||||
![队列](./picFolder/pic2.png)
|
||||
|
||||
![队列](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/20190107101745.png)
|
||||
|
||||
  生产者 Producer.java 代码如下:
|
||||
|
||||
@ -132,5 +134,7 @@ public class Comsumer {
|
||||
```
|
||||
|
||||
消息都成功被消费者消费,从打印结果也可看出生产者消费者的一个特点:一个消息只会被一个消费者消费。同时在管理页面中可以看到:
|
||||
![运行结果](./picFolder/pic3.png)
|
||||
|
||||
![运行结果](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E6%B6%88%E6%81%AF%E9%98%9F%E5%88%97/20190107101808.png)
|
||||
|
||||
每个消息队列有两个消费者,队列进入了三个消息,出了三个消息,说明消息都被消费掉了,如果注释掉消费者代码,再次运行,然后发送消息就会发现 MessagesEnqueued 数量大于 MessagesDequeued,然后再让消费者上线会立即消费掉队列中的消息。
|
||||
|
@ -6,38 +6,34 @@ tags=["java", "spring","springboot","消息队列","activeMQ"]
|
||||
category="java"
|
||||
serie="spring boot学习"
|
||||
---
|
||||
[id]:2018-09-06
|
||||
[type]:javaee
|
||||
[tag]:java,spring,activemq
|
||||
|
||||
  单个 MQ 节点总是不可靠的,一旦该节点出现故障,MQ 服务就不可用了,势必会产生较大的损失。这里记录 activeMQ 如何开启主从备份,一旦 master(主节点故障),slave(从节点)立即提供服务,实现原理是运行多个 MQ 使用同一个持久化数据源,这里以 jdbc 数据源为例。同一时间只有一个节点(节点 A)能够抢到数据库的表锁,其他节点进入阻塞状态,一旦 A 发生错误崩溃,其他节点就会重新获取表锁,获取到锁的节点成为 master,其他节点为 slave,如果节点 A 重新启动,也将成为 slave。
|
||||
|
||||
  单个MQ节点总是不可靠的,一旦该节点出现故障,MQ服务就不可用了,势必会产生较大的损失。这里记录activeMQ如何开启主从备份,一旦master(主节点故障),slave(从节点)立即提供服务,实现原理是运行多个MQ使用同一个持久化数据源,这里以jdbc数据源为例。同一时间只有一个节点(节点A)能够抢到数据库的表锁,其他节点进入阻塞状态,一旦A发生错误崩溃,其他节点就会重新获取表锁,获取到锁的节点成为master,其他节点为slave,如果节点A重新启动,也将成为slave。
|
||||
  主从备份解决了单节点故障的问题,但是同一时间提供服务的只有一个 master,显然是不能面对数据量的增长,所以需要一种横向拓展的集群方式来解决面临的问题。
|
||||
|
||||
主从备份解决了单节点故障的问题,但是同一时间提供服务的只有一个master,显然是不能面对数据量的增长,所以需要一种横向拓展的集群方式来解决面临的问题。
|
||||
|
||||
### 一、activeMQ设置
|
||||
### 一、activeMQ 设置
|
||||
|
||||
#### 1、平台版本说明:
|
||||
|
||||
- 平台:windows
|
||||
- activeMQ版本:5.9.1,[下载地址](https://www.apache.org/dist/activemq/5.9.1/apache-activemq-5.9.1-bin.zip.asc)
|
||||
- jdk版本:1.8
|
||||
- activeMQ 版本:5.9.1,[下载地址](https://www.apache.org/dist/activemq/5.9.1/apache-activemq-5.9.1-bin.zip.asc)
|
||||
- jdk 版本:1.8
|
||||
|
||||
#### 2、下载jdbc依赖
|
||||
#### 2、下载 jdbc 依赖
|
||||
|
||||
  下载下面三个依赖包,放到activeMQ安装目录下的lib文件夹中。
|
||||
  下载下面三个依赖包,放到 activeMQ 安装目录下的 lib 文件夹中。
|
||||
|
||||
[mysql驱动](http://central.maven.org/maven2/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar)
|
||||
[mysql 驱动](http://central.maven.org/maven2/mysql/mysql-connector-java/5.1.38/mysql-connector-java-5.1.38.jar)
|
||||
|
||||
[dhcp依赖](http://central.maven.org/maven2/org/apache/commons/commons-dbcp2/2.1.1/commons-dbcp2-2.1.1.jar)
|
||||
[dhcp 依赖](http://central.maven.org/maven2/org/apache/commons/commons-dbcp2/2.1.1/commons-dbcp2-2.1.1.jar)
|
||||
|
||||
[commons-pool2依赖](http://maven.aliyun.com/nexus/service/local/artifact/maven/redirect?r=jcenter&g=org.apache.commons&a=commons-pool2&v=2.6.0&e=jar)
|
||||
[commons-pool2 依赖](http://maven.aliyun.com/nexus/service/local/artifact/maven/redirect?r=jcenter&g=org.apache.commons&a=commons-pool2&v=2.6.0&e=jar)
|
||||
|
||||
###二、主从备份
|
||||
|
||||
####1、修改jettty
|
||||
####1、修改 jettty
|
||||
|
||||
  首先修改conf->jetty.xml,这里是修改activemq的web管理端口,管理界面账号密码默认为admin/admin
|
||||
  首先修改 conf->jetty.xml,这里是修改 activemq 的 web 管理端口,管理界面账号密码默认为 admin/admin
|
||||
|
||||
```xml
|
||||
<bean id="jettyPort" class="org.apache.activemq.web.WebConsolePort" init-method="start">
|
||||
@ -46,13 +42,13 @@ serie="spring boot学习"
|
||||
</bean>
|
||||
```
|
||||
|
||||
####2、修改activemq.xml
|
||||
####2、修改 activemq.xml
|
||||
|
||||
  然后修改conf->activemq.xml
|
||||
  然后修改 conf->activemq.xml
|
||||
|
||||
- 设置连接方式
|
||||
|
||||
默认是下面五种连接方式都打开,这里我们只要tcp,把其他的都注释掉,然后在这里设置activemq的服务端口,可以看到每种连接方式都对应一个端口。
|
||||
默认是下面五种连接方式都打开,这里我们只要 tcp,把其他的都注释掉,然后在这里设置 activemq 的服务端口,可以看到每种连接方式都对应一个端口。
|
||||
|
||||
```xml
|
||||
<transportConnectors>
|
||||
@ -65,11 +61,9 @@ serie="spring boot学习"
|
||||
</transportConnectors>
|
||||
```
|
||||
|
||||
|
||||
* 设置 jdbc 数据库
|
||||
|
||||
- 设置jdbc数据库
|
||||
|
||||
mysql数据库中创建activemq库,在`broker`标签的下面也就是根标签`beans`的下一级创建一个bean节点,内容如下:
|
||||
mysql 数据库中创建 activemq 库,在`broker`标签的下面也就是根标签`beans`的下一级创建一个 bean 节点,内容如下:
|
||||
|
||||
```xml
|
||||
<bean id="mysql-qs" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
|
||||
@ -81,15 +75,15 @@ serie="spring boot学习"
|
||||
</bean>
|
||||
```
|
||||
|
||||
- 设置数据源
|
||||
* 设置数据源
|
||||
|
||||
首先修改broker节点,设置name和persistent(默认为true),也可不做修改,修改后如下:
|
||||
首先修改 broker 节点,设置 name 和 persistent(默认为 true),也可不做修改,修改后如下:
|
||||
|
||||
```xml
|
||||
<broker xmlns="http://activemq.apache.org/schema/core" brokerName="mq1" persistent="true" dataDirectory="${activemq.data}">
|
||||
```
|
||||
|
||||
然后设置持久化方式,使用到我们之前设置的mysql-qs
|
||||
然后设置持久化方式,使用到我们之前设置的 mysql-qs
|
||||
|
||||
```xml
|
||||
<persistenceAdapter>
|
||||
@ -100,7 +94,7 @@ serie="spring boot学习"
|
||||
|
||||
#### 3、启动
|
||||
|
||||
  设置完毕后启动activemq(双击bin中的acitveMQ.jar),启动完成后可以看到如下日志信息:
|
||||
  设置完毕后启动 activemq(双击 bin 中的 acitveMQ.jar),启动完成后可以看到如下日志信息:
|
||||
|
||||
```verilog
|
||||
INFO | Using a separate dataSource for locking: org.apache.commons.dbcp2.BasicDataSource@179ece50
|
||||
@ -108,7 +102,7 @@ serie="spring boot学习"
|
||||
INFO | Becoming the master on dataSource: org.apache.commons.dbcp2.BasicDataSource@179ece50
|
||||
```
|
||||
|
||||
接着我们修改一下tcp服务端口,改为61617,然后重新启动,日志信息如下:
|
||||
接着我们修改一下 tcp 服务端口,改为 61617,然后重新启动,日志信息如下:
|
||||
|
||||
```verilog
|
||||
INFO | Using a separate dataSource for locking: org.apache.commons.dbcp2.BasicDataSource@179ece50
|
||||
@ -123,7 +117,7 @@ serie="spring boot学习"
|
||||
|
||||
### 三、负载均衡
|
||||
|
||||
  activemq可以实现多个mq之间进行路由,假设有两个mq,分别为brokerA和brokerB,当一条消息发送到brokerA的队列test中,有一个消费者连上了brokerB,并且想要获取test队列,brokerA中的test队列就会路由到brokerB上。
|
||||
  activemq 可以实现多个 mq 之间进行路由,假设有两个 mq,分别为 brokerA 和 brokerB,当一条消息发送到 brokerA 的队列 test 中,有一个消费者连上了 brokerB,并且想要获取 test 队列,brokerA 中的 test 队列就会路由到 brokerB 上。
|
||||
|
||||
   开启负载均衡需要设置`networkConnectors`节点,静态路由配置如下:
|
||||
|
||||
@ -133,24 +127,24 @@ serie="spring boot学习"
|
||||
</networkConnectors>
|
||||
```
|
||||
|
||||
brokerA和brokerB都要设置该配置,以连上对方。
|
||||
brokerA 和 brokerB 都要设置该配置,以连上对方。
|
||||
|
||||
### 四、测试
|
||||
|
||||
####1、建立mq
|
||||
####1、建立 mq
|
||||
|
||||
  组建两组broker,每组做主从配置。
|
||||
  组建两组 broker,每组做主从配置。
|
||||
|
||||
- brokerA:
|
||||
- 主:设置web管理端口8761,设置mq名称`mq`,设置数据库地址为activemq,设置tcp服务端口61616,设置负载均衡静态路由`static:failover://(tcp://localhost:61618,tcp://localhost:61619)`,然后启动
|
||||
- 从:上面的基础上修改tcp服务端口为61617,然后启动
|
||||
- 主:设置 web 管理端口 8761,设置 mq 名称`mq`,设置数据库地址为 activemq,设置 tcp 服务端口 61616,设置负载均衡静态路由`static:failover://(tcp://localhost:61618,tcp://localhost:61619)`,然后启动
|
||||
- 从:上面的基础上修改 tcp 服务端口为 61617,然后启动
|
||||
- brokerB:
|
||||
- 主:设置web管理端口8762,设置mq名称`mq1`,设置数据库地址activemq1,设置tcp服务端口61618,设置负载均衡静态路由`static:failover://(tcp://localhost:61616,tcp://localhost:61617)`,然后启动
|
||||
- 从:上面的基础上修改tcp服务端口为61619,然后启动
|
||||
- 主:设置 web 管理端口 8762,设置 mq 名称`mq1`,设置数据库地址 activemq1,设置 tcp 服务端口 61618,设置负载均衡静态路由`static:failover://(tcp://localhost:61616,tcp://localhost:61617)`,然后启动
|
||||
- 从:上面的基础上修改 tcp 服务端口为 61619,然后启动
|
||||
|
||||
#### 2、springboot测试
|
||||
#### 2、springboot 测试
|
||||
|
||||
   沿用上一篇的项目,修改配置文件的broker-url为`failover:(tcp://localhost:61616,tcp://localhost:61617,tcp://localhost:61618,tcp://localhost:61619)`,然后启动项目访问会在控制台看到如下日志:
|
||||
   沿用上一篇的项目,修改配置文件的 broker-url 为`failover:(tcp://localhost:61616,tcp://localhost:61617,tcp://localhost:61618,tcp://localhost:61619)`,然后启动项目访问会在控制台看到如下日志:
|
||||
|
||||
```java
|
||||
2018-07-31 15:09:25.076 INFO 12780 --- [ActiveMQ Task-1] o.a.a.t.failover.FailoverTransport : Successfully connected to tcp://localhost:61618
|
||||
@ -163,4 +157,4 @@ brokerA和brokerB都要设置该配置,以连上对方。
|
||||
2I'm from queue1:hello
|
||||
```
|
||||
|
||||
证明负载均衡成功。
|
||||
证明负载均衡成功。
|
||||
|
Before Width: | Height: | Size: 5.1 KiB |
Before Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 44 KiB |
@ -42,7 +42,7 @@ serie="spring boot学习"
|
||||
|
||||
然后重启数据库,使用`show master status;`语句查看主库状态,如下所示:
|
||||
|
||||
![主库状态](./picFolder/pic1.png)
|
||||
![主库状态](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/20190107101953.png)
|
||||
|
||||
- 从库配置
|
||||
|
||||
@ -68,9 +68,9 @@ serie="spring boot学习"
|
||||
|
||||
接着运行`start slave;`开启备份,正常情况如下图所示:Slave_IO_Running 和 Slave_SQL_Running 都为 yes。
|
||||
|
||||
![1536223020742](./picFolder/pic2.png)
|
||||
![状态](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/20190107102024.png)
|
||||
|
||||
可以用这个步骤开启多个从库。
|
||||
可以用这个步骤开启多个从库。
|
||||
|
||||
  默认情况下备份是主库的全部操作都会备份到从库,实际可能需要忽略某些库,可以在主库中增加如下配置:
|
||||
|
||||
@ -315,6 +315,6 @@ public class ReadOnlyInterceptor implements Ordered {
|
||||
|
||||
  编写好代码来试试结果如何,下面是运行截图:
|
||||
|
||||
![1536312274474](./picFolder/pic3.png)
|
||||
![测试结果](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E8%AF%BB%E5%86%99%E5%88%86%E7%A6%BB/20190107102056.png)
|
||||
|
||||
  断断续续写了好几天终于是写完了,,,如果有帮助到你,,欢迎 star 哦,,这里是完整代码地址:[点击跳转](https://github.com/FleyX/demo-project/tree/master/dxfl)
|
||||
|
@ -10,7 +10,9 @@ serie="springCloud实战"
|
||||
## 一、前言
|
||||
|
||||
  在开发普通的 web 应用中,我们通常是将配置项写在单独的配置文件中,比如`application.yml`,`application.properties`,但是在微服务架构中,可能会出现数百个微服务,如果每个微服务将配置文件写在自身的配置文件中,会导致配置文件的管理非常复杂。因此集中式的配置管理是非常有必要的,每个服务启动时从集中式的存储库中读取需要的配置信息。其模型如下:
|
||||
![配置管理概念架构](./picFolder/配置管理概念架构.png)
|
||||
|
||||
![配置管理概念架构](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springcloud%E5%AE%9E%E6%88%98/20190107102213.png)
|
||||
|
||||
简单来说就是如下几点:
|
||||
|
||||
1. 启动一个微服务实例时向配置管理服务请求获取其所在环境的特定配置文件
|
||||
|
@ -17,7 +17,8 @@ serie="springCloud实战"
|
||||
4. 健康监测:服务如何将它的健康信息传回给服务发现代理?
|
||||
|
||||
下图展示了这 4 个概念的流程,以及在服务发现模式实现中通常发生的情况:
|
||||
![服务发现架构](./picFolder/服务发现架构.png)
|
||||
|
||||
![服务发现架构](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springcloud%E5%AE%9E%E6%88%98/20190107102247.png)
|
||||
|
||||
  通常服务实例都只向一个服务发现实例注册,服务发现实例之间再通过数据传输,让每个服务实例注册到所有的服务发现实例中。
|
||||
  服务在向服务发现实例注册后,这个服务就能被服务消费者调用了。服务消费者可以使用多种模型来"发现"服务。
|
||||
@ -26,6 +27,7 @@ serie="springCloud实战"
|
||||
2. 更健壮的方法是使用所谓的客户端负载均衡。
|
||||
|
||||
  如下图所示:
|
||||
|
||||
![客户端负载均衡](./picFolder/客户端负载均衡模型.png
|
||||
  在这个模型中,当服务消费者需要调用一个服务时:
|
||||
|
||||
|
@ -38,7 +38,7 @@ serie="springCloud实战"
|
||||
|
||||
  下图展示了这些模式是如何运用到微服务中的:
|
||||
|
||||
![客户端弹性模式架构](./picFolder/客户端弹性模式架构.png)
|
||||
![客户端弹性模式架构](https://raw.githubusercontent.com/FleyX/files/master/blogImg/springcloud%E5%AE%9E%E6%88%98/20190107102342.png)
|
||||
|
||||
# 三、spring cloud 中使用
|
||||
|
||||
|
20
java/springcloud实战/4.springCloud之Zuul服务路由.md
Normal file
@ -0,0 +1,20 @@
|
||||
---
|
||||
id="2019-01-03-19-19"
|
||||
title="springCloud学习4(Zuul服务路由)"
|
||||
headWord="像微服务这样的分布式架构中,需要确保跨多个服务调用的关键行为(如安全、日志记录、用户跟踪等)能够正常运行,这就需要一个服务网关来统一处理。"
|
||||
tags=["spring-boot", "spring-cloud","netflix-zuul","service-gateway"]
|
||||
category="java"
|
||||
serie="springCloud实战"
|
||||
---
|
||||
|
||||
<span id="personBlogId" value="2019-01-03-19-19"/>
|
||||
|
||||
# 一、背景
|
||||
|
||||
  微服务架构将一个应用拆分为很多个微小应用,这样会导致之前不是问题的问题出现,比如:
|
||||
|
||||
1. 安全问题如何实现?
|
||||
2. 日志记录如何实现?
|
||||
3. 用户跟踪如何实现?
|
||||
|
||||
上面的问题在传统的单机应用很容易解决,只需要当作一个功能实现即可。但是在微服务中就行不通了,让每个服务都实现一份上述功能,那是相当不现实的,费时,费力还容易出问题。为了解决这个问题,需要将这些横切关注点(分布式系统级别的横切关注点和 spring 中的基本一个意思)抽象成一个独立的且作为应用程序中所有微服务调用的过滤器和路由器的服务。这样的服务被称为————**服务网管(service gateway)**,服务客户端不再直接调用服务。取而代之的是,服务网关作为单个策略执行点(Policy Enforcement Point,PEP) , 所有调用都通过服务网管进行路由,然后被送到目的地, asd发生的 ,, ,,,阿斯蒂芬😊
|
Before Width: | Height: | Size: 58 KiB |
Before Width: | Height: | Size: 24 KiB |
Before Width: | Height: | Size: 55 KiB |
Before Width: | Height: | Size: 64 KiB |
Before Width: | Height: | Size: 20 KiB |
@ -19,7 +19,7 @@ npm i -g typescript
|
||||
|
||||
  以 test 项目为例,在 test 目录下执行`tsc --init`,会在项目目录下产生一个`tsconfig.json`的配置文件,每项配置都有说明,如下图所示:
|
||||
|
||||
![tscofnig文件部分截图](./picFolder/tsconfig界面.png)
|
||||
![tscofnig文件部分截图](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/20190107102602.png)
|
||||
|
||||
主要用到的配置项如下:
|
||||
|
||||
@ -56,7 +56,7 @@ npm i -g typescript
|
||||
|
||||
  首先添加 launch.json,如图所示:
|
||||
|
||||
![添加配置](./picFolder/添加配置.png)
|
||||
![添加配置](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/20190107102624.png)
|
||||
|
||||
选中 node 环境,然后将要调试的文件改为输出目录中对应的 js 文件,修改 program 属性:
|
||||
|
||||
@ -111,6 +111,6 @@ npm i -g typescript
|
||||
|
||||
最后调试页面启动调试,选择代码真实运行的进程,如下图所示:
|
||||
|
||||
![vscode符加进程](./picFolder/vscode附加进程.png)
|
||||
![vscode符加进程](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E7%8E%AF%E5%A2%83%E9%85%8D%E7%BD%AE/20190107102641.png)
|
||||
|
||||
  大功告成。。
|
||||
|
@ -9,9 +9,11 @@ serie="踩坑"
|
||||
|
||||
  项目组最近加了一个新功能到代码中,使用 flyway 记录数据库版本变更,该工具会记录每次数据库结构的修改并生成 sql 文件存在指定目录上(当然必须用它来变更数据库,外部的变更它是无法感知的),然后每次启动时 flyway 会检查使用的数据库和当前项目代码中的 sql 变更版本是否一致,一致正常启动,不一致中如果是数据库落后将会更新数据库(这样能够保证代码在任何地方运行数据库都是一致的),否则就报错了。数据库中有一张表记录版本信息,如下图:
|
||||
|
||||
![版本记录](./picFolder/版本记录.PNG),同时本地代码中也有一个文件夹保存每次操作的 sql 语句,如下图:
|
||||
![版本记录](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E5%85%B6%E4%BB%96%E5%90%84%E7%A7%8D/20190107102736.PNG)
|
||||
|
||||
![版本sql](./picFolder/版本sql.PNG)
|
||||
同时本地代码中也有一个文件夹保存每次操作的 sql 语句,如下图:
|
||||
|
||||
![版本sql](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E5%85%B6%E4%BB%96%E5%90%84%E7%A7%8D/20190107102748.PNG)
|
||||
|
||||
通过对比 checksum 值来判断当前 sql 语句和生成数据库的执行语句是否一致,checksum 值由 CRC32 计算后处理得出。
|
||||
|
||||
|
Before Width: | Height: | Size: 4.2 KiB |
Before Width: | Height: | Size: 8.8 KiB |
37
数据库/分布式事务.md
@ -15,31 +15,31 @@ serie="分布式事务"
|
||||
|
||||
### 1.数据库事务
|
||||
|
||||
我们都知道数据库事务的四个特性:原子性、一致性、隔离性和持久性,数据库事务由数据库软件自身来完成。假如数据库在提交事务的时候突然断电,数据库可以在日志记录中找到上一次事务操作然后根据当前数据库的情况进行undo回滚或者是redo前滚(基于某时刻的完整备份然后执行从该时刻到崩溃时间所有增删改查操作,使数据库恢复到崩溃前的状态)。在分布式环境中可能遇到的问题就更多了,例如机器宕机、网络异常、消息乱序、数据错误、存储数据丢失等等,数据库自身并没有比较好的解决方案(下文会提到一种数据库支持的解决方法)。
|
||||
  我们都知道数据库事务的四个特性:原子性、一致性、隔离性和持久性,数据库事务由数据库软件自身来完成。假如数据库在提交事务的时候突然断电,数据库可以在日志记录中找到上一次事务操作然后根据当前数据库的情况进行 undo 回滚或者是 redo 前滚(基于某时刻的完整备份然后执行从该时刻到崩溃时间所有增删改查操作,使数据库恢复到崩溃前的状态)。在分布式环境中可能遇到的问题就更多了,例如机器宕机、网络异常、消息乱序、数据错误、存储数据丢失等等,数据库自身并没有比较好的解决方案(下文会提到一种数据库支持的解决方法)。
|
||||
|
||||
### 2.分布式理论
|
||||
|
||||
  当单个数据库的性能产生瓶颈的时候,我们可能会对数据库进行分区,这里分区指的是物理分区,分区后不同的库可能就在不同的服务器上了,这个时候单个数据库的ACID已经不能适应这种情况了,在集群情况下想保证集群的ACID是很困难的,即使能够达到,效率和性能也会大幅下降,而且难以拓展。这就需要一个新的理论**CAP原则**。
|
||||
  当单个数据库的性能产生瓶颈的时候,我们可能会对数据库进行分区,这里分区指的是物理分区,分区后不同的库可能就在不同的服务器上了,这个时候单个数据库的 ACID 已经不能适应这种情况了,在集群情况下想保证集群的 ACID 是很困难的,即使能够达到,效率和性能也会大幅下降,而且难以拓展。这就需要一个新的理论**CAP 原则**。
|
||||
|
||||
  CAP是加州大学伯克利分校Eric Brewer教授提出的,他指出WEB服务无法同时满足以下3个属性:
|
||||
  CAP 是加州大学伯克利分校 Eric Brewer 教授提出的,他指出 WEB 服务无法同时满足以下 3 个属性:
|
||||
|
||||
- 一致性(Consistency):客户端发起的一系列操作都会同时生效
|
||||
- 可用性(Availability):每个操作必须以可预期的响应结束
|
||||
- 分区容错性(Partition Tolerance):即使单个组件无法使用,操作任然可以完成
|
||||
|
||||
具体的说在分布式系统中,任何数据库至多只能同时支持上面的两个属性,但是任何横向拓展策略都要依赖数据分区。因此,设计人员必须在一致性与可用性中作出选择。在此基础上后面又提出了另外一个理论,**BASE**理论,用于对CAP原则进一步扩充。BASE理论指的是:
|
||||
具体的说在分布式系统中,任何数据库至多只能同时支持上面的两个属性,但是任何横向拓展策略都要依赖数据分区。因此,设计人员必须在一致性与可用性中作出选择。在此基础上后面又提出了另外一个理论,**BASE**理论,用于对 CAP 原则进一步扩充。BASE 理论指的是:
|
||||
|
||||
- 基本可用(Basically Available)
|
||||
- 软状态(Soft State)
|
||||
- 最终一致性(Eventually Consistent)
|
||||
|
||||
BASE理论是对CAP中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:**我们没法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性**。
|
||||
BASE 理论是对 CAP 中的一致性和可用性进行一个权衡的结果,理论的核心思想就是:**我们没法做到强一致,但每个应用都可以根据自身的业务特点,采用适当的方式来使系统达到最终一致性**。
|
||||
|
||||
## 二、解决方案
|
||||
|
||||
### 1.两阶段提交(2PC)
|
||||
|
||||
主流关系型数据库大都支持,又叫**XA Transactions(XAT)**。其中XA是一个两阶段提交协议,该协议分为以下两个阶段:
|
||||
主流关系型数据库大都支持,又叫**XA Transactions(XAT)**。其中 XA 是一个两阶段提交协议,该协议分为以下两个阶段:
|
||||
|
||||
- 第一阶段:事务协调器要求每个涉及到事务的数据库预提交(precommit)此操作,并反映是否可以提交
|
||||
- 第二阶段:事务协调器要求每个数据库提交数据
|
||||
@ -52,33 +52,32 @@ BASE理论是对CAP中的一致性和可用性进行一个权衡的结果,理
|
||||
|
||||
### 2.补偿事务(TCC)
|
||||
|
||||
核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段:
|
||||
核心思想是:针对每个操作,都要注册一个与其对应的确认和补偿(撤销)操作。它分为三个阶段:
|
||||
|
||||
- Try阶段主要对业务系统做检测及资源预留
|
||||
- Confirm阶段主要对业务系统做确认提交,Try阶段执行成功然后开始执行Confirm阶段时,默认Confirm阶段是不会出错的。也就是只要Try成功,Confirm一定成功。
|
||||
- Cancel阶段主要在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
|
||||
- Try 阶段主要对业务系统做检测及资源预留
|
||||
- Confirm 阶段主要对业务系统做确认提交,Try 阶段执行成功然后开始执行 Confirm 阶段时,默认 Confirm 阶段是不会出错的。也就是只要 Try 成功,Confirm 一定成功。
|
||||
- Cancel 阶段主要在业务执行错误,需要回滚的状态下执行的业务取消,预留资源释放。
|
||||
|
||||
**优点**:跟2PC比起来,实现以及流程相对简单了点,但是数据的一致性也差一点
|
||||
**优点**:跟 2PC 比起来,实现以及流程相对简单了点,但是数据的一致性也差一点
|
||||
|
||||
**缺点**:在第二阶段、第三阶段都由可能失败。对业务代码入侵比较严重,需要在实现的时候多写很多补偿代码。
|
||||
|
||||
### 3.本地消息表(异步补偿)
|
||||
|
||||
本地消息应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行处理,这种思路来源于ebay。
|
||||
本地消息应该是业界使用最多的,其核心思想是将分布式事务拆分成本地事务进行处理,这种思路来源于 ebay。
|
||||
|
||||
基本思路如下:
|
||||
基本思路如下:
|
||||
|
||||
每个分布式节点都需要额外建一个消息表。
|
||||
每个分布式节点都需要额外建一个消息表。
|
||||
|
||||
消息生产方,记录消息发送状态。消息表和业务数据放在一个事物里提交,然后消息经过MQ发送到消息的消费方,如果消息发送失败,进行重新发送。
|
||||
消息生产方,记录消息发送状态。消息表和业务数据放在一个事物里提交,然后消息经过 MQ 发送到消息的消费方,如果消息发送失败,进行重新发送。
|
||||
|
||||
消息消费方,需要处理这个消息,并完成自己的业务逻辑,同上也要将消息记录到消息表中,此时如果本地事务处理成功,将消息通过MQ发送给下一个消费方,知道所有事物执行完毕,如果事物处理失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作,生产方再向上传递,直到回到初始状态。
|
||||
消息消费方,需要处理这个消息,并完成自己的业务逻辑,同上也要将消息记录到消息表中,此时如果本地事务处理成功,将消息通过 MQ 发送给下一个消费方,知道所有事物执行完毕,如果事物处理失败,可以给生产方发送一个业务补偿消息,通知生产方进行回滚等操作,生产方再向上传递,直到回到初始状态。
|
||||
|
||||
生产方和消费方定时扫描本地消息表,把还没处理玩的消息或失败消息再次发送一遍,这需要一个靠谱的自动对账补账逻辑。
|
||||
生产方和消费方定时扫描本地消息表,把还没处理玩的消息或失败消息再次发送一遍,这需要一个靠谱的自动对账补账逻辑。
|
||||
|
||||
这种方案遵循BASE理论,采用最终一致性,实现较为简单,性能也不错。
|
||||
这种方案遵循 BASE 理论,采用最终一致性,实现较为简单,性能也不错。
|
||||
|
||||
**优点**:一种非常经典的实现,避免了分布式事务,实现了最终一致性。
|
||||
|
||||
**缺点**:消息表耦合到了业务系统中。
|
||||
|
||||
|
@ -7,7 +7,7 @@ category="数据库"
|
||||
serie="分布式事务"
|
||||
---
|
||||
|
||||
## 一、 数据库事务四大特性ACID
|
||||
## 一、 数据库事务四大特性 ACID
|
||||
|
||||
### 1、 原子性(Atomicity)
|
||||
|
||||
@ -16,13 +16,13 @@ serie="分布式事务"
|
||||
### 2、一致性(Consistency)
|
||||
|
||||
  一致性是指事务必须使数据库从一个一致性状态变成另一个一致性状态,也就是事务执行前后必须处于一致性状态。
|
||||
  以转账为例,假设用户A和B两者的钱加起来是5000,那么不管A和B之间如何转账,转多少次,事务结束后两个用户的钱加起来应该还得是5000,这就是事务的一致性。
|
||||
  以转账为例,假设用户 A 和 B 两者的钱加起来是 5000,那么不管 A 和 B 之间如何转账,转多少次,事务结束后两个用户的钱加起来应该还得是 5000,这就是事务的一致性。
|
||||
|
||||
### 3、 隔离性(Isolation)
|
||||
|
||||
  隔离性是当多个用户并发访问数据库时,比如操作同一张表时,数据库为每一个用户开启的事务,不能被其它的事务操作所干扰,多个并发事务之间要相互隔离。
|
||||
|
||||
  既要达到这么一种效果:对于任意的两个并发的事务T1和T2,它们相互之间感觉不到对方正在并发的执行,关于事务的隔离性数据库提供了多种隔离级别,假设我们不考虑隔离性会发生什么问题呢?
|
||||
  既要达到这么一种效果:对于任意的两个并发的事务 T1 和 T2,它们相互之间感觉不到对方正在并发的执行,关于事务的隔离性数据库提供了多种隔离级别,假设我们不考虑隔离性会发生什么问题呢?
|
||||
|
||||
- 脏读
|
||||
|
||||
@ -34,21 +34,21 @@ serie="分布式事务"
|
||||
|
||||
- 幻读(虚读)
|
||||
|
||||
幻读是事物非独立执行时发生的一种现象,例如事物T1对一个表中所有的行的某个数据设置为了1,这时还有一个其他操作向该表中插入了一行数据,并且数据不为1,如果操作T1的用户查看刚刚修改的数据就会发现还有一行没有修改,其实这行是在修改操作完毕后新加入的一条数据。
|
||||
幻读是事物非独立执行时发生的一种现象,例如事物 T1 对一个表中所有的行的某个数据设置为了 1,这时还有一个其他操作向该表中插入了一行数据,并且数据不为 1,如果操作 T1 的用户查看刚刚修改的数据就会发现还有一行没有修改,其实这行是在修改操作完毕后新加入的一条数据。
|
||||
|
||||
### 4、 持久性
|
||||
|
||||
  持久性是指一个事务一旦被提交了,那么对数据库中的数据的改变就是永久性的,即使在数据库系统遇到故障的情况下也不会丢失提交事务的操作。
|
||||
|
||||
   例如我们在使用jdbc操作数据库时,在提交事务方法成功后,就可以认定事务已经被正确提交,即使数据发生重大故障,操作也会正确完成。
|
||||
   例如我们在使用 jdbc 操作数据库时,在提交事务方法成功后,就可以认定事务已经被正确提交,即使数据发生重大故障,操作也会正确完成。
|
||||
|
||||
## 二、 四种隔离级别
|
||||
|
||||
  Mysql数据库提供了四种数据库的隔离级别:
|
||||
  Mysql 数据库提供了四种数据库的隔离级别:
|
||||
|
||||
1. Serializable(串行化):对表加了读写锁,每次读写都需要获取共享锁,丧失了并发速度,可避免脏读,不可重复读,幻读的发生
|
||||
2. Repeatable read(可重复读):在同一个事务内的查询都是事务开始时刻一致的,可避免脏读、不可重复读的发生
|
||||
3. Read committed(读已提交):只能读取到已经提交的数据,避免了脏读的发生。
|
||||
4. Read uncommitted(读未提交):所有都能读取到,啥都无法避免
|
||||
|
||||
  Mysql默认的事务隔离级别是2。
|
||||
  Mysql 默认的事务隔离级别是 2。
|
||||
|
@ -6,35 +6,32 @@ tags=["vmware","nat","ping","ubuntu"]
|
||||
category="java"
|
||||
serie="正则匹配"
|
||||
---
|
||||
[id]:2018-08-04
|
||||
[type]:软件
|
||||
[tag]:vmware,vps,nat,ubuntu
|
||||
|
||||
## 1、wmware设置
|
||||
## 1、wmware 设置
|
||||
|
||||
  这篇记录下nat网络模式下虚拟机与主机的相互ping通。首先使用wmware建立一个ubuntu虚拟机,网络模式选择nat模式。然后点击虚拟网络编辑:
|
||||
  这篇记录下 nat 网络模式下虚拟机与主机的相互 ping 通。首先使用 wmware 建立一个 ubuntu 虚拟机,网络模式选择 nat 模式。然后点击虚拟网络编辑:
|
||||
|
||||
![1536153781962](./picFolder/pic1.png)
|
||||
![虚拟机网络编辑](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E7%BD%91%E7%BB%9C/20190107102915.png)
|
||||
|
||||
接下来点击nat设置:
|
||||
接下来点击 nat 设置:
|
||||
|
||||
![1536153954193](./picFolder/pic2.png)
|
||||
![nat设置](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E7%BD%91%E7%BB%9C/20190107102934.png)
|
||||
|
||||
看到如下:
|
||||
|
||||
![pic3](./picFolder/pic3.png)
|
||||
![pic](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E7%BD%91%E7%BB%9C/20190107102951.png)
|
||||
|
||||
上面红框是关键,记录这个值,下面虚拟机设置静态ip要用到。
|
||||
上面红框是关键,记录这个值,下面虚拟机设置静态 ip 要用到。
|
||||
|
||||
## 2、window网络设置
|
||||
## 2、window 网络设置
|
||||
|
||||
  打开网络适配器页面,选择VMnet,右键->属性->Internet协议版本 4(TCP/IPV4)->属性,设置ip地址为上面上面网关地址最后一个数改成1,比如192.168.128.2就要设置为192.168.128.1,同时设置子网掩码为255.255.255.0,默认网关不要填。我的如下:
|
||||
  打开网络适配器页面,选择 VMnet,右键->属性->Internet 协议版本 4(TCP/IPV4)->属性,设置 ip 地址为上面上面网关地址最后一个数改成 1,比如 192.168.128.2 就要设置为 192.168.128.1,同时设置子网掩码为 255.255.255.0,默认网关不要填。我的如下:
|
||||
|
||||
![pic4](./picFolder/pic4.png)
|
||||
![pic4](https://raw.githubusercontent.com/FleyX/files/master/blogImg/%E7%BD%91%E7%BB%9C/20190107103024.png)
|
||||
|
||||
**如果想让虚拟机能够访问主机需要关闭主机的防火墙**
|
||||
|
||||
## 3、ubuntu设置
|
||||
## 3、ubuntu 设置
|
||||
|
||||
  编辑/etc/network/interfaces
|
||||
|
||||
@ -66,4 +63,4 @@ dns-nameservers 192.168.128.2
|
||||
|
||||
## 3、验证
|
||||
|
||||
  现在虚拟机中`ping 192.168.128.1`可以ping通,主机中`ping 192.168.128.129`也可ping通。
|
||||
  现在虚拟机中`ping 192.168.128.1`可以 ping 通,主机中`ping 192.168.128.129`也可 ping 通。
|
||||
|
Before Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 83 KiB |
Before Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 67 KiB |