1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-16 18:10:13 +08:00

[refractor]删除Sring部分文章

This commit is contained in:
guide 2020-10-16 12:16:42 +08:00
parent 89c3bccef2
commit f80a2dd60a
7 changed files with 6 additions and 813 deletions

View File

@ -45,7 +45,7 @@
</table>
## Java
## Java(必看:+1: )
### 基础
@ -156,12 +156,11 @@
## 系统设计
### 编码规范
### 编码之道(必看 :+1:)
1. [RestFul API 简明教程](docs/system-design/restful-api.md)
1. [RestFul API 简明教程](docs/system-design/coding-way/RESTfulAPI简明教程.md)
2. [Java 编程规范以及优雅 Java 代码实践总结](docs/java/Java编程规范.md)
3. [Java 命名之道](docs/system-design/naming.md)
4. [设计模式系列文章](docs/system-design/设计模式.md)
### 常用框架
@ -176,11 +175,9 @@
**重要知识点详解:**
1. **[Spring/Spring 常用注解总结!安排!](./docs/system-design/framework/spring/spring-annotations.md)**
2. **[Spring 事务总结](docs/system-design/framework/spring/spring-transaction.md)**
1. **[Spring/Spring 常用注解总结!安排!](./docs/system-design/framework/spring/SpringBoot+Spring常用注解总结.md)** (必看 :+1:)
2. **[Spring 事务总结](docs/system-design/framework/spring/spring-transaction.md)** (必看 :+1:)
3. [Spring 中都用到了那些设计模式?](docs/system-design/framework/spring/Spring-Design-Patterns.md)
4. [Spring 中 Bean 的作用域与生命周期](docs/system-design/framework/spring/SpringBean.md)
5. [SpringMVC 工作原理详解](docs/system-design/framework/spring/SpringMVC-Principle.md)
#### MyBatis

View File

@ -1,451 +0,0 @@
<!-- MarkdownTOC -->
- [前言](#前言)
- [一 bean的作用域](#一-bean的作用域)
- [1. singleton——唯一 bean 实例](#1-singleton——唯一-bean-实例)
- [2. prototype——每次请求都会创建一个新的 bean 实例](#2-prototype——每次请求都会创建一个新的-bean-实例)
- [3. request——每一次HTTP请求都会产生一个新的bean该bean仅在当前HTTP request内有效](#3-request——每一次http请求都会产生一个新的bean该bean仅在当前http-request内有效)
- [4. session——每一次HTTP请求都会产生一个新的 bean该bean仅在当前 HTTP session 内有效](#4-session——每一次http请求都会产生一个新的-bean该bean仅在当前-http-session-内有效)
- [5. globalSession](#5-globalsession)
- [二 bean的生命周期](#二-bean的生命周期)
- [initialization 和 destroy](#initialization-和-destroy)
- [实现*Aware接口 在Bean中使用Spring框架的一些对象](#实现aware接口-在bean中使用spring框架的一些对象)
- [BeanPostProcessor](#beanpostprocessor)
- [总结](#总结)
- [单例管理的对象](#单例管理的对象)
- [非单例管理的对象](#非单例管理的对象)
- [三 说明](#三-说明)
<!-- /MarkdownTOC -->
# 前言
在 Spring 中,那些组成应用程序的主体及由 Spring IOC 容器所管理的对象,被称之为 bean。简单地讲bean 就是由 IOC 容器初始化、装配及管理的对象除此之外bean 就与应用程序中的其他对象没有什么区别了。而 bean 的定义以及 bean 相互间的依赖关系将通过配置元数据来描述。
**Spring中的bean默认都是单例的这些单例Bean在多线程程序下如何保证线程安全呢** 例如对于Web应用来说Web容器对于每个用户请求都创建一个单独的Sevlet线程来处理请求引入Spring框架之后每个Action都是单例的那么对于Spring托管的单例Service Bean如何保证其安全呢 **Spring的单例是基于BeanFactory也就是Spring容器的单例Bean在此容器内只有一个Java的单例是基于 JVM每个 JVM 内只有一个实例。**
在大多数情况下。单例 bean 是很理想的方案。不过,有时候你可能会发现你所使用的类是易变的,它们会保持一些状态,因此重用是不安全的。在这种情况下,将 class 声明为单例的就不是那么明智了。因为对象会被污染,稍后重用的时候会出现意想不到的问题。所以 Spring 定义了多种作用域的bean。
# 一 bean的作用域
创建一个bean定义其实质是用该bean定义对应的类来创建真正实例的“配方”。把bean定义看成一个配方很有意义它与class很类似只根据一张“处方”就可以创建多个实例。不仅可以控制注入到对象中的各种依赖和配置值还可以控制该对象的作用域。这样可以灵活选择所建对象的作用域而不必在Java Class级定义作用域。Spring Framework支持五种作用域分别阐述如下表。
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-17/1188352.jpg)
五种作用域中,**request、session** 和 **global session** 三种作用域仅在基于web的应用中使用不必关心你所采用的是什么web应用框架只能用在基于 web 的 Spring ApplicationContext 环境。
### 1. singleton——唯一 bean 实例
**当一个 bean 的作用域为 singleton那么Spring IoC容器中只会存在一个共享的 bean 实例,并且所有对 bean 的请求,只要 id 与该 bean 定义相匹配则只会返回bean的同一实例。** singleton 是单例类型(对应于单例模式)就是在创建起容器时就同时自动创建了一个bean的对象不管你是否使用但我们可以指定Bean节点的 `lazy-init=”true”` 来延迟初始化bean这时候只有在第一次获取bean时才会初始化bean即第一次请求该bean时才初始化。 每次获取到的对象都是同一个对象。注意singleton 作用域是Spring中的缺省作用域。要在XML中将 bean 定义成 singleton ,可以这样配置:
```xml
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">
```
也可以通过 `@Scope` 注解它可以显示指定bean的作用范围。的方式
```java
@Service
@Scope("singleton")
public class ServiceImpl{
}
```
### 2. prototype——每次请求都会创建一个新的 bean 实例
**当一个bean的作用域为 prototype表示一个 bean 定义对应多个对象实例。** **prototype 作用域的 bean 会导致在每次对该 bean 请求**(将其注入到另一个 bean 中,或者以程序的方式调用容器的 getBean() 方法**)时都会创建一个新的 bean 实例。prototype 是原型类型它在我们创建容器的时候并没有实例化而是当我们获取bean的时候才会去创建一个对象而且我们每次获取到的对象都不是同一个对象。根据经验对有状态的 bean 应该使用 prototype 作用域,而对无状态的 bean 则应该使用 singleton 作用域。** 在 XML 中将 bean 定义成 prototype ,可以这样配置:
```java
<bean id="account" class="com.foo.DefaultAccount" scope="prototype"/>
或者
<bean id="account" class="com.foo.DefaultAccount" singleton="false"/>
```
通过 `@Scope` 注解的方式实现就不做演示了。
### 3. request——每一次HTTP请求都会产生一个新的bean该bean仅在当前HTTP request内有效
**request只适用于Web程序每一次 HTTP 请求都会产生一个新的bean同时该bean仅在当前HTTP request内有效当请求结束后该对象的生命周期即告结束。** 在 XML 中将 bean 定义成 request ,可以这样配置:
```java
<bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
```
### 4. session——每一次HTTP请求都会产生一个新的 bean该bean仅在当前 HTTP session 内有效
**session只适用于Web程序session 作用域表示该针对每一次 HTTP 请求都会产生一个新的 bean同时该 bean 仅在当前 HTTP session 内有效.与request作用域一样可以根据需要放心的更改所创建实例的内部状态而别的 HTTP session 中根据 userPreferences 创建的实例,将不会看到这些特定于某个 HTTP session 的状态变化。当HTTP session最终被废弃的时候在该HTTP session作用域内的bean也会被废弃掉。**
```xml
<bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
```
### 5. globalSession
global session 作用域类似于标准的 HTTP session 作用域,不过仅仅在基于 portlet 的 web 应用中才有意义。Portlet 规范定义了全局 Session 的概念,它被所有构成某个 portlet web 应用的各种不同的 portle t所共享。在global session 作用域中定义的 bean 被限定于全局portlet Session的生命周期范围内。
```xml
<bean id="user" class="com.foo.Preferences "scope="globalSession"/>
```
# 二 bean的生命周期
Spring Bean是Spring应用中最最重要的部分了。所以来看看Spring容器在初始化一个bean的时候会做那些事情顺序是怎样的在容器关闭的时候又会做哪些事情。
> spring版本4.2.3.RELEASE
鉴于Spring源码是用gradle构建的我也决定舍弃我大maven尝试下洪菊推荐过的gradle。运行beanLifeCycle模块下的junit test即可在控制台看到如下输出可以清楚了解Spring容器在创建初始化和销毁Bean的时候依次做了那些事情。
```
Spring容器初始化
=====================================
调用GiraffeService无参构造函数
GiraffeService中利用set方法设置属性值
调用setBeanName:: Bean Name defined in context=giraffeService
调用setBeanClassLoader,ClassLoader Name = sun.misc.Launcher$AppClassLoader
调用setBeanFactory,setBeanFactory:: giraffe bean singleton=true
调用setEnvironment
调用setResourceLoader:: Resource File Name=spring-beans.xml
调用setApplicationEventPublisher
调用setApplicationContext:: Bean Definition Names=[giraffeService, org.springframework.context.annotation.CommonAnnotationBeanPostProcessor#0, com.giraffe.spring.service.GiraffeServicePostProcessor#0]
执行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=giraffeService
调用PostConstruct注解标注的方法
执行InitializingBean接口的afterPropertiesSet方法
执行配置的init-method
执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=giraffeService
Spring容器初始化完毕
=====================================
从容器中获取Bean
giraffe Name=李光洙
=====================================
调用preDestroy注解标注的方法
执行DisposableBean接口的destroy方法
执行配置的destroy-method
Spring容器关闭
```
先来看看Spring在Bean从创建到销毁的生命周期中可能做得事情。
### initialization 和 destroy
有时我们需要在Bean属性值set好之后和Bean销毁之前做一些事情比如检查Bean中某个属性是否被正常的设置好值了。Spring框架提供了多种方法让我们可以在Spring Bean的生命周期中执行initialization和pre-destroy方法。
**1.实现InitializingBean和DisposableBean接口**
这两个接口都只包含一个方法。通过实现InitializingBean接口的afterPropertiesSet()方法可以在Bean属性值设置好之后做一些操作实现DisposableBean接口的destroy()方法可以在销毁Bean之前做一些操作。
例子如下:
```java
public class GiraffeService implements InitializingBean,DisposableBean {
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("执行InitializingBean接口的afterPropertiesSet方法");
}
@Override
public void destroy() throws Exception {
System.out.println("执行DisposableBean接口的destroy方法");
}
}
```
这种方法比较简单但是不建议使用。因为这样会将Bean的实现和Spring框架耦合在一起。
**2.在bean的配置文件中指定init-method和destroy-method方法**
Spring允许我们创建自己的 init 方法和 destroy 方法,只要在 Bean 的配置文件中指定 init-method 和 destroy-method 的值就可以在 Bean 初始化时和销毁之前执行一些操作。
例子如下:
```java
public class GiraffeService {
//通过<bean>的destroy-method属性指定的销毁方法
public void destroyMethod() throws Exception {
System.out.println("执行配置的destroy-method");
}
//通过<bean>的init-method属性指定的初始化方法
public void initMethod() throws Exception {
System.out.println("执行配置的init-method");
}
}
```
配置文件中的配置:
```
<bean name="giraffeService" class="com.giraffe.spring.service.GiraffeService" init-method="initMethod" destroy-method="destroyMethod">
</bean>
```
需要注意的是自定义的init-method和destroy-method方法可以抛异常但是不能有参数。
这种方式比较推荐因为可以自己创建方法无需将Bean的实现直接依赖于spring的框架。
**3.使用@PostConstruct和@PreDestroy注解**
除了xml配置的方式Spring 也支持用 `@PostConstruct``@PreDestroy`注解来指定 `init``destroy` 方法。这两个注解均在`javax.annotation` 包中。为了注解可以生效需要在配置文件中定义org.springframework.context.annotation.CommonAnnotationBeanPostProcessor或context:annotation-config
例子如下:
```java
public class GiraffeService {
@PostConstruct
public void initPostConstruct(){
System.out.println("执行PostConstruct注解标注的方法");
}
@PreDestroy
public void preDestroy(){
System.out.println("执行preDestroy注解标注的方法");
}
}
```
配置文件:
```xml
<bean class="org.springframework.context.annotation.CommonAnnotationBeanPostProcessor" />
```
### 实现*Aware接口 在Bean中使用Spring框架的一些对象
有些时候我们需要在 Bean 的初始化中使用 Spring 框架自身的一些对象来执行一些操作,比如获取 ServletContext 的一些参数,获取 ApplicaitionContext 中的 BeanDefinition 的名字,获取 Bean 在容器中的名字等等。为了让 Bean 可以获取到框架自身的一些对象Spring 提供了一组名为*Aware的接口。
这些接口均继承于`org.springframework.beans.factory.Aware`标记接口,并提供一个将由 Bean 实现的set*方法,Spring通过基于setter的依赖注入方式使相应的对象可以被Bean使用。
网上说这些接口是利用观察者模式实现的类似于servlet listeners目前还不明白不过这也不在本文的讨论范围内。
介绍一些重要的Aware接口
- **ApplicationContextAware**: 获得ApplicationContext对象,可以用来获取所有Bean definition的名字。
- **BeanFactoryAware**:获得BeanFactory对象可以用来检测Bean的作用域。
- **BeanNameAware**:获得Bean在配置文件中定义的名字。
- **ResourceLoaderAware**:获得ResourceLoader对象可以获得classpath中某个文件。
- **ServletContextAware**:在一个MVC应用中可以获取ServletContext对象可以读取context中的参数。
- **ServletConfigAware** 在一个MVC应用中可以获取ServletConfig对象可以读取config中的参数。
```java
public class GiraffeService implements ApplicationContextAware,
ApplicationEventPublisherAware, BeanClassLoaderAware, BeanFactoryAware,
BeanNameAware, EnvironmentAware, ImportAware, ResourceLoaderAware{
@Override
public void setBeanClassLoader(ClassLoader classLoader) {
System.out.println("执行setBeanClassLoader,ClassLoader Name = " + classLoader.getClass().getName());
}
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("执行setBeanFactory,setBeanFactory:: giraffe bean singleton=" + beanFactory.isSingleton("giraffeService"));
}
@Override
public void setBeanName(String s) {
System.out.println("执行setBeanName:: Bean Name defined in context="
+ s);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("执行setApplicationContext:: Bean Definition Names="
+ Arrays.toString(applicationContext.getBeanDefinitionNames()));
}
@Override
public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
System.out.println("执行setApplicationEventPublisher");
}
@Override
public void setEnvironment(Environment environment) {
System.out.println("执行setEnvironment");
}
@Override
public void setResourceLoader(ResourceLoader resourceLoader) {
Resource resource = resourceLoader.getResource("classpath:spring-beans.xml");
System.out.println("执行setResourceLoader:: Resource File Name="
+ resource.getFilename());
}
@Override
public void setImportMetadata(AnnotationMetadata annotationMetadata) {
System.out.println("执行setImportMetadata");
}
}
```
### BeanPostProcessor
上面的*Aware接口是针对某个实现这些接口的Bean定制初始化的过程
Spring同样可以针对容器中的所有Bean或者某些Bean定制初始化过程只需提供一个实现BeanPostProcessor接口的类即可。 该接口中包含两个方法postProcessBeforeInitialization和postProcessAfterInitialization。 postProcessBeforeInitialization方法会在容器中的Bean初始化之前执行 postProcessAfterInitialization方法在容器中的Bean初始化之后执行。
例子如下:
```java
public class CustomerBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行BeanPostProcessor的postProcessBeforeInitialization方法,beanName=" + beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("执行BeanPostProcessor的postProcessAfterInitialization方法,beanName=" + beanName);
return bean;
}
}
```
要将BeanPostProcessor的Bean像其他Bean一样定义在配置文件中
```xml
<bean class="com.giraffe.spring.service.CustomerBeanPostProcessor"/>
```
### 总结
所以。。。结合第一节控制台输出的内容Spring Bean的生命周期是这样纸的
- Bean容器找到配置文件中 Spring Bean 的定义。
- Bean容器利用Java Reflection API创建一个Bean的实例。
- 如果涉及到一些属性值 利用set方法设置一些属性值。
- 如果Bean实现了BeanNameAware接口调用setBeanName()方法传入Bean的名字。
- 如果Bean实现了BeanClassLoaderAware接口调用setBeanClassLoader()方法传入ClassLoader对象的实例。
- 如果Bean实现了BeanFactoryAware接口调用setBeanFactory()方法传入BeanFactory对象的实例。
- 与上面的类似,如果实现了其他*Aware接口就调用相应的方法。
- 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象执行postProcessBeforeInitialization()方法
- 如果Bean实现了InitializingBean接口执行afterPropertiesSet()方法。
- 如果Bean在配置文件中的定义包含init-method属性执行指定的方法。
- 如果有和加载这个Bean的Spring容器相关的BeanPostProcessor对象执行postProcessAfterInitialization()方法
- 当要销毁Bean的时候如果Bean实现了DisposableBean接口执行destroy()方法。
- 当要销毁Bean的时候如果Bean在配置文件中的定义包含destroy-method属性执行指定的方法。
用图表示一下(图来源:http://www.jianshu.com/p/d00539babca5)
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-17/48376272.jpg)
与之比较类似的中文版本:
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-9-17/5496407.jpg)
**其实很多时候我们并不会真的去实现上面说描述的那些接口那么下面我们就除去那些接口针对bean的单例和非单例来描述下bean的生命周期**
### 单例管理的对象
当scope=”singleton”即默认情况下会在启动容器时即实例化容器时时实例化。但我们可以指定Bean节点的lazy-init=”true”来延迟初始化bean这时候只有在第一次获取bean时才会初始化bean即第一次请求该bean时才初始化。如下配置
```xml
<bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" lazy-init="true"/>
```
如果想对所有的默认单例bean都应用延迟初始化可以在根节点beans设置default-lazy-init属性为true如下所示
```xml
<beans default-lazy-init="true" >
```
默认情况下Spring 在读取 xml 文件的时候,就会创建对象。在创建对象的时候先调用构造器,然后调用 init-method 属性值中所指定的方法。对象在被销毁的时候,会调用 destroy-method 属性值中所指定的方法例如调用Container.destroy()方法的时候)。写一个测试类,代码如下:
```java
public class LifeBean {
private String name;
public LifeBean(){
System.out.println("LifeBean()构造函数");
}
public String getName() {
return name;
}
public void setName(String name) {
System.out.println("setName()");
this.name = name;
}
public void init(){
System.out.println("this is init of lifeBean");
}
public void destory(){
System.out.println("this is destory of lifeBean " + this);
}
}
```
 life.xml配置如下
```xml
<bean id="life_singleton" class="com.bean.LifeBean" scope="singleton"
init-method="init" destroy-method="destory" lazy-init="true"/>
```
测试代码:
```java
public class LifeTest {
@Test
public void test() {
AbstractApplicationContext container =
new ClassPathXmlApplicationContext("life.xml");
LifeBean life1 = (LifeBean)container.getBean("life");
System.out.println(life1);
container.close();
}
}
```
运行结果:
```
LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@573f2bb1
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1
```
### 非单例管理的对象
`scope=”prototype”`时,容器也会延迟初始化 beanSpring 读取xml 文件的时候,并不会立刻创建对象,而是在第一次请求该 bean 时才初始化如调用getBean方法时。在第一次请求每一个 prototype 的bean 时Spring容器都会调用其构造器创建这个对象然后调用`init-method`属性值中所指定的方法。对象销毁的时候Spring 容器不会帮我们调用任何方法因为是非单例这个类型的对象有很多个Spring容器一旦把这个对象交给你之后就不再管理这个对象了。
为了测试prototype bean的生命周期life.xml配置如下
```xml
<bean id="life_prototype" class="com.bean.LifeBean" scope="prototype" init-method="init" destroy-method="destory"/>
```
测试程序:
```java
public class LifeTest {
@Test
public void test() {
AbstractApplicationContext container = new ClassPathXmlApplicationContext("life.xml");
LifeBean life1 = (LifeBean)container.getBean("life_singleton");
System.out.println(life1);
LifeBean life3 = (LifeBean)container.getBean("life_prototype");
System.out.println(life3);
container.close();
}
}
```
运行结果:
```
LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@573f2bb1
LifeBean()构造函数
this is init of lifeBean
com.bean.LifeBean@5ae9a829
……
this is destory of lifeBean com.bean.LifeBean@573f2bb1
```
可以发现,对于作用域为 prototype 的 bean ,其`destroy`方法并没有被调用。**如果 bean 的 scope 设为prototype时当容器关闭时`destroy` 方法不会被调用。对于 prototype 作用域的 bean有一点非常重要那就是 Spring不能对一个 prototype bean 的整个生命周期负责容器在初始化、配置、装饰或者是装配完一个prototype实例后将它交给客户端随后就对该prototype实例不闻不问了。** 不管何种作用域容器都会调用所有对象的初始化生命周期回调方法。但对prototype而言任何配置好的析构生命周期回调方法都将不会被调用。**清除prototype作用域的对象并释放任何prototype bean所持有的昂贵资源都是客户端代码的职责**让Spring容器释放被prototype作用域bean占用资源的一种可行方式是通过使用bean的后置处理器该处理器持有要被清除的bean的引用。谈及prototype作用域的bean时在某些方面你可以将Spring容器的角色看作是Java new操作的替代者任何迟于该时间点的生命周期事宜都得交由客户端来处理。
**Spring 容器可以管理 singleton 作用域下 bean 的生命周期在此作用域下Spring 能够精确地知道bean何时被创建何时初始化完成以及何时被销毁。而对于 prototype 作用域的beanSpring只负责创建当容器创建了 bean 的实例后bean 的实例就交给了客户端的代码管理Spring容器将不再跟踪其生命周期并且不会管理那些被配置成prototype作用域的bean的生命周期。**
# 三 说明
本文的完成结合了下面两篇文章,并做了相应修改:
- https://blog.csdn.net/fuzhongmin05/article/details/73389779
- https://yemengying.com/2016/07/14/spring-bean-life-cycle/
由于本文非本人独立原创,所以未声明为原创!在此说明!

View File

@ -315,7 +315,7 @@ public class UserRegisterRequest {
这样我们的后端就可以直接把 json 格式的数据映射到我们的 `UserRegisterRequest` 类上。
![](https://cdn.jsdelivr.net/gh/javaguide-tech/blog-images/2020-08/663d1ec1-7ebc-41ab-8431-159dc1ec6589.png)
![](images/spring-annotations/@RequestBody.png)
👉 需要注意的是:**一个请求方法只可以有一个`@RequestBody`,但是可以有多个`@RequestParam``@PathVariable`**。 如果你的方法必须要用两个 `@RequestBody`来接受数据的话,大概率是你的数据库设计或者系统设计出问题了!

View File

@ -1,269 +0,0 @@
> 本文整理自网络,原文出处暂不知,对原文做了较大的改动,在此说明!
### 先来看一下什么是 MVC 模式
MVC 是一种设计模式.
**MVC 的原理图如下:**
![](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-10-11/60679444.jpg)
### SpringMVC 简单介绍
SpringMVC 框架是以请求为驱动,围绕 Servlet 设计,将请求发给控制器,然后通过模型对象,分派器来展示请求结果视图。其中核心类是 DispatcherServlet它是一个 Servlet顶层是实现的Servlet接口。
### SpringMVC 使用
需要在 web.xml 中配置 DispatcherServlet 。并且需要配置 Spring 监听器ContextLoaderListener
```xml
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>springmvc</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<!-- 如果不设置init-param标签则必须在/WEB-INF/下创建xxx-servlet.xml文件其中xxx是servlet-name中配置的名称。 -->
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/springmvc-servlet.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>springmvc</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
```
### SpringMVC 工作原理(重要)
**简单来说:**
客户端发送请求-> 前端控制器 DispatcherServlet 接受客户端请求 -> 找到处理器映射 HandlerMapping 解析请求对应的 Handler-> HandlerAdapter 会根据 Handler 来调用真正的处理器来处理请求,并处理相应的业务逻辑 -> 处理器返回一个模型视图 ModelAndView -> 视图解析器进行解析 -> 返回一个视图对象->前端控制器 DispatcherServlet 渲染数据Model->将得到视图对象返回给用户
**如下图所示:**
![SpringMVC运行原理](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-10-11/49790288.jpg)
上图的一个笔误的小问题Spring MVC 的入口函数也就是前端控制器 DispatcherServlet 的作用是接收请求,响应结果。
**流程说明(重要):**
1客户端浏览器发送请求直接请求到 DispatcherServlet。
2DispatcherServlet 根据请求信息调用 HandlerMapping解析请求对应的 Handler。
3解析到对应的 Handler也就是我们平常说的 Controller 控制器)后,开始由 HandlerAdapter 适配器处理。
4HandlerAdapter 会根据 Handler 来调用真正的处理器开处理请求,并处理相应的业务逻辑。
5处理器处理完业务后会返回一个 ModelAndView 对象Model 是返回的数据对象View 是个逻辑上的 View。
6ViewResolver 会根据逻辑 View 查找实际的 View。
7DispaterServlet 把返回的 Model 传给 View视图渲染
8把 View 返回给请求者(浏览器)
### SpringMVC 重要组件说明
**1、前端控制器DispatcherServlet不需要工程师开发,由框架提供(重要)**
作用:**Spring MVC 的入口函数。接收请求,响应结果,相当于转发器,中央处理器。有了 DispatcherServlet 减少了其它组件之间的耦合度。用户请求到达前端控制器它就相当于mvc模式中的cDispatcherServlet是整个流程控制的中心由它调用其它组件处理用户的请求DispatcherServlet的存在降低了组件之间的耦合性。**
**2、处理器映射器HandlerMapping(不需要工程师开发),由框架提供**
作用根据请求的url查找Handler。HandlerMapping负责根据用户请求找到Handler即处理器ControllerSpringMVC提供了不同的映射器实现不同的映射方式例如配置文件方式实现接口方式注解方式等。
**3、处理器适配器HandlerAdapter**
作用按照特定规则HandlerAdapter要求的规则去执行Handler
通过HandlerAdapter对处理器进行执行这是适配器模式的应用通过扩展适配器可以对更多类型的处理器进行执行。
**4、处理器Handler(需要工程师开发)**
注意编写Handler时按照HandlerAdapter的要求去做这样适配器才可以去正确执行Handler
Handler 是继DispatcherServlet前端控制器的后端控制器在DispatcherServlet的控制下Handler对具体的用户请求进行处理。
由于Handler涉及到具体的用户业务请求所以一般情况需要工程师根据业务需求开发Handler。
**5、视图解析器View resolver(不需要工程师开发),由框架提供**
作用进行视图解析根据逻辑视图名解析成真正的视图view
View Resolver负责将处理结果生成View视图View Resolver首先根据逻辑视图名解析成物理视图名即具体的页面地址再生成View视图对象最后对View进行渲染将处理结果通过页面展示给用户。 springmvc框架提供了很多的View视图类型包括jstlView、freemarkerView、pdfView等。
一般情况下需要通过页面标签或页面模版技术将模型数据通过页面展示给用户,需要由工程师根据业务需求开发具体的页面。
**6、视图View(需要工程师开发)**
View是一个接口实现类支持不同的View类型jsp、freemarker、pdf...
**注意处理器Handler也就是我们平常说的Controller控制器以及视图层view都是需要我们自己手动开发的。其他的一些组件比如前端控制器DispatcherServlet、处理器映射器HandlerMapping、处理器适配器HandlerAdapter等等都是框架提供给我们的不需要自己手动开发。**
### DispatcherServlet详细解析
首先看下源码:
```java
package org.springframework.web.servlet;
@SuppressWarnings("serial")
public class DispatcherServlet extends FrameworkServlet {
public static final String MULTIPART_RESOLVER_BEAN_NAME = "multipartResolver";
public static final String LOCALE_RESOLVER_BEAN_NAME = "localeResolver";
public static final String THEME_RESOLVER_BEAN_NAME = "themeResolver";
public static final String HANDLER_MAPPING_BEAN_NAME = "handlerMapping";
public static final String HANDLER_ADAPTER_BEAN_NAME = "handlerAdapter";
public static final String HANDLER_EXCEPTION_RESOLVER_BEAN_NAME = "handlerExceptionResolver";
public static final String REQUEST_TO_VIEW_NAME_TRANSLATOR_BEAN_NAME = "viewNameTranslator";
public static final String VIEW_RESOLVER_BEAN_NAME = "viewResolver";
public static final String FLASH_MAP_MANAGER_BEAN_NAME = "flashMapManager";
public static final String WEB_APPLICATION_CONTEXT_ATTRIBUTE = DispatcherServlet.class.getName() + ".CONTEXT";
public static final String LOCALE_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".LOCALE_RESOLVER";
public static final String THEME_RESOLVER_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_RESOLVER";
public static final String THEME_SOURCE_ATTRIBUTE = DispatcherServlet.class.getName() + ".THEME_SOURCE";
public static final String INPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".INPUT_FLASH_MAP";
public static final String OUTPUT_FLASH_MAP_ATTRIBUTE = DispatcherServlet.class.getName() + ".OUTPUT_FLASH_MAP";
public static final String FLASH_MAP_MANAGER_ATTRIBUTE = DispatcherServlet.class.getName() + ".FLASH_MAP_MANAGER";
public static final String EXCEPTION_ATTRIBUTE = DispatcherServlet.class.getName() + ".EXCEPTION";
public static final String PAGE_NOT_FOUND_LOG_CATEGORY = "org.springframework.web.servlet.PageNotFound";
private static final String DEFAULT_STRATEGIES_PATH = "DispatcherServlet.properties";
protected static final Log pageNotFoundLogger = LogFactory.getLog(PAGE_NOT_FOUND_LOG_CATEGORY);
private static final Properties defaultStrategies;
static {
try {
ClassPathResource resource = new ClassPathResource(DEFAULT_STRATEGIES_PATH, DispatcherServlet.class);
defaultStrategies = PropertiesLoaderUtils.loadProperties(resource);
}
catch (IOException ex) {
throw new IllegalStateException("Could not load 'DispatcherServlet.properties': " + ex.getMessage());
}
}
/** Detect all HandlerMappings or just expect "handlerMapping" bean? */
private boolean detectAllHandlerMappings = true;
/** Detect all HandlerAdapters or just expect "handlerAdapter" bean? */
private boolean detectAllHandlerAdapters = true;
/** Detect all HandlerExceptionResolvers or just expect "handlerExceptionResolver" bean? */
private boolean detectAllHandlerExceptionResolvers = true;
/** Detect all ViewResolvers or just expect "viewResolver" bean? */
private boolean detectAllViewResolvers = true;
/** Throw a NoHandlerFoundException if no Handler was found to process this request? **/
private boolean throwExceptionIfNoHandlerFound = false;
/** Perform cleanup of request attributes after include request? */
private boolean cleanupAfterInclude = true;
/** MultipartResolver used by this servlet */
private MultipartResolver multipartResolver;
/** LocaleResolver used by this servlet */
private LocaleResolver localeResolver;
/** ThemeResolver used by this servlet */
private ThemeResolver themeResolver;
/** List of HandlerMappings used by this servlet */
private List<HandlerMapping> handlerMappings;
/** List of HandlerAdapters used by this servlet */
private List<HandlerAdapter> handlerAdapters;
/** List of HandlerExceptionResolvers used by this servlet */
private List<HandlerExceptionResolver> handlerExceptionResolvers;
/** RequestToViewNameTranslator used by this servlet */
private RequestToViewNameTranslator viewNameTranslator;
private FlashMapManager flashMapManager;
/** List of ViewResolvers used by this servlet */
private List<ViewResolver> viewResolvers;
public DispatcherServlet() {
super();
}
public DispatcherServlet(WebApplicationContext webApplicationContext) {
super(webApplicationContext);
}
@Override
protected void onRefresh(ApplicationContext context) {
initStrategies(context);
}
protected void initStrategies(ApplicationContext context) {
initMultipartResolver(context);
initLocaleResolver(context);
initThemeResolver(context);
initHandlerMappings(context);
initHandlerAdapters(context);
initHandlerExceptionResolvers(context);
initRequestToViewNameTranslator(context);
initViewResolvers(context);
initFlashMapManager(context);
}
}
```
DispatcherServlet类中的属性beans
- HandlerMapping用于handlers映射请求和一系列的对于拦截器的前处理和后处理大部分用@Controller注解
- HandlerAdapter帮助DispatcherServlet处理映射请求处理程序的适配器而不用考虑实际调用的是 哪个处理程序。- - -
- ViewResolver根据实际配置解析实际的View类型。
- ThemeResolver解决Web应用程序可以使用的主题例如提供个性化布局。
- MultipartResolver解析多部分请求以支持从HTML表单上传文件。-
- FlashMapManager存储并检索可用于将一个请求属性传递到另一个请求的input和output的FlashMap通常用于重定向。
在Web MVC框架中每个DispatcherServlet都拥自己的WebApplicationContext它继承了ApplicationContext。WebApplicationContext包含了其上下文和Servlet实例之间共享的所有的基础框架beans。
**HandlerMapping**
![HandlerMapping](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-10-11/96666164.jpg)
HandlerMapping接口处理请求的映射HandlerMapping接口的实现类
- SimpleUrlHandlerMapping类通过配置文件把URL映射到Controller类。
- DefaultAnnotationHandlerMapping类通过注解把URL映射到Controller类。
**HandlerAdapter**
![HandlerAdapter](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-10-11/91433100.jpg)
HandlerAdapter接口-处理请求映射
AnnotationMethodHandlerAdapter通过注解把请求URL映射到Controller类的方法上。
**HandlerExceptionResolver**
![HandlerExceptionResolver](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-10-11/50343885.jpg)
HandlerExceptionResolver接口-异常处理接口
- SimpleMappingExceptionResolver通过配置文件进行异常处理。
- AnnotationMethodHandlerExceptionResolver通过注解进行异常处理。
**ViewResolver**
![ViewResolver](http://my-blog-to-use.oss-cn-beijing.aliyuncs.com/18-10-11/49497279.jpg)
ViewResolver接口解析View视图。
UrlBasedViewResolver类 通过配置文件把一个视图名交给到一个View来处理。

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

View File

@ -1,84 +0,0 @@
# Java 设计模式
下面是自己学习设计模式的时候做的总结,有些是自己的原创文章,有些是网上写的比较好的文章,保存下来细细消化吧!
**系列文章推荐:**<https://design-patterns.readthedocs.io/zh_CN/latest/index.html>
## 创建型模式
### 创建型模式概述
- 创建型模式(Creational Pattern)对类的实例化过程进行了抽象,能够将软件模块中对象的创建和对象的使用分离。为了使软件的结构更加清晰,外界对于这些对象只需要知道它们共同的接口,而不清楚其具体的实现细节,使整个系统的设计更加符合单一职责原则。
- 创建型模式在创建什么(What),由谁创建(Who),何时创建(When)等方面都为软件设计者提供了尽可能大的灵活性。创建型模式隐藏了类的实例的创建细节,通过隐藏对象如何被创建和组合在一起达到使整个系统独立的目的。
![创建型模式](https://user-gold-cdn.xitu.io/2018/6/16/1640641afcb7559b?w=491&h=241&f=png&s=51443)
### 常见创建型模式详解
- **单例模式:** [深入理解单例模式——只有一个实例](https://blog.csdn.net/qq_34337272/article/details/80455972)
- **工厂模式:** [深入理解工厂模式——由对象工厂生成对象](https://blog.csdn.net/qq_34337272/article/details/80472071)
- **建造者模式:** [深入理解建造者模式 ——组装复杂的实例](http://blog.csdn.net/qq_34337272/article/details/80540059)
- **原型模式:** [深入理解原型模式 ——通过复制生成实例](https://blog.csdn.net/qq_34337272/article/details/80706444)
## 结构型模式
### 结构型模式概述
- **结构型模式(Structural Pattern)** 描述如何将类或者对象结合在一起形成更大的结构,就像搭积木,可以通过简单积木的组合形成复杂的、功能更为强大的结构
![结构型模式(Structural Pattern)](https://user-gold-cdn.xitu.io/2018/6/16/164064d6b3c205e3?w=719&h=233&f=png&s=270293)
- **结构型模式可以分为类结构型模式和对象结构型模式:**
- 类结构型模式关心类的组合,由多个类可以组合成一个更大的系统,在类结构型模式中一般只存在继承关系和实现关系。
- 对象结构型模式关心类与对象的组合,通过关联关系使得在一个类中定义另一个类的实例对象,然后通过该对象调用其方法。根据“合成复用原则”,在系统中尽量使用关联关系来替代继承关系,因此大部分结构型模式都是对象结构型模式。
![结构型模式](https://user-gold-cdn.xitu.io/2018/6/16/1640655459d766d2?w=378&h=266&f=png&s=59652)
### 常见结构型模式详解
- **适配器模式:**
- [深入理解适配器模式——加个“适配器”以便于复用](https://segmentfault.com/a/1190000011856448) https://blog.csdn.net/carson_ho/article/details/54910430
- [适配器模式原理及实例介绍-IBM](https://www.ibm.com/developerworks/cn/java/j-lo-adapter-pattern/index.html)
- **桥接模式:** [设计模式笔记16桥接模式(Bridge Pattern)](https://blog.csdn.net/yangzl2008/article/details/7670996)
- **组合模式:** [大话设计模式—组合模式](https://blog.csdn.net/lmb55/article/details/51039781)
- **装饰模式:** [java模式—装饰者模式](https://www.cnblogs.com/chenxing818/p/4705919.html)、[Java设计模式-装饰者模式](https://blog.csdn.net/cauchyweierstrass/article/details/48240147)
- **外观模式:** [java设计模式之外观模式门面模式](https://www.cnblogs.com/lthIU/p/5860607.html)
- **享元模式:** [享元模式](http://www.jasongj.com/design_pattern/flyweight/)
- **代理模式:**
- [代理模式原理及实例讲解 IBM出品很不错](https://www.ibm.com/developerworks/cn/java/j-lo-proxy-pattern/index.html)
- [轻松学Java 中的代理模式及动态代理](https://blog.csdn.net/briblue/article/details/73928350)
- [Java代理模式及其应用](https://blog.csdn.net/justloveyou_/article/details/74203025)
## 行为型模式
### 行为型模式概述
- 行为型模式(Behavioral Pattern)是对在不同的对象之间划分责任和算法的抽象化。
- 行为型模式不仅仅关注类和对象的结构,而且重点关注它们之间的相互作用。
- 通过行为型模式,可以更加清晰地划分类与对象的职责,并研究系统在运行时实例对象之间的交互。在系统运行时,对象并不是孤立的,它们可以通过相互通信与协作完成某些复杂功能,一个对象在运行时也将影响到其他对象的运行。
**行为型模式分为类行为型模式和对象行为型模式两种:**
- **类行为型模式:** 类的行为型模式使用继承关系在几个类之间分配行为,类行为型模式主要通过多态等方式来分配父类与子类的职责。
- **对象行为型模式:** 对象的行为型模式则使用对象的聚合关联关系来分配行为,对象行为型模式主要是通过对象关联等方式来分配两个或多个类的职责。根据“合成复用原则”,系统中要尽量使用关联关系来取代继承关系,因此大部分行为型设计模式都属于对象行为型设计模式。
![行为型模式](https://user-gold-cdn.xitu.io/2018/6/28/164467dd92c6172c?w=453&h=269&f=png&s=63270)
- **职责链模式:**
- [Java设计模式之责任链模式、职责链模式](https://blog.csdn.net/jason0539/article/details/45091639)
- [责任链模式实现的三种方式](https://www.cnblogs.com/lizo/p/7503862.html)
- **命令模式:** <https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/command.html> 在软件设计中,我们经常需要向某些对象发送请求,但是并不知道请求的接收者是谁,也不知道被请求的操作是哪个,我们只需在程序运行时指定具体的请求接收者即可,此时,可以使用命令模式来进行设计,使得请求发送者与请求接收者消除彼此之间的耦合,让对象之间的调用关系更加灵活。命令模式可以对发送者和接收者完全解耦,发送者与接收者之间没有直接引用关系,发送请求的对象只需要知道如何发送请求,而不必知道如何完成请求。这就是命令模式的模式动机。
- **解释器模式:**
- **迭代器模式:** <https://www.cnblogs.com/zhili/p/IteratorPattern.html>
- **中介者模式:** <https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/mediator.html>
- **备忘录模式:**
- **观察者模式:** <https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/observer.html><https://juejin.im/post/5c712ab56fb9a049a7127114>
- **状态模式:**<https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/state.html>
- **策略模式:**<https://design-patterns.readthedocs.io/zh_CN/latest/behavioral_patterns/strategy.html>
策略模式作为设计原则中开闭原则最典型的体现也是经常使用的。下面这篇博客介绍了策略模式一般的组成部分和概念并用了一个小demo去说明了策略模式的应用。
[java设计模式之策略模式](https://blog.csdn.net/zlj1217/article/details/81230077)
- **模板方法模式:**
- **访问者模式:**