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的体系结构
IoC的概念和作用
什么是程序的耦合耦合性(Coupling),也叫耦合度,是对模块间关联程度的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。模块间的耦合度是指模块之间的依赖关系,包括控制关系、调用关系、数据传递关系。模块间联系越多,其耦合性越强,同时表明其独立性越差( 降低耦合性,可以提高其独立性)。耦合性存在于各个领域,而非软件设计中独有的,但是我们只讨论软件工程中的耦合。在软件工程中,耦合指的就是就是对象之间的依赖性。对象之间的耦合越高,维护成本越高。因此对象的设计应使类和构件之间的耦合最小。软件设计中通常用耦合度和内聚度作为衡量模块独立程度的标准。划分模块的一个准则就是高内聚低耦合。
解决程序耦合的思路当是我们讲解jdbc时,是通过反射来注册驱动的,代码如下:
Class.forName("com.mysql.jdbc.Driver");//此处只是一个字符串
此时的好处是,我们的类中不再依赖具体的驱动类,此时就算删除mysql的驱动jar包,依然可以编译(运行就不要想了,没有驱动不可能运行成功的)。
同时,也产生了一个新的问题,mysql驱动的全限定类名字符串是在java类中写死的,一旦要改还是要修改源码。解决这个问题也很简单,使用配置文件配置。
工厂模式解耦
在实际开发中我们可以把三层的对象都使用配置文件配置起来,当启动服务器应用加载的时候,让一个类中的方法通过读取配置文件,把这些对象创建出来并存起来。在接下来的使用的时候,直接拿过来用就好了。那么,这个读取配置文件,创建和获取三层对象的类就是工厂。
控制反转-Inversion Of Control
这种被动接收的方式获取对象的思想就是控制反转,它是spring框架的核心之一
明确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:约束.
创建业务层接口和实现类
创建持久层接口和实现类
基于XML的配置(入门案例
第一步:拷贝必备的jar包到工程的lib目录中
第二步:在类的根路径下创建一个任意名称的xml文件(不能是中文)
给配置文件导入约束:
/spring-framework-5.0.2.RELEASE/docs/spring-framework-reference/html5/core.html
第三步:让spring管理资源,在配置文件中配置service和dao
测试配置是否成功
Spring基于XML的IOC细节
spring中工厂的类结构图
BeanFactory和ApplicationContext的区别
ApplicationContext接口的实现类
IOC中bean标签和管理对象细节
bean标签
bean的作用范围和生命周期
实例化Bean的三种方式
第一种方式:
使用默认无参构造函数
<!--在默认情况下:
它会根据默认无参构造函数来创建类对象。如果bean中没有默认无参构造函数,将会创建失败。
--><beanid="accountService"class="com.itheima.service.impl.AccountServiceImpl"/>
spring的依赖注入
依赖注入的概念
依赖注入:Dependency Injection。它是spring框架核心ioc的具体实现。我们的程序在编写时,通过控制反转,把对象的创建交给了spring,但是代码中不可能出现没有依赖的情况。ioc解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。那这种业务层和持久层的依赖关系,在使用spring之后,就让spring来维护了。简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
构造函数注入
set方法注入
使用p名称空间注入数据(本质还是调用set方法)
配置文件代码
注入集合属性
Spring配置文件中提示的配置
案例:使用spring的IoC的实现账户的CRUD
需求和技术要求
需求
实现账户的CRUD操作
技术要求
使用spring的IoC实现对象的管理
使用DBAssit作为持久层解方案决
使用c3p0数据源
环境搭建
拷贝jar包
创建数据库和编写实体类
编写持久层代码
编写业务层代码
创建并编写配置文件
配置步骤
配置对象
测试案例
测试类代码
分析测试了中的问题
通过上面的测试类,我们可以看出,每个测试方法都重新获取了一次spring的核心容器,造成了不必要的重复代码,增加了我们开发的工作量。这种情况,在开发中应该避免发生。
可能会想到把容器的获取定义到类中去。例如:
基于注解的IOC配置
明确:写在最前
关于实际的开发中到底使用xml还是注解,每家公司有着不同的使用习惯。所以这两种配置方式我们都需要掌
握。
学习基于注解的IoC配置,大家脑海里首先得有一个认知,即注解配置和xml配置要实现的功能都是一样的,都是要降低程序间的耦合。只是配置的形式不一样。我们在讲解注解配置时,采用上一章节的案例,把spring的xml配置内容改为使用注解逐步实现。
环境搭建
注意:在基于注解的配置中,我们还要多拷贝一个aop的jar包。如下图
第一步:拷贝必备jar包到工程的lib目录。
第二步:使用@Component注解配置管理的资源
注意:当我们使用注解注入时,set方法不用写
第三步:创建spring的xml配置文件并开启对注解的支持
注意:由于我们使用了注解配置,此时不能在继承JdbcDaoSupport,需要自己配置一个JdbcTemplate基于注解整合时,导入约束时需要多导入一个context名称空间下的约束。
常用注解
相当于:<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方式的比较:
spring管理对象细节
基于注解的spring IoC配置中,bean对象的特点和基于XML配置是一模一样的。
spring的纯注解配置
写到此处,基于注解的IoC配置已经完成,但是大家都发现了一个问题:我们依然离不开spring的xml配置文件,那么能不能不写这个bean.xml,所有配置都用注解来实现呢?当然,同学们也需要注意一下,我们选择哪种配置的原则是简化开发和配置方便,而非追求某种技术。
待改造的问题
我们发现,之所以我们现在离不开xml配置文件,是因为我们有一句很关键的配置:
新注解说明
@Configuration
作用:用于指定当前类是一个spring配置类,当创建容器时会从该类上加载注解。获取容器时需要使用AnnotationApplicationContext(有@Configuration注解的类.class)。
属性:value:用于指定配置类的字节码
@ComponentScan
作用:用于指定spring在初始化容器时要扫描的包。作用和在spring的xml配置文件中的:<context:component-scanbase-package="com.itheima"/>是一样的。
属性:basePackages:用于指定要扫描的包。和该注解中的value属性作用一样。
@Bean
作用:该注解只能写在方法上,表明使用此方法创建一个对象,并且放入spring容器。
属性:name:给当前@Bean注解方法创建的对象指定一个名称(即bean的id)。
示例代码:
@PropertySource
作用:用于加载.properties文件中的配置。例如我们配置数据源时,可以把连接数据库的信息写到properties配置文件中,就可以使用此注解指定properties配置文件的位置。
属性:value[]:用于指定properties文件位置。如果是在类路径下,需要写上classpath:
@Import
作用:用于导入其他配置类,在引入其他配置类时,可以不用再写@Configuration注解。当然,写上也没问题。
属性:value[]:用于指定其他配置类的字节码。
通过注解获取容器
工程结构图
Spring整合Junit
测试类中的问题和解决思路
问题
解决思路
分析针对上述问题,我们需要的是程序能自动帮我们创建容器。一旦程序能自动为我们创建spring容器,我们就无须手动创建了,问题也就解决了。我们都知道,junit单元测试的原理(在web阶段课程中讲过),但显然,junit是无法实现的,因为它自己都无法知晓我们是否使用了spring框架,更不用说帮我们创建spring容器了。不过好在,junit给我们暴露了一个注解,可以让我们替换掉它的运行器。这时,我们需要依靠spring框架,因为它提供了一个运行器,可以读取配置文件(或注解)来创建容器。我们只需要告诉它配置文件在哪就行了。
配置步骤
第一步:拷贝整合junit的必备jar包到lib目录
此处需要注意的是,导入jar包时,需要导入一个spring中aop的jar包。
第二步:使用@RunWith注解替换原有运行器
第三步:使用@ContextConfiguration指定spring配置文件的位置
第四步:使用@Autowired给测试类中的变量注入数据
为什么不把测试类配到xml中
在解释这个问题之前,先解除大家的疑虑,配到XML中能不能用呢?答案是肯定的,没问题,可以使用。那么为什么不采用配置到xml中的方式呢?这个原因是这样的:第一:当我们在xml中配置了一个bean,spring加载配置文件创建容器时,就会创建对象。第二:测试类只是我们在测试功能时使用,而在项目中它并不参与程序逻辑,也不会解决需求上的问题,所以创建完了,并没有使用。那么存在容器中就会造成资源的浪费。所以,基于以上两点,我们不应该把测试配置到xml文件中。
AOP的相关概念
AOP概述
什么是AOP
AOP:全称是Aspect Oriented Programming即:面向切面编程。
简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
AOP的作用及优势
作用:在程序运行期间,不修改源码对已有方法进行增强。
优势:减少重复代码提高开发效率维护方便
AOP的实现方式
使用动态代理技术
AOP的具体应用
案例中问题
下面是客户的业务层实现类
客户的业务层实现类
问题就是:事务被自动控制了。换言之,我们使用了connection对象的setAutoCommit(true)此方式控制事务,如果我们每次都执行一条sql语句,没有问题,但是如果业务方法一次要执行多条sql语句,这种方式就无法实现功能了。
问题的解决
解决办法:让业务层来控制事务的提交和回滚。
新的问题
通过对业务层改造,已经可以实现事务控制了,但是由于我们添加了事务控制,也产生了一个新的问题:业务层方法变得臃肿了,里面充斥着很多重复代码。并且业务层方法和事务控制方法耦合了。试想一下,如果我们此时提交,回滚,释放资源中任何一个方法名变更,都需要修改业务层的代码,况且这还只是一个业务层实现类,而实际的项目中这种业务层实现类可能有十几个甚至几十个。
思考:这个问题能不能解决呢?
答案是肯定的,使用下一小节中提到的技术。
动态代理回顾
动态代理的特点
字节码随用随创建,随用随加载。它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。装饰者模式就是静态代理的一种体现。
动态代理常用的有两种方式
基于接口的动态代理
提供者:JDK官方的Proxy类。
要求:被代理类最少实现一个接口
基于子类的动态代理
提供者:第三方的CGLib,如果报asmxxxx异常,需要导入asm.jar。
要求:被代理类不能用final修饰的类(最终类)。
使用JDK官方的Proxy类创建代理对象
此处我们使用的是一个演员的例子:在很久以前,演员和剧组都是直接见面联系的。没有中间人环节。而随着时间的推移,产生了一个新兴职业:经纪人(中间人),这个时候剧组再想找演员就需要通过经纪人来找了。下面我们就用代码演示出来。
使用CGLib的Enhancer类创建代理对象
解决案例中的问题
Spring中的AOP
AOP相关术语
Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。
Pointcut(切入点):所谓切入点是指我们要对哪些Joinpoint进行拦截的定义。
学习spring中的AOP要明确的事
a、开发阶段(我们做的)编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP编程人员来做。在配置文件中,声明切入点与通知间的关系,即切面。:AOP编程人员来做。
b、运行阶段(Spring框架完成的)Spring框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。
关于代理的选择在spring中,框架会根据目标类是否实现了接口来决定采用哪种动态代理的方式。
基于XML的AOP配置
示例:我们在学习spring的aop时,采用账户转账作为示例。并且把spring的ioc也一起应用进来。
环境搭建
第一步:准备必要的代码此处包含了实体类,业务层和持久层代码。我们沿用上一章节中的代码即可
第二步:拷贝必备的jar包到工程的lib目录
第三步:创建spring的配置文件并导入约束
第四步:配置spring的ioc
第五步:抽取公共代码制作成通知
配置步骤
第一步:把通知类用bean标签配置起来
第二步:使用aop:config声明aop配置
第三步:使用aop:aspect配置切面
第四步:使用aop:pointcut配置切入点表达式
第五步:使用aop:xxx配置对应的通知类型
切入点表达式说明
环绕通知
基于注解的AOP配置
环境搭建
第一步:准备必要的代码和jar包
第二步:在配置文件中导入context的名称空间
第三步:把资源使用注解配置
第四步:在配置文件中指定spring要扫描的包
配置步骤
第一步:把通知类也使用注解配置
第二步:在通知类上使用@Aspect注解声明为切面
作用:把当前类声明为切面类。
第三步:在增强的方法上使用注解配置通知
第四步:在spring配置文件中开启spring对注解AOP的支持
环绕通知注解配置
切入点表达式注解
不使用XML的配置方式
Spring中的JdbcTemplate
JdbcTemplate概述
JdbcTemplate对象的创建
spring中配置数据源
环境搭建
编写spring的配置文件
配置数据源
我们之前已经接触过了两个数据源,C3P0和DBCP。要想使用这两数据源都需要导入对应的jar包。
配置C3P0数据源
配置DBCP数据源
配置spring内置数据源
将数据库连接的信息配置到属性文件中:
JdbcTemplate的增删改查操作
前期准备
在spring配置文件中配置JdbcTemplate
最基本使用
保存操作
更新操作
删除操作
查询所有操作
}
查询一个操作
查询返回一行一列操作
在dao中使用JdbcTemplate
准备实体类
第一种方式:在dao中定义JdbcTemplate
第二种方式:让dao继承JdbcDaoSupport
Spring中的事务控制
Spring事务控制我们要明确的
第一:JavaEE体系进行分层开发,事务处理位于业务层,Spring提供了分层设计业务层的事务处理解决方案。
第二:spring框架为我们提供了一组事务控制的接口。具体在后面的第二小节介绍。这组接口是在spring-tx-5.0.2.RELEASE.jar中。
第三:spring的事务控制都是基于AOP的,它既可以使用编程的方式实现,也可以使用配置的方式实现。我们学习的重点是使用配置的方式实现。
Spring中事务控制的API介绍
PlatformTransactionManager
TransactionDefinition
事务的隔离级别
事务的传播行为
超时时间
默认值是-1,没有超时限制。如果有,以秒为单位进行设置。
是否是只读事务
建议查询时设置为只读
TransactionStatus
基于XML的声明式事务控制(配置方式)重点
环境搭建
第一步:拷贝必要的jar包到工程的lib目录
第二步:创建spring的配置文件并导入约束
第三步:准备数据库表和实体类
第四步:编写业务层接口和实现类
第五步:编写Dao接口和实现类
第六步:在配置文件中配置业务层和持久层对
配置步骤
第一步:配置事务管理器
第二步:配置事务的通知引用事务管理器
第三步:配置事务的属性
第四步:配置AOP切入点表达式
第五步:配置切入点表达式和事务通知的对应关系
基于注解的配置方式
环境搭建
第一步:拷贝必备的jar包到工程的lib目录
第二步:创建spring的配置文件导入约束并配置扫描的包
第三步:创建数据库表和实体类
和基于xml的配置相同。略
第四步:创建业务层接口和实现类并使用注解让spring管理
第五步:创建Dao接口和实现类并使用注解让spring管理
配置步骤
第一步:配置事务管理器并注入数据源
第二步:在业务层使用@Transactional注解
第三步:在配置文件中开启spring对注解事务的支持
不使用xml的配置方式
Spring5的新特性
与JDK相关的升级
jdk版本要求:
利用jdk8版本更新的内容
第一:基于JDK8的反射增强请看下面的代码:
核心容器的更新
Spring Framework 5.0 现在支持候选组件索引作为类路径扫描的替代方案。该功能已经在类路径扫描器中添加,以简化添加候选组件标识的步骤。
应用程序构建任务可以定义当前项目自己的META-INF/spring.components 文件。在编译时,源模型是自包含的,JPA 实体和Spring 组件是已被标记的。
从索引读取实体而不是扫描类路径对于小于200 个类的小型项目是没有明显差异。但对大型项目影响较大。
加载组件索引开销更低。因此,随着类数的增加,索引读取的启动时间将保持不变。加载组件索引的耗费是廉价的。因此当类的数量不断增长,加上构建索引的启动时间仍然可以维持一个常数, 不过对于组件扫描而言,启动时间则会有明显的增长。这个对于我们处于大型Spring 项目的开发者所意味着的,是应用程序的启动时间将被大大缩减。虽然20 或者30 秒钟看似没什么,但如果每天要这样登上好几百次,加起来就够你受的了。使用了组件索引的话,就能帮助你每天过的更加高效。你可以在Spring 的Jira上了解更多关于组件索引的相关信息。
JetBrains Kotlin语言支持
响应式编程风格
Junit5支持
依赖类库的更新
终止支持的类库
以上是关于spring5的主要内容,如果未能解决你的问题,请参考以下文章