spring5

Posted 基本功修炼

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了spring5相关的知识,希望对你有一定的参考价值。

spring是什么

Spring是分层的Java SE/EE应用full-stack轻量级开源框架,以IoC(Inverse Of Control:反转控制)和AOP(Aspect Oriented Programming:面向切面编程)为内核,提供了展现层Spring MVC和持久层Spring JDBC以及业务层事务管理等众多的企业级应用技术,还能整合开源世界众多著名的第三方框架和类库,逐渐成为使用最多的Java EE企业应用开源框架。


Spring的发展历程

1997年IBM提出了EJB的思想

1998年,SUN制定开发标准规范EJB1.0

1999年,EJB1.1发布

2001年,EJB2.0发布

2003年,EJB2.1发布

2006年,EJB3.0发布

Rod Johnson(spring之父) Expert One-to-One J2EE Design and Development(2002)阐述了J2EE使用EJB开发设计的优点及解决方案Expert One-to-One J2EE Development without EJB(2004)阐述了J2EE开发不使用EJB的解决方式(Spring雏形) 

2017年9月份发布了spring的最新版本spring 5.0通用版(GA) 


spring的优势方便解耦,简化开发通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。AOP编程的支持通过Spring的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以


spring的优势

方便解耦,简化开发通过Spring提供的IoC容器,可以将对象间的依赖关系交由Spring进行控制,避免硬编码所造成的过度程序耦合。用户也不必再为单例模式类、属性文件解析等这些很底层的需求编写代码,可以更专注于上层的应用。


AOP编程的支持通过Spring的AOP功能,方便进行面向切面的编程,许多不容易用传统OOP实现的功能可以通过AOP轻松应付。


声明式事务的支持

可以将我们从单调烦闷的事务管理代码中解脱出来,通过声明式方式灵活的进行事务的管理,提高开发效率和质量。


方便程序的测试

可以用非容器依赖的编程方式进行几乎所有的测试工作,测试不再是昂贵的操作,而是随手可做的事情。


方便集成各种优秀框架

Spring可以降低各种框架的使用难度,提供了对各种优秀框架(Struts、Hibernate、Hessian、Quartz等)的直接支持。


降低JavaEE API的使用难度

Spring对JavaEE API(如JDBC、JavaMail、远程调用等)进行了薄薄的封装层,使这些API的使用难度大为降低。


Java源码是经典学习范例

Spring的源代码设计精妙、结构清晰、匠心独用,处处体现着大师对Java设计模式灵活运用以及对Java技术的高深造诣。它的源代码无意是Java技术的最佳实践的范例。


spring的体系结构

spring5


 IoC的概念和作用

什么是程序的耦合耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。

spring5

spring5

spring5

spring5

解决程序耦合的思路当是我们讲解jdbc时,是通过反射来注册驱动的,代码如下:

Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串

此时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除mysql的驱动jar包,依然可以编译(运行就不要想了,没有驱动不可能运行成功的)。

同时,也产生了一个新的问题,mysql驱动的全限定类名字符串是在java类中写死的,一旦要改还是要修改源码。解决这个问题也很简单,使用配置文件配置。


工厂模式解耦

在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件,创建和获取三层对象的类就是工厂。


控制反转-Inversion Of Control

spring5

spring5

这种被动接收的方式获取对象的思想就是控制反转,它是spring框架的核心之一

spring5

明确ioc的作用:削减计算机程序的耦合(解除我们代码中的依赖关系)。


使用spring的IOC解决程序耦合 

本次的案例是,账户的业务层和持久层的依赖关系解决。在开始spring的配置之前,我们要先准备一下环境。由于我们是使用spring解决依赖关系,并不是真正的要做增删改查操作,所以此时我们没必要写实体类。并且我们在此处使用的是java工程,不是java web工程。


准备spring的开发包

官网:http://spring.io/

http://repo.springsource.org/libs-release-local/org/springframework/spring

解压:(Spring目录结构:)

* docs:API和开发规范.

* libs:jar包和源码. 

* schema:约束.


创建业务层接口和实现类

spring5

创建持久层接口和实现类

spring5

基于XML的配置(入门案例

第一步:拷贝必备的jar包到工程的lib目录中

spring5

第二步:在类的根路径下创建一个任意名称的xml文件(不能是中文)

spring5

给配置文件导入约束:

/spring-framework-5.0.2.RELEASE/docs/spring-framework-reference/html5/core.html

spring5

第三步:让spring管理资源,在配置文件中配置service和dao

spring5

测试配置是否成功

spring5

spring5

Spring基于XML的IOC细节

spring中工厂的类结构图

spring5

spring5

BeanFactory和ApplicationContext的区别

spring5

ApplicationContext接口的实现类

spring5

IOC中bean标签和管理对象细节

bean标签

spring5

bean的作用范围和生命周期

spring5

实例化Bean的三种方式 

第一种方式:

使用默认无参构造函数

<!--在默认情况下:

      它会根据默认无参构造函数来创建类对象。如果bean中没有默认无参构造函数,将会创建失败。

--><beanid="accountService"class="com.itheima.service.impl.AccountServiceImpl"/>

spring5

spring5

spring的依赖注入

依赖注入的概念

依赖注入:Dependency Injection。它是spring框架核心ioc的具体实现。我们的程序在编写时,通过控制反转,把对象的创建交给了spring,但是代码中不可能出现没有依赖的情况。ioc解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系,在使用spring之后,就让spring来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。


构造函数注入

spring5

spring5

set方法注入

spring5

spring5

使用p名称空间注入数据(本质还是调用set方法)

spring5

配置文件代码

spring5

spring5

注入集合属性

spring5

spring5

spring5

Spring配置文件中提示的配置

spring5


案例:使用spring的IoC的实现账户的CRUD

需求和技术要求

需求

实现账户的CRUD操作

技术要求

使用spring的IoC实现对象的管理

使用DBAssit作为持久层解方案决

使用c3p0数据源


环境搭建

拷贝jar包

spring5

创建数据库和编写实体类

spring5

编写持久层代码

spring5

spring5

编写业务层代码

spring5

spring5

创建并编写配置文件

spring5

配置步骤

配置对象

spring5

spring5


测试案例

测试类代码

spring5

spring5

分析测试了中的问题

通过上面的测试类,我们可以看出,每个测试方法都重新获取了一次spring的核心容器,造成了不必要的重复代码,增加了我们开发的工作量。这种情况,在开发中应该避免发生。

可能会想到把容器的获取定义到类中去。例如:

spring5


基于注解的IOC配置

明确:写在最前

关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌

握。


学习基于注解的IoC配置,大家脑海里首先得有一个认知,即注解配置和xml配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。我们在讲解注解配置时,采用上一章节的案例,把spring的xml配置内容改为使用注解逐步实现。


环境搭建

注意:在基于注解的配置中,我们还要多拷贝一个aop的jar包。如下图

spring5

第一步:拷贝必备jar包到工程的lib目录。

第二步:使用@Component注解配置管理的资源

spring5

注意:当我们使用注解注入时,set方法不用写

第三步:创建spring的xml配置文件并开启对注解的支持

spring5


注意:由于我们使用了注解配置,此时不能在继承JdbcDaoSupport,需要自己配置一个JdbcTemplate基于注解整合时,导入约束时需要多导入一个context名称空间下的约束。

spring5

常用注解

相当于:<beanid=""class="">用于创建对象的


@Component

作用:把资源让spring来管理。相当于在xml中配置一个bean。

属性:value:指定bean的id。如果不指定value属性,默认bean的id是当前类的类名。首字母小写。

@Controller@Service@Repository

他们三个注解都是针对一个的衍生注解,他们的作用及属性都是一模一样的。他们只不过是提供了更加明确的语义化。


@Controller:一般用于表现层的注解。

@Service:一般用于业务层的注解。

@Repository:一般用于持久层的注解。


用于注入数据的

细节:如果注解中有且只有一个属性要赋值时,且名称是value,value在赋值是可以不写。

相当于:

<propertyname=""ref="">

<propertyname="" value="">


@Autowired

作用:自动按照类型注入。当使用注解注入属性时,set方法可以省略。它只能注入其他bean类型。当有多个类型匹配时,使用要注入的对象变量名称作为bean的id,在spring容器查找,找到了也可以注入成功。找不到就报错。


@Qualifier

作用:在自动按照类型注入的基础之上,再按照Bean的id注入。它在给字段注入时不能独立使用,必须和@Autowire一起使用;但是给方法参数注入时,可以独立使用。

属性:value:指定bean的id。


@Value

作用:注入基本数据类型和String类型数据的
属性:value:用于指定值


用于改变作用范围的:相当于:<beanid=""class=""scope="">

@Scope

作用:指定bean的作用范围。

属性:value:指定范围的值。

取值:singletonprototyperequest session globalsession

 

和生命周期相关的

相当于:<bean id="" class=""init-method=""destroy-method=""/>


@PostConstruct

作用:用于指定初始化方法。


@PreDestroy

作用:用于指定销毁方法


关于Spring注解和XML的选择问题

注解的优势:配置简单,维护方便(我们找到类,就相当于找到了对应的配置)。

XML的优势:修改时,不用改源码。不涉及重新编译和部署。

Spring管理Bean方式的比较:

spring5

spring管理对象细节

基于注解的spring IoC配置中,bean对象的特点和基于XML配置是一模一样的。


spring的纯注解配置

写到此处,基于注解的IoC配置已经完成,但是大家都发现了一个问题:我们依然离不开spring的xml配置文件,那么能不能不写这个bean.xml,所有配置都用注解来实现呢?当然,同学们也需要注意一下,我们选择哪种配置的原则是简化开发和配置方便,而非追求某种技术。


待改造的问题

我们发现,之所以我们现在离不开xml配置文件,是因为我们有一句很关键的配置:

spring5

新注解说明

@Configuration

作用:用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)。

属性:value:用于指定配置类的字节码


spring5

@ComponentScan

作用:用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:<context:component-scanbase-package="com.itheima"/>是一样的。

属性:basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。

spring5

@Bean

作用:该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。

属性:name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。

示例代码:

spring5

@PropertySource

作用:用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。

属性:value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:

spring5

spring5

@Import

作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。

属性:value[]:用于指定其他配置类的字节码。

spring5

通过注解获取容器

spring5

工程结构图

spring5

Spring整合Junit

测试类中的问题和解决思路

问题

spring5

解决思路

分析针对上述问题,我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建spring容器,我们就无须手动创建了,问题也就解决了。我们都知道,junit单元测试的原理(在web阶段课程中讲过),但显然,junit是无法实现的,因为它自己都无法知晓我们是否使用了spring框架,更不用说帮我们创建spring容器了。不过好在,junit给我们暴露了一个注解,可以让我们替换掉它的运行器。这时,我们需要依靠spring框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。我们只需要告诉它配置文件在哪就行了。


配置步骤

第一步:拷贝整合junit的必备jar包到lib目录

此处需要注意的是,导入jar包时,需要导入一个spring中aop的jar包。

spring5

第二步:使用@RunWith注解替换原有运行器

spring5

第三步:使用@ContextConfiguration指定spring配置文件的位置

spring5

spring5

第四步:使用@Autowired给测试类中的变量注入数据

spring5

为什么不把测试类配到xml中

在解释这个问题之前,先解除大家的疑虑,配到XML中能不能用呢?答案是肯定的,没问题,可以使用。那么为什么不采用配置到xml中的方式呢?这个原因是这样的:第一:当我们在xml中配置了一个bean,spring加载配置文件创建容器时,就会创建对象。第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。所以,基于以上两点,我们不应该把测试配置到xml文件中。


AOP的相关概念

AOP概述

什么是AOP

AOP:全称是Aspect Oriented Programming即:面向切面编程。

spring5

简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。


AOP的作用及优势

作用:在程序运行期间,不修改源码对已有方法进行增强。

优势:减少重复代码提高开发效率维护方便


AOP的实现方式

使用动态代理技术


AOP的具体应用

案例中问题

下面是客户的业务层实现类


客户的业务层实现类

spring5

问题就是:事务被自动控制了。换言之,我们使用了connection对象的setAutoCommit(true)此方式控制事务,如果我们每次都执行一条sql语句,没有问题,但是如果业务方法一次要执行多条sql语句,这种方式就无法实现功能了。

spring5

问题的解决

解决办法:让业务层来控制事务的提交和回滚。

spring5

spring5

spring5

spring5

spring5

新的问题

通过对业务层改造,已经可以实现事务控制了,但是由于我们添加了事务控制,也产生了一个新的问题:业务层方法变得臃肿了,里面充斥着很多重复代码。并且业务层方法和事务控制方法耦合了。试想一下,如果我们此时提交,回滚,释放资源中任何一个方法名变更,都需要修改业务层的代码,况且这还只是一个业务层实现类,而实际的项目中这种业务层实现类可能有十几个甚至几十个。

思考:这个问题能不能解决呢?

答案是肯定的,使用下一小节中提到的技术。


动态代理回顾

动态代理的特点

字节码随用随创建,随用随加载。它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。装饰者模式就是静态代理的一种体现。


动态代理常用的有两种方式

基于接口的动态代理

提供者:JDK官方的Proxy类。

要求:被代理类最少实现一个接口

基于子类的动态代理

提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar。

要求:被代理类不能用final修饰的类(最终类)。


使用JDK官方的Proxy类创建代理对象

此处我们使用的是一个演员的例子:在很久以前,演员和剧组都是直接见面联系的。没有中间人环节。而随着时间的推移,产生了一个新兴职业:经纪人(中间人),这个时候剧组再想找演员就需要通过经纪人来找了。下面我们就用代码演示出来。


spring5

spring5

spring5

使用CGLib的Enhancer类创建代理对象

spring5

spring5

spring5

解决案例中的问题

spring5

spring5


 Spring中的AOP

AOP相关术语

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。

Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。

spring5

学习spring中的AOP要明确的事

a、开发阶段(我们做的)编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP编程人员来做。在配置文件中,声明切入点与通知间的关系,即切面。:AOP编程人员来做。

b、运行阶段(Spring框架完成的)Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。


关于代理的选择在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。


基于XML的AOP配置

示例:我们在学习spring的aop时,采用账户转账作为示例。并且把spring的ioc也一起应用进来。


环境搭建

第一步:准备必要的代码此处包含了实体类,业务层和持久层代码。我们沿用上一章节中的代码即可

第二步:拷贝必备的jar包到工程的lib目录

spring5

第三步:创建spring的配置文件并导入约束

spring5

第四步:配置spring的ioc

spring5

spring5

第五步:抽取公共代码制作成通知

spring5

spring5

配置步骤

第一步:把通知类用bean标签配置起来

spring5

第二步:使用aop:config声明aop配置

spring5

spring5

第三步:使用aop:aspect配置切面

spring5

第四步:使用aop:pointcut配置切入点表达式

spring5

第五步:使用aop:xxx配置对应的通知类型

spring5

spring5

切入点表达式说明

spring5

spring5

环绕通知

spring5

spring5

基于注解的AOP配置

环境搭建

第一步:准备必要的代码和jar包

第二步:在配置文件中导入context的名称空间

spring5

第三步:把资源使用注解配置

spring5

spring5

第四步:在配置文件中指定spring要扫描的包

spring5


配置步骤

第一步:把通知类也使用注解配置

spring5

第二步:在通知类上使用@Aspect注解声明为切面

作用:把当前类声明为切面类。

spring5

第三步:在增强的方法上使用注解配置通知

spring5

spring5

第四步:在spring配置文件中开启spring对注解AOP的支持

spring5

环绕通知注解配置

spring5

切入点表达式注解

spring5

spring5

不使用XML的配置方式

spring5

 Spring中的JdbcTemplate

JdbcTemplate概述

spring5

JdbcTemplate对象的创建

spring5

spring中配置数据源

环境搭建

spring5

编写spring的配置文件

spring5

配置数据源

我们之前已经接触过了两个数据源,C3P0和DBCP。要想使用这两数据源都需要导入对应的jar包。

配置C3P0数据源

spring5

spring5

配置DBCP数据源

spring5

配置spring内置数据源

spring5

将数据库连接的信息配置到属性文件中:

spring5

spring5

JdbcTemplate的增删改查操作

前期准备

spring5

在spring配置文件中配置JdbcTemplate

spring5

最基本使用

spring5

保存操作

spring5

更新操作

spring5

删除操作

spring5

查询所有操作

spring5

}

查询一个操作

spring5

查询返回一行一列操作

spring5

spring5

在dao中使用JdbcTemplate

准备实体类

spring5

spring5

第一种方式:在dao中定义JdbcTemplate

spring5

spring5

spring5

第二种方式:让dao继承JdbcDaoSupport

spring5

spring5

spring5

spring5

spring5

Spring中的事务控制

Spring事务控制我们要明确的

第一:JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案。

第二:spring框架为我们提供了一组事务控制的接口。具体在后面的第二小节介绍。这组接口是在spring-tx-5.0.2.RELEASE.jar中。

第三:spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。


Spring中事务控制的API介绍

PlatformTransactionManager

spring5

spring5

TransactionDefinition

spring5

事务的隔离级别

spring5

事务的传播行为

spring5

超时时间

默认值是-1,没有超时限制。如果有,以秒为单位进行设置。


是否是只读事务

建议查询时设置为只读


TransactionStatus

spring5

   基于XML的声明式事务控制(配置方式)重点

环境搭建

第一步:拷贝必要的jar包到工程的lib目录

spring5

第二步:创建spring的配置文件并导入约束

spring5

第三步:准备数据库表和实体类

spring5

spring5

第四步:编写业务层接口和实现类

spring5

spring5

第五步:编写Dao接口和实现类

spring5

    

spring5

spring5

第六步:在配置文件中配置业务层和持久层对

spring5

配置步骤

第一步:配置事务管理器

spring5

spring5

第二步:配置事务的通知引用事务管理器

spring5

第三步:配置事务的属性

spring5

第四步:配置AOP切入点表达式

spring5

第五步:配置切入点表达式和事务通知的对应关系

spring5


基于注解的配置方式

环境搭建

第一步:拷贝必备的jar包到工程的lib目录

spring5

第二步:创建spring的配置文件导入约束并配置扫描的包

spring5

spring5

第三步:创建数据库表和实体类

和基于xml的配置相同。略

第四步:创建业务层接口和实现类并使用注解让spring管理

spring5

第五步:创建Dao接口和实现类并使用注解让spring管理

spring5

spring5

配置步骤

第一步:配置事务管理器并注入数据源

spring5

第二步:在业务层使用@Transactional注解

spring5

spring5

第三步:在配置文件中开启spring对注解事务的支持

spring5

不使用xml的配置方式

spring5


 Spring5的新特性

与JDK相关的升级

jdk版本要求:

spring5


利用jdk8版本更新的内容

第一:基于JDK8的反射增强请看下面的代码:

spring5

spring5

核心容器的更新

Spring Framework 5.0 现在支持候选组件索引作为类路径扫描的替代方案。该功能已经在类路径扫描器中添加,以简化添加候选组件标识的步骤。

应用程序构建任务可以定义当前项目自己的META-INF/spring.components 文件。在编译时,源模型是自包含的,JPA 实体和Spring 组件是已被标记的。

从索引读取实体而不是扫描类路径对于小于200 个类的小型项目是没有明显差异。但对大型项目影响较大。

加载组件索引开销更低。因此,随着类数的增加,索引读取的启动时间将保持不变。加载组件索引的耗费是廉价的。因此当类的数量不断增长,加上构建索引的启动时间仍然可以维持一个常数, 不过对于组件扫描而言,启动时间则会有明显的增长。这个对于我们处于大型Spring 项目的开发者所意味着的,是应用程序的启动时间将被大大缩减。虽然20 或者30 秒钟看似没什么,但如果每天要这样登上好几百次,加起来就够你受的了。使用了组件索引的话,就能帮助你每天过的更加高效。你可以在Spring 的Jira上了解更多关于组件索引的相关信息。


JetBrains Kotlin语言支持

spring5

响应式编程风格

spring5

Junit5支持

spring5

依赖类库的更新

终止支持的类库

以上是关于spring5的主要内容,如果未能解决你的问题,请参考以下文章