再学习spring&spring-mvc&springboot

Spring的工作

Spring的核心是一个Map,存放了众多的对象。

Spring的一个工作是,根据配置文件,或者类的注解来生成一个对象放在自己的Map中。

这个工作的核心就是生成过程自动化

生成过程自动化

1 根据配置或者类中的注解信息来生成一个对象

常用的手段有IOC控制反转也就是用配置注入生成对象

然后就是依赖注入实际上就是spring自己从Map中找一个匹配的对象注入

spring的第二个工作是,第三方代码自动配置

我们自己的类,可以在spring配置文件中配置,可以在源文件中写注解来配置,让spring来自动生成对象。但是第三方的框架呢?

现在的spring已经非常流行了,各个大框架都已经提供了适配spring的整合模块。这样框架中的类也带有spring的配置信息,这样spring扫描到类的时候就可以自动生成对象放在Map中了。

框架使用spring之后,spring往往掌握了框架的配置权限(因为框架对象都是spring生成的),所以很多框架的配置可以由spring自己进行配置再注入。

spring的最外围的功能是从spring中获取对象

spring对象的生命周期和作用域都是顶级的.所以spring对象又叫做应用上下文,意思是应用就运行在spring容器中.

所以spring的对象叫做ApplicationContext

spring程序的运行就从这个对象的初始化开始了,new这个对象需要指定一个配置文件。叫做applicationContext.xml

通过这个对象的getBean方法可以获得Spring中的对象.

自动生成过程

纯注入

简单类型

xml配置方式

1
2
3
4
5
6
7
8
9
<bean name="myName" class="com.wainyz.MyClass">
<property name="set-function-name" value="字面值(可以是boolean,数值,字符串值)"/>
</bean>
<!-- 或者通过构造方法注入 -->
<bean name="myName" class="com.wainyz.MyClass">
<contructor-arg type="int" value="20"></contructor-arg>
<contructor-arg name="age" value="20"></contructor-arg>
<contructor-arg index="1" value="20"></contructor-arg>
</bean>

注解配置方式

1
2
3
4
5
6
7
8
9
10
11
12
@Component
class MyClass{
@value("字面值")
String oneVar;
MyClass(){}
MyClass(@value("字面值") String temp){
oneVar = temp;
}
public void setOneVar(@value("字面值") String temp){
oneVar = temp;
}
}

集合类型注入

List对象的注入

通过xml方式中的List标签

@Value注解结合SpEL表达式

Set对象的注入

通过xml方式中的Set标签

@Value注解结合SpEL表达式

Map对象的注入

通过xml中的Map标签以及entry标签

@Value注解结合SpEL表达式

依赖注入

依赖注入实际上就是引用类型的注入,让spring找一个对象注入,实际上是获得了对象的引用

所以叫做依赖注入

xml配置方式

1
2
3
4
5
<property name="set name">
<!-- 有一个标签 ref可以直接引用spring 的Map中的对象 -->
<ref bean="bean name"></ref>
</property>

注解配置方式

@AutoWired @Resource

注入的简化语法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<bean id="some_id" class="classpath" p:name="defaultvalue" p:age="17"></bean>
<!-- 相当于下面的代码 -->
<bean id="some_id" class="classpath">
<property name="name" value="deafultvalue"></property>
<property name="age" >
<value>17</value>
</property>
</bean>
<bean id="some_id" class="classpath" c:name="defaultvalue" c:age="17"></bean>
<bean id="libraryAdmin" class="task02.LibraryAdmin">
<constructor-arg type="java.util.List" >
<list>
<!-- 注意简化写法的引用类型就是加上-ref -->
<bean class="task02.Student" c:_0="张三" c:_1-ref="cardRedA"></bean>
<bean class="task02.Student" c:_0="李四" c:_1-ref="cardBlueA"></bean>
<bean class="task02.Student" c:_0="王五" c:_1-ref="cardRedB"></bean>
<bean class="task02.Student" c:_0="赵六" c:_1-ref="cardBlueB"></bean>
</list>
</constructor-arg>
</bean>

生成代理(瞒天过海)

在spring启动的时候就会检查有没有代理任务。根据代理任务在生成对象的时候就先检查是否需要代理,如果需要代理就根据动态代理技术,返回代理对象充当原来的对象。

具体的技术如下:

  1. 切面类@Aspect描述代理任务

如何描述是代理任务?

  1. 描述要代理的方法特征,使用切入表达式
  2. 描述代理的形式,before,after.afterReturning,around,afterThrowing

复杂对象生成

复杂对象不能简单的通过注入的简单形式创建,而是需要执行特定的代码构造之类的.

所以复杂对象的创建我们交给java类自己提供,但是spring需要调用类体提供的方法来创建对象并放置到Map中

如何寻找类提供的创建方法?

一种是让类按照spring的要求实现,这样spring就知道

一种是让spring知道类是怎么实现的,这样spring也能知道

对于第一种就是实现spring提供的接口FactoryBean,对于实现了这种接口的类,在创建对象时会直接调用接口中的方法得到对象,而不是通过new

第二种就是通过配置让spring找到怎么使用这个类

xml方式
1
 
注解

@Configuration

直接通过注解标注,如何获得对象

spring的内部

进行表达式计算

spring将字符串当做表达式字符串进行解析,这样我我们可以用更少的数据表示更多的操作信息

Spring表达式语言(简称“ SpEL”)是一种功能强大的表达式语言,支持在运行时查询和操作对象图。

SpEL提供了一种在Spring应用程序中进行动态计算和注入值的机制,在spring的注解中广泛使用.

动态计算是通过在运行时解析表达式字符串并将其转换为可执行的代码来实现的。在动态计算过程中,程序会根据特定的逻辑和规则,将字符串表示的表达式转换为对应的操作,然后执行这段代码以实现动态计算的功能。动态计算可以根据不同的输入和条件灵活地生成和执行代码,从而实现动态的计算和逻辑处理。

SpEL的应用

Spring框架在以下几个地方使用了SpEL(Spring Expression Language):

  • Spring的注解中,如@Value、@Conditional、@Cacheable等注解中可以使用SpEL表达式来动态设置属性值或条件判断。
  • Spring的XML配置文件中,可以使用SpEL表达式来配置Bean的属性值或条件判断。
  • Spring Security中,可以使用SpEL表达式来定义安全规则和权限控制。
  • Spring Integration中,可以使用SpEL表达式来配置消息路由和转换。
  • Spring Data中,可以使用SpEL表达式来定义查询方法的动态条件。

总的来说,Spring框架中的各个模块都可以通过SpEL表达式来实现动态计算和配置,提高了灵活性和可扩展性。

SpEL(Spring Expression Language)是Spring框架提供的一种表达式语言,用于在运行时查询和操作对象图。它支持查询和操作对象的属性、方法调用、进行算术运算、逻辑运算等操作。通过SpEL表达式,可以在Spring的注解中引用配置文件中的值,实现动态注入和配置管理。SpEL语法简洁灵活,可以方便地实现复杂的逻辑处理和数值计算。

在Spring中,可以使用@Value注解结合SpEL表达式来注入集合类型的值。例如,可以通过以下方式注入一个List集合:

1
2
@Value("#{'${my.list}'.split(',')}")
private List<String> myList;

上述代码中,${my.list}是从配置文件中读取的一个以逗号分隔的字符串,通过split(',')方法将其转换为List集合。这样就可以实现通过@Value注解注入集合类型的值。

也可以调用spring提供的SpEL的接口,处理字符串

具体语法

SpEL(Spring Expression Language)的具体语法包括以下几个方面:

  • 字面量表达式:可以直接表示数字、字符串、布尔值等常量,例如100, 'hello', true
  • 属性引用:通过#{}来引用Bean的属性,例如#{user.name}
  • 方法调用:通过#{}来调用Bean的方法,例如#{user.getName()}
  • 运算符:支持算术运算符(+, -, *, /)、逻辑运算符(and, or, not)、关系运算符(>, <, ==)等。
  • 条件运算:支持三元运算符?:,例如#{score > 60 ? '及格' : '不及格'}
  • 集合操作:支持集合的访问和操作,例如#{list[0]}表示访问List的第一个元素。
  • 正则表达式:支持使用正则表达式进行匹配操作,例如#{#pattern.matches('abc')}
  • 类型操作:支持获取Bean的类型信息,例如#{T(java.lang.Math).PI}表示获取Math类的PI常量。

这些语法元素可以组合在一起,形成复杂的SpEL表达式,用于在Spring中进行动态值的计算和注入。

Spring MVC的工作

Spring MVC实际上就是用自己联系MVC三层。

所以实际上Spring MVC想做的是和Spring一样的事情,接管整个程序。

让MVC三层都包含在Sping MVC的容器中。

然后服务器直接接触的实际上是Spring MVC的容器。

所以我在这里要给Spring MVC改名了,我叫他,服务器 ->spring->mvc。

实际的工作

  1. 拦截服务器的所有请求
  2. 加速MVC三层交流
  3. 向服务器返回结果

拦截请求

唯一的选择

web服务器并不知道,应用程序是什么技术写的,它只认servlet类

所以我们只配置一个servlet,那么这个servlet就拦截了所有请求了

除了拦截的作用之外,这个servlet还要做到分发的功能

Spring MVC提供了这个类

org.springframework.web.servlet.DispathcherServle

翻译过来就是调度员servlet

放行静态请求

例如静态资源的请求,如果不加配置,那么需要写controller来处理请求,所以我们不需要捕获这些请求。

通过application.xml配置

1
2
3
4
<!-- 在springmvc.xml中,使用mvc命名空间的标签 -->
<mvc:resources mapping="/static/**" location="/static/"></mvc:resources>
<!-- mapping的值就是放行请求的url特征 location就是映射到的一个目录/目录指的是 从webapp目录下开始,设置这个值而不是直接通过url进行文件的查找是为了安全以及方便 -->
</mvc:resources>

mvc配置的resources配置所以是mvc:resources

具体配置

一方面让web服务器找到它。

1
2
3
4
5
6
7
8
9
10
11
<!-- 在web.xml中配置 -->
<!-- 只配置一个servlet -->
<servlet>
<servlet-name>some name</servlet-name>
<servlet-class>org.springframework.web.servlet.DispathcherServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>some name</servlet-name>
<!-- 所有路径的请求都接收 -->
<url-pattern>/</url-pattern>
</servlet-mapping>

服务器找到servlet之后会new一个出来,大家都知道。这个时候创建这个调度员servlet的时候就是我们创建spring容器的时候。

1
2
3
4
5
6
7
8
9
<servlet>
<servlet-name>>some name</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:springmvc.xml</param-value>
</init-param>
</servlet>
<!-- servlet mapping ... -->

这里主要表达的内容是,在web.xml中的servlet配置中,要配置一个init-param

将servlet中的一个参数contextConfigLocation配置上我们的spring的配置文件

这样就可以启动spring了.

另外就是spring注解扫描了

对于application.xml

1
2
<mvc:annotion-driver/>
<context:component-scan base-package="com"/>

第一个配置mvc注解扫描引擎

第二个配置注解扫描范围.

分发请求

有一个处理表叫做HandleMap,里面都是处理请求的Controller,也就是Spring内部的请求处理类,对象。

我的调度员servlet,让HandleMapping从HandleMap中找到匹配请求的那个controller,将请求交给controller处理。

衔接视图

在MVC模式中,我们的servlet将数据放在request对象中,然后在jsp中形成返回。

现在spring接管了,所以不再需要requeset作为桥梁,而是使用spring提供的桥梁。

ModelAndView类作为Controller和View的接口类。

现在controller返回modelAndView类给DispatcherServlet,它自会知道如何将数据交由view处理。

具体流程

  1. 客户端发送请求到前端控制器DispatcherServlet。
  2. DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的处理器Controller。
  3. HandlerMapping将处理器Controller返回给DispatcherServlet。
  4. DispatcherServlet调用处理器Controller。
  5. Controller处理请求,调用业务逻辑处理后返回ModelAndView。
  6. DispatcherServlet调用ViewResolver,解析逻辑视图名,找到具体视图。
  7. 视图负责将模型数据渲染到视图中。
  8. DispatcherServlet将视图返回给客户端。

核心内容Controller

controller类需要包含很多信息.

  1. 处理哪类请求
  2. 返回的modelAndView

(请求匹配)注解

基本注解@RequsetMapping

携带基本的信息,匹配请求路径

需要注意的就是这个路径不需要以/开头,这一点和@webservlet不一样

强化

这个注可以写在类上,表示匹配路径的前缀,但是主要写在具体的方法上。

常用注解

包括getMapping,postMapping,putMapping,deleteMapping,PacthMapping之类的

路径语法

注解中的路径可以使用Ant风格的路径模式进行匹配,支持通配符和占位符。常见的语法包括:

  • ?:匹配一个字符。
  • *:匹配任意数量的字符(可以是0个字符)。
  • **:匹配任意数量的路径,可以是0个路径。
  • {}:占位符,可以将匹配的部分作为参数传递给处理方法。

例如,@RequestMapping("/user/{id}")中的{id}就是一个占位符,可以匹配/user/后面的任意字符,并将匹配的部分作为参数传递给处理方法。

ModelAndView怎么用

从controller中出来的ModelAndView一般只带有,数据信息也就是Model,和ViewName,并没有View对象

控制器方法返回一个ModelAndView对象时,其中包含了视图名称(viewName)以及模型数据(model)。InternalResourceViewResolver会根据视图名称解析出对应的View对象,然后使用该View对象来渲染模型数据并生成最终的响应。

所以第一步是配置这个类

配置资源解析器

1
2
3
4
<bean class="org.springframework.web.servlet.view.InternalResourceViewResovler">
<property name="prefix" value="/WEB-INF/pages/"></property>
<!-- 后缀的参数名字是 suffix -->
</bean>

配置前缀的意思是,我们在controller中返回的路径不需要写前缀了!

如果配置了后缀,比如.jsp那么我们也可以不用写后缀了!

生成modelAndView

ModelAndView对象主要携带以下信息

  1. Map (Model)传递键值对给view
  2. view名称,用来查找内部view资源
  3. View对象,用于具体的渲染返回给客户端的视图。
重要的方法

ModelAndView的方法

  • addObject(String attributeName, Object attributeValue):向模型中添加一个属性。
  • setModel():获取模型中的所有属性。
  • setViewName(String viewName):设置视图的逻辑名称。
  • setViewName():获取视图的逻辑名称。
  • setView():获取视图对象。
  • addAllObjects(Map<String, ?> modelMap):将给定的Map中的所有键值对添加到模型中。

controller就主要使用addObject设置属性

以及setViewName设置对接的视图名称

View对象的方法

  • render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response):根据模型数据渲染视图并将结果写入响应。
  • getContentType():获取视图的内容类型。
  • getAttributesMap():获取视图的属性映射。
  • getStaticAttributes():获取静态属性。
  • exposeModelAsRequestAttributes(boolean exposeModelAttributes):设置是否将模型数据暴露为请求属性。

可以推断出,DispatcherServlet就是用render方法返回给客户端的

视图控制

Spring Boot的工作

spring boot要做的事情更绝了,springboot要控制整个开发流程。

对于不同的程序,有不同的构成,所以springboot提供了不同的starter来提供不同的全流程控制的spring。

例如web开发,需要用到web服务器,web工程,以及web测试,部署之类的,spring web提供了。

所以整个程序可是说是一个spring程序了,因为程序的主体就是spring.

所以基本的理解就是

在springboot提供的程序上进行修改

所以我们要了解springboot已经形成的大体框架是什么?

默认配置是什么,然后才能正确的进行springboot的开发.

通用的东西

spring boot程序有一些通用的东西,使得程序开发所有的程序一样的风格,一样的简单.

  1. 自动配置
  2. 起步依赖
  3. 命令行界面
  4. Actuator监控

起步依赖

也叫做依赖管理,实际就是各种的spring-boot-starter

帮助我们集合了各种框架,例如要开发web程序,那么只需要导入web-starter就行了,关于版本和相关依赖都已经配置好了

命名约定

spring官方提供的的起步依赖名是: spring-boot-starter-**

第三方的提供的起步依赖名是: *-spring-starter

实际上区别就是第一个开头的

自动配置

实际上自动配置就是有一些默认的配置选项,如果spring boot扫描到了新的组件,那么就会首先按照默认配置选项进行配置,我们之后再在这个基础是修改配置

  • 扫描组件规则

默认之扫描springbootapplication主类所在包下的所有类,以及子包

  • 配置项的默认值

默认值实际上是从配置类对象中获取的.

这个类可以叫做配置属性类

有不同的配置属性类

默认值可能是从类中源码来,也可能是从springboot的初始化工作中来设置的.

  • 按需加载自动配置

我们并不确定会导入那些starter所以每个starter的都需要加上springboot-starter

而spring-boot-starter中又包含一个依赖叫做Autoconfigure,这个依赖有全场景的自动配置,我们导入哪一个依赖就会触发哪一个场景的自动配置

核心注解

Bean的配置注解

配置类标记@Configuration和@SpringBootConfiguration

配置类内部标记@Bean@Scope

快速配置@Import快速导入bean类

以及不常用的组件扫描设置@ComponentScan

条件注解

@ConditionalOnxxxx

如果存在某些条件就启用同僚注解,也就是在同位置的注解

常见的条件有这些

  • classpath中存在某个类,或者不存在某个类
  • 容器中有或者没有一个bean
  • 是否能找到一个资源

注入配置文件中的配置

可以给容器中的组件的属性中注入配置文件中的配置值

@ConfigurationProperties这个注解需要指明配置项的前缀,然后会自动注入到同名属性中

@ConfigurationProperties需要让类在容器中才能发挥作用

@EnableConfigurationProperties这个用来远程添加一个类进入容器,所以结合就可以远程启用属性配置注解

主要用于启动第三方,本地的spring容器扫描不到的包的configurationProperties

SpringBoot 的Web开发

和之前说的一样,我们要先了解spring boot已经做到了哪些东西。

了解Spring Boot Web做了什么

  1. 全权交互web服务器

sbw提供了web服务器的适配器,通过sbw的配置文件来对web服务器进行配置


再学习spring&spring-mvc&springboot
https://wainyz.online/wainyz/2024/04/25/再学习spring&spring-mvc&springboot/
作者
wainyz
发布于
2024年4月25日
许可协议