This commit is contained in:
yinkanglong
2023-08-13 16:09:29 +08:00
parent f068be44c3
commit 4c7ee762dc
47 changed files with 1564 additions and 444 deletions

View File

@@ -9,7 +9,7 @@
* 设计模式中的观察者模式
* jdk中的observable和observer
* ui中事件监听机制
* 注册中心和消息队列的订阅发布机制
* 消息队列的订阅发布机制
先是一种对象间的一对多的关系;最简单的如交通信号灯,信号灯是目标(一方),行人注视着信号灯(多方)。当目标发送改变(发布),观察者(订阅者)就可以接收到改变。 观察者如何处理(如行人如何走,是快走/慢走/不走,目标不会管的), 目标无需干涉;所以就松散耦合了它们之间的关系。

View File

@@ -0,0 +1,33 @@
# springApplication创建的方法
### 1.通过类的静态方法直接创建
```java
SpringApplication.run(ApplicationConfiguration.class,args);
```
### 2.通过自定义SpringApplication创建
```java
SpringApplication springApplication = new SpringApplication(ApplicationConfiguration.class); //这里也是传入配置源,但也可以不传
springApplication.setWebApplicationType(WebApplicationType.NONE); //指定服务类型 可以指定成非Web应用和SERVLET应用以及REACTIVE应用
springApplication.setAdditionalProfiles("prod"); //prodFiles配置
Set<String> sources = new HashSet<>(); //创建配置源
sources.add(ApplicationConfiguration.class.getName()); //指定配置源
springApplication.setSources(sources); //设置配置源,注意配置源可以多个
ConfigurableApplicationContext context = springApplication.run(args); //运行SpringApplication 返回值为服务上下文对象
context.close(); //上下文关闭
```
### 3.通过Builder工厂模式
> 只是一种初始化对象的方法。
```java
ConfigurableApplicationContext context = new SpringApplicationBuilder(ApplicationConfiguration.class)//这里也是传入配置源,但也可以不传
.web(WebApplicationType.REACTIVE)
.profiles("java7")
.sources(ApplicationConfiguration.class) //可以多个Class
.run();
context.close(); //上下文关闭
```

View File

@@ -0,0 +1,199 @@
对于spring的bean来讲我们默认可以指定两个生命周期回调方法。一个是在ApplicationContext将bean初始化完全完成后包括注入对应的依赖例如属性注入后的回调方法另一个是在ApplicationContext准备销毁之前的回调方法。
要实现这种回调主要有三种方式:
实现特定的接口。
在XML配置文件中指定回调方法。
使用JSR-250标准的注解。
为什么要调用生命周期回调函数
因为如果在构造方法中执行一些操作实际上spring并没有完成依赖注入调用过程中会报错。因为在spring bean的实例化过程中是先单独实例化PersonService和EvanService的。然后再完成对EvanService的注入。如果不这么做的话而选择在PersonService的构造方法里用EvanService做一些事的话此时的EvanService是还没有完成注入的。
调用构造函数初始化一个对象--> 进行依赖注入 --> 调用生命周期回调函数init方法
## 1 实现特定的接口
针对bean初始化后的回调和ApplicationContext销毁前的回调Spring分别为我们了提供了InitializingBean和DisposableBean接口供用户实现这样Spring在需要进行回调时就会调用对应接口提供的回调方法。
### InitializingBean
InitializingBean是用来定义ApplicationContext在完全初始化一个bean以后需要需要回调的方法的其中只定义了一个afterPropertiesSet()方法。如其名称所描述的那样该方法将在ApplicationContext将一个bean完全初始化包括将对应的依赖项都注入以后才会被调用。InitializingBean的完全定义如下。
```java
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
```
由于InitializingBean的afterPropertiesSet()方法会在依赖项都进行注入以后再回调所以该方法通常会用来检查必要的依赖注入以使我们能够在bean被初始化时就发现其中的错误而不是在很长时间使用以后才发现。如果你去看Spring的源码你就会发现源码中有很多InitializingBean的使用而且基本都是用来检查必要的依赖项是否为空的。
```java
public class Hello implements InitializingBean {
private World world;
/**
* 该方法将在当前bean被完全初始化后被调用
*/
public void afterPropertiesSet() throws Exception {
Assert.notNull(world, "world should not be null.");
}
public void setWorld(World world) {
this.world = world;
}
}
```
### DisposableBean
DisposableBean是用来定义在ApplicationContext销毁之前需要回调的方法的。DisposableBean接口中只定义了一个destroy()方法在ApplicationContext被销毁前Spring将依次调用bean容器中实现了DisposableBean接口的destroy()方法。所以我们可以通过实现该接口的destroy()方法来达到在ApplicationContext销毁前释放某些特定资源的目的。
```
public interface DisposableBean {
void destroy() throws Exception;
}
```
在Spring的源码中也有很多实现了DisposableBean接口的类如我们熟悉的ApplicationContext实现类、SingleConnectionDataSource等。
## 2 在XML中配置回调方法
在XML配置文件中通过bean元素定义一个bean时我们可以通过bean元素的init-method属性和destroy-method属性来指定当前bean在初始化以后和ApplicationContext销毁前的回调方法。需要注意的是所指定的回调方法必须是没有参数的。
通过init-method属性来指定初始化方法时所对应的方法必须是该bean中所拥有的方法所以首先我们需要在对应的bean中定义对应的初始化方法这里假设我们需要在bean中定义一个init()方法作为该bean的初始化方法那么我们可以对我们的bean进行类似如下定义。
```java
public class Hello {
private World world;
/**
* 该方法将被用来作为初始化方法在当前bean被完全初始化后被调用
*/
public void init() {
Assert.notNull(world, "world should not be null.");
}
public void setWorld(World world) {
this.world = world;
}
}
```
接下来就是在XML配置文件中定义该bean时通过init-method属性定义对应的初始化方法为init()方法init-method属性的属性值就对应初始化方法的名称所以我们的bean应该是如下定义。
```xml
<bean name="world" class="com.app.World"/>
<!-- 通过init-method属性指定初始化方法名称 -->
<bean id="hello" class="com.app.Hello" init-method="init">
<property name="world" ref="world"/>
</bean>
```
init-method和destroy-method的用法和配置等基本上都是一样的所以对于使用destroy-method来指定ApplicationContext销毁前的回调方法的用法就不再赘述了。
如果我们的初始化方法或销毁方法的名称大都是一样的在通过init-method和destroy-method进行指定的时候我们就没有必要一个个bean都去指定了Spring允许我们在最顶级的beans元素上指定默认的初始化后回调方法和销毁前的回调方法名称这样对于没有指定init-method或destroy-method的bean将默认将其中default-init-method或default-destroy-method属性值对应名称的方法如果存在的话视为初始化后的回调方法或销毁前的回调方法。这是通过default-init-method和default-destroy-method属性来定义的。
```java
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd"
default-init-method="init" default-destroy-method="destroy">
</beans>
```
以上表示定义默认的初始化后回调方法名称为init默认的销毁前回调方法名称为destroy。
当定义了default-init-method或default-destroy-method以后如果我们的某个bean对应的初始化后回调方法名称或销毁前的回调方法名称与默认定义的不一样则我们可以在对应的bean上通过init-method或destroy-method指定该bean自身的回调方法名称即bean上定义的回调方法名称将会比默认定义拥有更高的优先级。
## 3 使用JSR-250标准的注解
关于bean的生命周期回调方法Spring也会JSR-250标准注解做了支持即在bean完全初始化后将回调使用@PostConstruct标注的方法在销毁ApplicationContext前将回调使用@PreDestroy标注的方法
针对之前的示例如果我们现在把定义的bean定义成如下这样即没有在bean上通过init-method和destroy-method指定初始化方法和销毁方法。
```xml
<bean name="world" class="com.app.World"/>
<bean id="hello" class="com.app.Hello">
<property name="world" ref="world"/>
</bean>
```
当然这里也不考虑全局性的init-method和destroy-method方法如果我们希望在id为“hello”的bean被初始化后回调其中的init()方法在销毁前回调其中的destroy()方法,我们就可以通过@PostConstruct和@PreDestroy进行如下定义
```
public class Hello {
private World world;
/**
* 该方法将被用来作为初始化方法在当前bean被完全初始化后被调用
*/
@PostConstruct
public void init() {
Assert.notNull(world, "world should not be null.");
}
@PreDestroy
public void destroy() {
System.out.println("---------destroy-----------");
}
public void setWorld(World world) {
this.world = world;
}
}
```
使用JSR-250标准指定初始化后的回调方法以及销毁前的回调方法时如果我们希望将多个方法都作为对应的回调方法进行回调则可以在多个方法上同时使用对应的注解进行标注Spring将依次执行对应的方法。
```java
public class Hello {
private World world;
@PostConstruct
public void init() {
System.out.println("-----------init-------------");
}
/**
* 该方法将被用来作为初始化方法在当前bean被完全初始化后被调用
*/
@PostConstruct
public void init2() {
Assert.notNull(world, "world should not be null.");
}
@PreDestroy
public void destroy() {
System.out.println("------------destroy----------------");
}
@PreDestroy
public void destroy2() {
System.out.println("---------destroy2-----------");
}
public void setWorld(World world) {
this.world = world;
}
}
```
## 4 混合使用三种方式
依据spring官方文档
Spring允许我们混合使用上述介绍的三种方式来指定对应的回调方法。当对于同一个bean使用三种方式指定了同一个方法作为初始化后的回调方法或销毁前的回调方法则对应的回调方法只会被执行一次。然而当对于同一个bean使用两种或三种方式指定的回调方法不是同一个方法时Spring将依次执行使用不同的方式指定的回调方法。对于初始化后的回调方法而言具体规则如下
使用@PostConstruct标注的方法
实现InitializingBean接口后的回调方法afterPropertiesSet()方法。
通过init-method或default-init-method指定的方法。
对于销毁前的回调方法而言,其规则是一样的:
使用@PreDestroy标注的方法
实现DisposableBean接口后的回调方法destroy()方法。
通过destroy-method或default-destroy-method指定的方法。