02-Spring篇

Spring

简介

Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。

Spring 框架是一个开源的 Java 平台,它最初是由 Rod Johnson 编写的,并且于 2003 年 6 月首次在 Apache 2.0 许可下发布。

Spring 框架的核心特性是可以用于开发任何 Java 应用程序,但是在 Java EE 平台上构建 web 应用程序是需要扩展的。 Spring 框架的目标是使 J2EE 开发变得更容易使用,通过启用基于 POJO 编程模型来促进良好的编程实践。

SSH:Struct2 + Spring + Hibernate

SSM:SpringMVC + Spring + Mybatis

相关资料

官网:https://spring.io/projects/spring-framework#overview

中文文档:https://m.w3cschool.cn/wkspring/pesy1icl.html

狂神Spring视频:https://www.bilibili.com/video/BV1WE411d7Dv

<dependencies>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <!--            <version>5.2.16.RELEASE</version>-->
        <!--            <version>5.1.10.RELEASE</version>-->
        <version>5.3.9</version>
    </dependency>
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.9</version>
    </dependency>
</dependencies>

优点

  • Spring是一个开源的免费的框架(容器)

  • Spring是一个轻量级的、非入侵式的框架

  • 控制反转、面向切面编程(AOP)

  • 支持事务的处理

组成

img

核心容器(Spring Core)

  核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。

应用上下文(Spring Context)

  Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。

Spring面向切面编程(Spring AOP)

  通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

JDBC和DAO模块(Spring DAO)

  JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。

对象实体映射(Spring ORM)

  Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。

Web模块(Spring Web)

  Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

MVC模块(Spring Web MVC)

  MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。

拓展

image-20210918173823119

在Spring的官网有这个介绍:现代化的java开发,说白就是基于Spring的开发。

  • Spring Boot:

    • 一个快速开发的脚手架

    • 基于SpringBoot可以快速的开发单个微服务

    • 约定大于配置

  • Spring Cloud

    • Spring Cloud是基于Spring Boot实现的

因为现在大多数公司都在使用SpringBoot进行快速开发,学习SpringBoot的前提,需要完全掌握Spring以及SpringMVC。

由于发展了太久,违背了原来的理念,配置十分的繁琐。

IOC理论推导

  • UserDao接口

  • UserDaoImpl实现类

  • UserService业务接口

  • UserServiceImpl业务实现类

在之前的业务中,用户的需求可能会影响原来的代码,需要根据用户的需求去修改源代码。如果代码量很大,会导致修改的成本代价过大。

通过setUserDao接口实现,从而解决这个问题:

​ 采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是loC容器,其实现方法是依赖注入(Dependency Injection,Dl)。

第一个实例:Hello Spring

  • 创建java实体类

com.easy.pojo.Hello.java

  • 配置元数据

resources/beans.xml

(1) id属性是标识单个 bean 定义的字符串。

(2) class属性定义 bean 的类型并使用完全限定的类名。

(2) property为对象设置一个值。

id属性的值是指协作对象。在此示例中未显示用于引用协作对象的 XML。

  • 实例化容器

提供给ApplicationContext构造函数的位置路径是资源字符串,这些资源字符串使容器可以从各种外部资源(例如本地文件系统,Java CLASSPATH等)加载配置元数据。

test.java.MyTest.java

  • Hello对象是谁创建的?Hello对象的属性是谁设置的?

    • hello对象是由Spring创建的,hello对象的属性是由Spring设置的。这个过程就叫控制反转:

    • 控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring之后,对象是由Spring来创建的。

    • 反转:程序本身不创建对象,而变成被动的接收对象。

    • 依赖注入:就是利用set方法来进行注入的!

    • IOC是一种编程思想,由主动的编程变成被动的接受。

spring-01-ioc1进行改写:

测试类

IOC对象创建方式

  1. 使用无参构造对象,默认

  2. 使用有参构造对象:

  • 通过下标创建

  • 通过类型创建

  • 通过参数名创建

总结:在配置文件加载的时候,容器中管理的对象就已经初始化了!

Spring配置

别名

如果添加了别名,也可以使用别名获取到这个对象。

Bean的配置

  • id:bean的唯一标识符,也就是相当于学过的对象名

  • class:bean对象所对应的全限定名(包名+类型)

  • name:也是别名,而且可以同时取多个别名

import

import一般用于团队开发使用,可以将多个配置文件,导入合并为一个。

假设,现在项目中有多个人开发,这三个人复制不同的类开发,不同的类需要注册在不同的bean中,我们可以利用import将所有人的beans.xml合并为一个总的!

applicationContext.xml

依赖注入

构造器注入

前面已经叙说过了。。

set方式注入

概念

  • 依赖注入:set注入

    • 依赖:bean对象的创建依赖于容器

    • 注入:bean对象中的所有属性,由容器来注入!

【环境搭建】

  • 创建spring-04-di工程

  • 创建com.easy.pojo.Student实体类

  • 创建com.easy.pojo.Address实体类

  • 创建beans.xml

  • 测试

注入方式

常量注入

Bean注入

数组注入

List注入

Map注入

set注入

Null注入

Properties注入

有类似与Map

标签注入

  • 创建User.java

  • 创建resourcse/userBeans.xml

p命名空间注入/设置属性

  • 需要在头文件中加入约束文件

  • 设置属性

p命名空间注入可以进行设置属性,代替properties

  • 测试

如果不想强转类型,可以这样写User user = context.getBean("user",User.class);

c命名空间注入/设置有参构造器

  • 需要在头文件中加入约束文件

  • 设置有参构造器

如果类中没有有参构造器,会报错。

Bean的作用域

Scope
Description

(Default) Scopes a single bean definition to a single object instance for each Spring IoC container.

Scopes a single bean definition to any number of object instances.

Scopes a single bean definition to the lifecycle of a single HTTP request. That is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring ApplicationContext.

Scopes a single bean definition to the lifecycle of an HTTP Session. Only valid in the context of a web-aware Spring ApplicationContext.

Scopes a single bean definition to the lifecycle of a ServletContext. Only valid in the context of a web-aware Spring ApplicationContext.

Scopes a single bean definition to the lifecycle of a WebSocket. Only valid in the context of a web-aware Spring ApplicationContext.

  • 单例模式(Spring默认机制)

  • 原型模式:每次从容器中get的时候,都会产生一个新对象!

  • 其余的request(请求)、session(会话)、application(全局),这些只能在web开发中使用。

Bean的自动装配

概念

  • 自动装配是Spring满足bean依赖一种方式

  • Spring会在上下文中自动寻找,并自动给bean装配属性

在Spring中有三种装配方式:

  1. 在xml中显示的配置

  2. 在java中显示配置

  3. 隐式的自动装配bean【重要】

配置

  • 创建spring-05-Autowired工程目录

  • 创建com.easy.pojo

    • 创建Cat

    • 创建Dog类

    • 创建People

  • 创建resources/beans.xml

  • 测试

自动装配

autowire byName (按名称自动装配)

由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。

采用自动装配将避免这些错误,并且使配置简单化。

  • 修改bean配置,增加一个属性 autowire="byName"

该方法会自动在容器上下文中查找,和自己对象set方法后面的值对应的bean.id

autowire byType (按类型自动装配)

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。

  • 修改bean配置,增加一个属性 autowire="byType"

  1. byname的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法值一致。

  2. bytype的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致。

使用注解实现自动装配

jdk1.5开始支持注解,spring2.5开始全面支持注解。

要使用注解须知:

  • 导入约束

  • 配置注解的支持

==<context:annotation-config />==必须有

@Autowired

  • @Autowired是按类型自动转配的,不支持id匹配。

  • 需要导入 spring-aop的包!

  1. 将User类中的set方法去掉,使用@Autowired注解

  1. 配置Beans.xml文件

@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。

@Nullable 注解可以使字段为null

由于Autowired默认是按类型注入,让出现多个bean引用同一个实体类时,会报错,才需要用**@Qualifier**按照指定id名进行注入

@Inject代替@Autowired。完成自动装配

@Qualifier

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配

  • @Qualifier不能单独使用。

  1. 配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!

  1. 没有加Qualifier测试,直接报错

  2. 在属性上添加Qualifier注解

@Resource

  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;

  • 其次再进行默认的byName方式进行装配;

  • 如果以上都不成功,则按byType的方式自动装配。

  • 都不成功,则报异常。

结论:先进行byName查找,失败;再进行byType查找,成功。

@Autowired与@Resource的区别

@Autowired与@Resource异同:

  1. @Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。

  2. @Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用

  3. @Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。

它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。

使用注解开发

流程

在Spring4之后,要使用注解开发,必须要保证aop的包导入

image-20211204202812789

在配置文件中,引入context约束

我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!

Bean的实现

  • 配置扫描那些包下的注解

  • 在指定包下编写类,增加注解

若想更改注册名称,如下操作:

  • 测试

属性注入

使用注解注入属性

  • 可以不用提供set方法,直接在直接名上添加**@value("值")**

  • 如果提供了set方法,在set方法上添加**@value("值");**

衍生的注解

@Component有几个衍生注解。为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

  • dao:@Repository

  • service:@Service

  • controller:@Controller

这四个注解功能都是一样的,都是代表将某个类注册到Spring中,装配Bean。

自动装配

如上

作用域

@scope

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收

小结

xml与注解:

  • xml更加万能,适用于任何场合,维护简单方便。

  • 注解 不是自己类使用不了,维护相对复杂

xml与注解最佳实践:

  • xml用来管理bean

  • 注解只负责属性注入

  • 在使用过程中,只需要注意一个问题:必须让注解生效,就需要开启注解的支持!

使用java的方式配置Spring

现在要完全不使用Spring的xml配置了,全权交给java来做!

JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能!

image-20211206180154935
  • 创建spring-07-appconfig工程目录

  • 创建实体类com.easy.pojo.User.java

  • 创建配置文件com.easy.config.AppConfig.java

注册一个bean,就相当于之前写的一个bean标签。

  1. 这个方法的名字,就相当丁bean标签中的id属性

  2. 这个方法的返回值,就相当于 bean标签中的class属性

  • 测试

注意context.getBean("getUser",User.class)中填写的是方法名称。

如果完全使用了配置类方式去做,我们就只能通过 AnnotationConfig 上下文来获取容器,通过配置类的class对象加载!

  • 如何写多个beans,和之前的多个beans.xml一样

  1. 创建appConfig2.java

  1. 通过使用Import进行导入

纯Java的配置方式,在Springboot随处可见。

代理模式

为什么要学习代理模式?因为这就是SpringAOP的底层!【SpringAOP和SpringMVC】

代理模式的分类:

  • 静态代理

  • 动态代理

image-20211206184616714

静态代理

角色分析:

  • 抽象角色:一般会使用接口或者抽象类来解决

  • 真实角色:被代理的角色

  • 代理角色:代理真实角色,代理真实角色后,一般会做一些附属操作。

  • 客户:访问代理对象的人。

Rent. java 即抽象角色

Host.java 即真实角色

Proxy.java 即代理角色

Client.java 即客户

分析:在这个过程中,你直接接触的就是中介,就如同现实生活中的样子,你看不到房东,但是你依旧租到了房东的房子通过代理,这就是所谓的代理模式,程序源自于生活,所以学编程的人,一般能够更加抽象的看待生活中发生的事情。

静态代理的好处:

  • 可以使得我们的真实角色更加纯粹 ,不再去关注一些公共的事情

  • 公共的业务由代理来完成 ,实现了业务的分工

  • 公共业务发生扩展时,变得更加集中和方便

缺点 :

  • 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .

我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !

静态代理再理解

1、创建一个抽象角色,比如咋们平时做的用户业务,抽象起来就是增删改查!

2、我们需要一个真实对象来完成这些增删改查操作

3、需求来了,现在我们需要增加一个日志功能,怎么实现!

  • 思路1 :在实现类上增加代码 【麻烦!】

  • 思路2:使用代理来做,能够不改变原来的业务情况下,实现此功能就是最好的了!

4、设置一个代理类来处理日志!代理角色

5、测试访问类:

OK,到了现在代理模式大家应该都没有什么问题了,重点大家需要理解其中的思想;

我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想

聊聊AOP:纵向开发,横向开发

image-20211207152807838

动态代理

  • 动态代理和静态代理角色一样

  • 动态代理的代理类是动态生成的,不是直接写好的!

  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理

    • 基于接口———JDK动态代理

    • 基于类:cglib

    • java字节码实现:JAVAssist

关于java字节码的处理,有很多工具,如bcel,asm。不过这些都需要直接跟虚拟机指令打交道。如果你不想了解虚拟机指令,可以采用javassist。javassistjboss的一个子项目,其主要的优点,在于简单,而且快速。直接使用java编码的形式,而不需要了解虚拟机指令,就能动态改变类的结构,或者动态生成类。

需要了解两个类:Proxy,InvocationHandler

  • InvocationHandler是通过一个代理实例零调用处理程序实现的接口。

  • Proxy提供了创建动态代理类和实例的静态方法,也是由这些方法创建的所有动态代理类的超类。

改写上面的静态代理实例2

  • UserService.javaUserServiceImpl.java不变

  • UserServiceProxy.java改为ProxyInvocationHandler.java

  • 测试类

动态代理的好处:

  • 可以使得我们的真实角色更加纯粹 ,不再去关注一些公共的事情

  • 公共的业务由代理来完成 ,实现了业务的分工

  • 公共业务发生扩展时,变得更加集中和方便

  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务

  • 一个动态代理类可以代理多个类,只要是实现了同一个接口即可

AOP

什么是AOP

AOP(Aspect Oriented Programming)意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

image-20211207152826378

AOP在Spring中的作用

提供声明式事务;允许用户自定义切面

以下名词需要了解下:

  • 横切关注点:跨越应用程序多个模块的方法或功能。即是,与我们业务逻辑无关的,但是我们需要关注的部分,就是横切关注点。如日志 , 安全 , 缓存 , 事务等等 ....

  • 切面(ASPECT):横切关注点 被模块化 的特殊对象。即,它是一个类。

  • 通知(Advice):切面必须要完成的工作。即,它是类中的一个方法。

  • 目标(Target):被通知对象。

  • 代理(Proxy):向目标对象应用通知之后创建的对象。

  • 切入点(PointCut):切面通知 执行的 “地点”的定义。

  • 连接点(JointPoint):与切入点匹配的执行点。

image-20211207152733144

SpringAOP中,通过Advice定义横切逻辑,Spring中支持5种类型的Advice:

image-20211207152855234

即 Aop 在 不改变原有代码的情况下 , 去增加新的功能 。

使用Spring实现AOP

【重点】使用AOP织入,需要导入一个依赖包!

第一种方式:通过Spring API实现

  • 编写业务接口和实现类

  1. UserService.java

  1. UserServiceImpl.java

  • 然后写增强类 , 编写两个 , 一个前置增强 一个后置增强

  1. BeforeLog.java

  1. AfterLog.java

  • 最后去spring的文件中注册 , 并实现aop切入实现 , 注意导入约束 .

  • 测试

Aop的重要性 : 很重要 !!!一定要理解其中的思路,主要是思想的理解这一块 。

Spring的Aop就是将公共的业务 (日志 , 安全等) 和领域业务结合起来,当执行领域业务时,将会把公共业务加进来 ,实现公共业务的重复利用。领域业务更纯粹,程序猿专注领域业务,其本质还是动态代理。

第二种方式:通过自定义类来实现AOP

目标业务类不变依旧是userServiceImpl

第一步: 写我们自己的一个切入类

第二步:去spring中配置

第三种方式:使用注解方式来实现AOP

  • 第一步:编写一个注解实现的增强类

  • 第二步:在Spring配置文件中,注册bean,并增加支持注解的配置

其中,注册bean可以通过@Component实现。

  • 测试

image-20211207211302979

<aop:aspectj-autoproxy />

通过aop命名空间的<aop:aspectj-autoproxy />声明自动为spring容器中那些配置@aspect切面的bean创建代理,织入切面。

当然,spring 在内部依旧采用AnnotationAwareAspectJAutoProxyCreator进行自动代理的创建工作,但具体实现的细节已经被<aop:aspectj-autoproxy />隐藏起来了。

<aop:aspectj-autoproxy />有一个proxy-target-class属性,默认为false,表示使用jdk动态代理织入增强,当配为<aop:aspectj-autoproxy poxy-target-class="true"/>时,表示使用CGLib动态代理技术织入增强。不过即使proxy-target-class设置为false,如果目标类没有声明接口,则spring将自动使用CGLib动态代理。

整合Mybatis

回顾Mybatis

导入相关的包

  • 导入相关jar包

  • mybatis

  • mysql数据库

  • spring相关的

  • aop织入

  • mybatis-spring

编写配置文件

  • 防止资源导出失败

  • 编写实体类

  • 编写核心配置文件

  • 编写接口

  • 编写Mapper.xml

  • 测试

接下来整合mybatis:步骤:

  • 编写数据源配置

  • sqlSessionFactory

  • sqlSessionTemplate

  • 需要给接口增加实现类

  • 将自己写的实现类,注入到Spring中

  • 测试使用即可!!!

整合Mybatis方式一

  • 引入Spring配置文件beans.xml

  • 配置数据源替换mybaits的数据源

  • 配置SqlSessionFactory,关联MyBatis

  • 注册sqlSessionTemplate,关联sqlSessionFactory;

  • 增加Mapper接口的实现类;私有化sqlSessionTemplate

  • 注册bean实现

  • 测试

整合Mybatis方式二

  • 增加Mapper接口的实现类;私有化sqlSessionTemplate2

  • 注册bean

声明式事务

回顾事务

事务的四大特性主要是:

原子性(Atomicity):事务包含的所有操作要么全部成功,要么全部失败回滚。

一致性(Consistency):一个事务执行之前和执行之后都必须处于一致性状态。

隔离性(Isolation):多个业务可能操作同一个资源,防止数据损坏。

持久性(Durability):事务一旦提交,无论系统发生什么问题,结果都不会再被影响,被持久化的写到存储器中!

spring中的事务管理

  • 声明式事务:AOP

  • 编程式事务:需要在代码中,进行事务的管理

  1. 使用Spring管理事务,注意头文件的约束导入 : tx

  1. JDBC事务

  1. 配置好事务管理器后我们需要去配置事务的通知

  1. spring事务传播特性

Spring中七种Propagation类的事务属性

image-20211208221451774
  1. 配置aop

  1. 测试

为什么需要配置事务?

  • 如果不配置,就需要我们手动提交控制事务;

  • 事务在项目开发过程非常重要,涉及到数据的一致性的问题,不容马虎!

最后更新于

这有帮助吗?