目录
Spring框架
一、Spring框架的发展历史
- Spring:春天–>Spring这个框架给软件行业带来了春天
- 2002年,首次推出了Spring框架的雏形:interface21框架
- Spring框架既以interface21框架为基础,经过重新设计,并不断丰富其内涵,在2004.3.24,发布了1.0正式版
- Rod Jhonson,Spring Frameword创始人,著名作者,他的专业不是计算机,而是音乐学
- Springl理念:使现有的技术更加容易使用,Spring本身是一个大杂烩,整合了现有的技术框架!
二、市面上比较流行的架构方式
- SSH:Struct2+Spring+Hibernate! (现在基本上过时了)
- SSM:Spring+SpringMVC+Mybatis!
三、说了这么多,那到底什么是Spring,Spring 解决了什么问题,为什么要使用 Spring?
Spring 是个Java企业级应用的开源框架。它主要用来开发Java应用。Spring 框架目标是简化企业项目开发,它的理念是使现有的技术更容易使用,Spring本身是一个大杂烩,整合了现有的技术框架。
主要有以下几个模块组成:(这里先简单写一下,下面会详细写)
Spring Core:Spring核心类库,提供IOC服务的。
Spring Context:提供框架式的Bean访问方式,以及企业级能力(JNDI、定时任务等)
Spring AOP:AOP服务
Spring DAO:对JDBC的抽象,简化了数据访问异常的处理
Spring ORM:对现有的ORM框架的支持
Spring Web:提供了面向Web的综合特性,例如多方文件上传
Spring MVC:提供面向Web应用的Model-View-Controller实现
Spring 解决了什么问题?我们为什么要使用 Spring 框架?
我们平常在使用 SpringMVC,SpringBoot 做实际开发的时候,我们的pojo类,Dao层和Service层和Conntroller层中,所有的类我们都没有去手动的初始化过,我们知道 Java 语言是面向对象的,但是我们都没都创建过对象何来面向对象呢,所以,这些事情 Spring 都帮我们做好了。
大家都知道 Spring 本身就是个大容器,他里面存的是什么呢,就是存储的一个个的已经初始化好的对象(懒加载暂时不提),Spring 在运行的时候,会去加载我们的配置文件(Springboot就是加载启动类开始),然后根据你配置好的路径去加载指定的类或者让指定的注解生效,意思就是创建Bean,然后把这些类统统的初始化一遍。之后才会有我们通常所说的依赖注入,依赖注入就是把 Spring 已经初始化好的对象注入指定的对象中,但是它在这么多对象中是怎么找到和它自己匹配的对象呢,我们这里只说注解的方式依赖注入。
@Autowired是Spring框架提供的一个依赖注入的注解,它主要是根据byType的方式来进行依赖注入的,如果需要根据byName来进行依赖注入,需要和@Quilifier注解来配合使用。
总结:Spring 这个框架帮我们解决了对象初始化的问题,我们不需要去手动初始化一个一个的类,Spring都会帮我们自动初始化,需要用的时候自己去拿就行了。
四、Spring的官网和项目引入
Spring官网: Spring | Learn
官方下载地址: Index of release/org/springframework/spring
Github:spring-projects/spring-framework: Spring Framework (github.com)
Maven依赖:
<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.3.8</version>
</dependency>
五、Spring框架的优点
我们在项目中为什么要使用Spring框架?
- Spring是一个开源的免费的框架(容器)。
- Spring是一个轻量级的(本身很小,下载一个包就可以用了)、非入侵式的框架(引入了Spring不会改变你原来的代码情况)!基本的版本大约是2MB,如果是入侵式的就是你导入了一个jar包导致你原来的项目不能用了。
- 控制反转(IOC):Spring通过控制反转实现了松散耦合
- 和面向切面编程(AOP):Spring支持面向切面的编程,并且把应用业务逻辑和系统服务分开。
- 容器:Spring 包含并管理应用中对象的生命周期和配置。
- MVC框架:Spring的WEB框架是个精心设计的框架,是Web框架的一个很好的替代品。
- 支持事务管理:Spring 提供一个持续的事务管理接口,可以扩展到上至本地事务下至全局事务(JTA)。
8.Spring 提供方便的API把具体技术相关的异常(比如由JDBC,Hibernate or JDO抛出的)转化为一致的unchecked 异常。
总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架!
六、Spring框架的缺点
1.发展了太久之后,违背了原来的理念!配置十分繁琐,人称:“配置地狱”。
七、Spring框架的组成结构
-
核心容器SpringCode: 核心容器提供Spring框架的基本功能。—-它主要的组件就是BeanFactory,是工厂模式的实现。同时BeanFactory适用控制反转(IOC)思想将应用程序的配置和依赖性规范与实际的应用程序分开。
-
Spring Context: Spring上下文是一个配置文件,主要向框架提供上下文信息。
-
SpringAop: 通过配置管理特性,SpringAOP模块直接将面向切面地编程功能集成到了Spring框架中,所以,它可以很容易地使Spring框架管理的任何对象支持AOP。SpringAOP模块也是基于Spring的应用程序中的对象提供了事务管理服务。—–比较强大的功能。
-
SpringDAO: 它主要和dao层相关联,可以用该结构来管理异常处理和不同数据库供应商抛出的错误信息。其中异常层次结构简化了错误处理,并且极大地降低了需要编写地异常代码数据(例如打开和关闭连接)。
-
Spring ORM : Spring框架中插入了若干个ORM框架,从而提供了ORM的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
-
SpringWEB模块: Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
-
SpringMVC:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、FreeMarker、Velocity、Tiles(jsp布局)、iText(报表处理) 和 poi。
八、SpringIOC
1、IOC理论的推导
1.UserDao 接口
2.UserDAOImpl实现类
3.UserService业务接口
4.UserServiceImpl业务实现类
在我们之前的业务中,用户的需求可能会影响我们原来的代码,我们需要根据用户的需求请修改源代码!如果程序代码量十分大,修改一次的成本代价十分昂贵!
我们使用了一个Set接口实现,已经发生了革命性的变化!
private UserDAO userDao;
//利用set进行动态实现值的注入
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
- 之前,程序是主动创建对象,控制权在程序员手上!
- 使用了set注入后,程序不再具有主动性,而是变成了被动的接受对象!
让程序通过某种方式被动得接受对象的操作:这就叫控制反转。
这种思想,从本质上解决了问题,我们程序员不用再去管理对象的创建了,系统的耦合性大大减低,可以更加专注的在业务的实现上!这时IOC的原型!
2、 那说白了,什么是SpringIOC?
我们由一个图来解释什么是SpringIOC。
控制反转是一种通过(XML或者是注解)并通过第三方去生产获取特定对象的方式。在Spring中实现控制反转的是IOC容器,其实现方法是依赖注入。
根据上述的这句话,我自己手撸了一个微型版的SpringIOC 和 AOP 具体见:
博客:
GitHub:
对于控制反转,在熟记上述的概念之后,我们还要会对控制反转进行拆分,分别为 控制 和 反转
控制:谁来控制对象的创建,传统的应用程序的对象是由我们手动new出来的,在我们使用Spring之后,对象是由Spring来创建的。
反转:程序本身不创建对象,而变成被动的接收对象。
那什么又是依赖注入呢?
所谓的依赖注入就是利用set()方法进行注入。
总结来说:所谓的IOC,就一句话:对象由Spring来创建,管理和装配。
3、SpringIOC的几种注入方式
1、构造器注入
使用构造器注入对象的方式,我们默认使用的是无参构造创建对象!
如果我们要使用有参构造创建对象,有以下三种方式
第一种方式:下标法
<constructor-arg index= "0" value = "zhangsan"></constructor>
第二种方式:通过类型创建
<constructor-arg type= "java.lang.String" value = "zhangsan"></constructor>
注意:这个不推荐使用,因为如果有两个相同类型的好像就无法识别了
第三种方式:直接通过参数名来创建,我们一般都用这个
<constructor-arg name= "name" value = "zhangsan"></constructor>
我们之后写每一个类都要把它注册到beans.xml Spring的配置文件中,要养成好习惯!!!
在bean.xml中的所有bean,一旦被注册到配置文件中,我们启动项目的时候,就被Spring底层通过Java的反射机制动态注入,所以可以直接拿过来使用。
总结:Spring通过构造器创建对象的方式一共有四种,无参的一种,有参的三种,一般我们会使用参数名的方式来创建,在配置文件被加载的时候,Spring容器中的对象就已经被初始化了!Spring容器,指的是配置文件中的beans!
2、依赖注入
依赖注入,之前说了说白了底层就是利用set()进行注入,我将其拆开来。
依赖:bean对象的创建依赖于容器。
注入:bean对象中的所有属性,由容器来注入
依赖注入共有8种注入
第一种:普通注入,name:value
第二种,引用注入,name:ref
第三种,数组注入
<property name = "">
<array>
<value></value>
<value></value>
<value></value>
</array>
</property>
第四种,List集合注入
<property name = "">
<list>
<value></value>
<value></value>
<value></value>
</list>
</property>
第五种,Set集合注入
<property name = "">
<set>
<value></value>
<value></value>
<value></value>
</set>
</property>
第六种,map集合注入
<property name = "">
<map>
<entry key="" value=""></value>
<entry key="" value=""></value>
<entry key="" value=""></value>
</map>
</property>
第七种,null注入
<property name = "">
<null/>
</property>
第八种,Properties注入
<property name = "">
<props>
<prop key="" >value</value>
<prop key="" >value</value>
<prop key="" >value</value>
</props>
</property>
3、 P命名空间和C命名空间注入
P命名空间注入:
在beans标签后面加上如下第三方地址:
xmlns:p="http://www.springframework.org/schema/p"
C命名空间注入:
在beans标签后面加上如下第三方地址:
xmlns:c="http://www.springframework.org/schema/c"
总结:SpringIOC
在说Spring IOC之前,我们还要来讲讲历史,我们先来看在 Spring 没有出现之前我们是怎么样创建新的对象的,在没有 Spring 之前,我们一般都是使用new操作符来创建对象的,这一个过程需要我们程序员手动去声明,而 Spring 出现之后,我们程序员将这个手动创建对象这个过程交给spring容器去做。
那么具体什么是IOC控制反转呢?所谓控制反转,是指一种通过(XML或者是注解)并通过第三方组件去生产和获取特定对象的方式。我们可以把控制反转拆开来,控制:谁来控制对象的创建,传统的应用程序的对象是由我们手动new出来的,在我们使用Spring之后,对象是由Spring来创建的。反转:程序本身不创建对象,而变成被动的接收对象。我们将本来我们需要手动去创建对象这一个过程全程交给spring容器去,由spring负责对象的创建,管理和装配。spring IOC,底层通过Java的反射 机制和 动态代理模式来实现的。在讲到spring IOC的注入之前,我们先来看看其最基本的依赖注入,我们在类中声明一个对象,我们一般如何初始化这个类,我们会使用set()方法进行初始化,也就是注入。依赖注入,什么是依赖注入呢?依赖注入就是,我们依赖spring这个容器,底层通过Java的反射机制和动态代理模式通过set()方法对一个对象进行初始化的过程。Spring的IOC有三种依赖注入方式分别是, :构造器注入、setter方法注入、根据注解注入。总结来说:所谓的IOC,就一句话:对象由Spring来创建,管理和装配。
九、关于Spring中的Bean?
1、Spring支持几种作用域(Scope)的bean?
Spring容器中的bean可以分为5个范围:
1、singleton(单例模式):每次从容器中getBean的时候,都只会拿之前创建好的哪一个对象,这是Spring默认的机制。
注意:单线程一般都使用singleton
<bean id="address" class="com.at.cheng.pojo.Address" scope="singleton">
<property name="address" value="广东"></property>
</bean>
2、prototype(原型模式):每次从容器中get的时候,都会产生一个新的对象
注意:多线程可以使用prototype
<bean id="address" class="com.at.cheng.pojo.Address" scope="prototype">
<property name="address" value="广东"></property>
</bean>
其余的作用域,我们只能在web开发中使用。
3、request:为每一个网络请求创建一个实力,在请求完成之后,bean会失效并被垃圾回收器回收。
4、session:与request类似,确保每个session中有一个bean的实例,在session过期后,bean会随之失效。
5、global-session:全局作用域,global-session和Portlet应用相关。当你的应用部署在Portlet容器中工作时,它包含很多portlet。如果你想要声明让所有的portlet共用全局的存储变量的话,那 么这全局变量需要存储在global-session中。全局作用域与Servlet中的session作用域效果相同。
2、Spring框架中的单例Bean是线程安全的么?
Spring框架并没有对单例Bean进行任何多线程的封装处理。
关于单例Bean的线程安全和并发问题,需要开发者自行去搞定。
单例的线程安全问题,并不是Spring应该去关心的,Spring应该做的是,根据提供的配置创建单例Bean或多例Bean的功能。
当然,实际上,大部分的SpringBean并没有可变的状态,所以在某种程度上说 Spring 的单例
Bean 是线程安全的。如果你的 Bean 有多种状态的话,就需要自行保证线程安全。最浅显的解决办法,就是将多态 Bean 的作用域(Scope)由 Singleton 变更为 Prototype。
3、说一说Spring Bean的生命周期
Spring Bean的生命周期是一个比较复杂的过程,具体详细见我另一篇博客:Spring Bean 的生命周期
十、SpringAOP
1、SpringAOP的切入点
我们在开发代码的时候通常是纵向开发:dao——service——controller——再到前端,我们这个流程在之前已经完成了,但是我们想给我们我们之前写的代码加入日志log的功能,我又得去修改我原有的代码,在修改的过程中,我可能会写出bug,从而导致我先前写的代码全盘奔溃。这样就违背了我们OOP面向对象的开闭原则,对拓展开放,对修改关闭。
就在这个时候,我们为了不改变纵向开发的代码,防止纵向开发的代码全盘奔溃,我们就需要用代理模式来实现横向插入到纵向开发,而这也是AOP的实现机制,面向切面编程。
2、什么是AOP?
SpringAOP总结成一句话就是:AOP是一个横向的面向切面编程的思想,指在不影响原来业务的情况下,实现动态的增强。
Spring AOP是基于动态代理的,如果要代理的对象实现了某个接口,那么Spring AOP就会使用JDK动态代理去创建代理对象(房东要租房,房东实现租房这个接口,Spring AOP就会使用JDK动态代理生成租房代理对象,既中介);而对于没有实现接口的对象,就无法使用JDK动态代理,转而使用CGlib动态代理生成一个被代理对象的子类来作为代理(生成房东的子类来作为代理)。
当然也可以使用AspectJ,Spring AOP中已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架了。使用AOP之后我们可以把一些通用功能抽象出来,在需要用到的地方直接使 用即可,这样可以大大简化代码量。我们需要增加新功能也方便,提高了系统的扩展性。
只要你提到了AspectJ,那么我就应该准备说一说AspectJ了
3、Spring AOP和AspectJ AOP有什么区别?
1、SpringAOP属于运行时增强,而AspectJ是编译时增强的。
2、SpringAOP是基于代理的,而AspectJ是基于字节码操作的。
3、如果我们的切面比较少,那么两者性能差异不大,但是如果切面太多的话,最好选择AspectJ,它比SpringAOP快很多。
Spring AOP已经集成了AspectJ,AspectJ应该算得上是Java生态系统中最完整的AOP框架了。
AspectJ相比于Spring AOP功能更加强大,但是Spring AOP相对来说更简单。
说到切面问题,那么我就应该准备说一说,关注点和横切关注点的区别了
4、在SpringAOP中,关注点和横切关注点的区别是什么?
关注点:关注点在是应用中的一个模块的行为,一个关注点可能会被定义成为我们想要去实现的一个功能。
横切关注点:横切关注点是一个关注点,这个关注点是整个应用都会用到的功能,并影响整个应用,比如日志、安全等等,几乎应用的每个模块都需要的功能。
连接点:连接点代表着一个应用程序的某个位置,在这个位置我们可以插入一个AOP切面,它实际上是应用程序执行SpringAOP的位置。
切入点:切入点是一个或者是一组连接点,通知将在这些位置上执行。
5、切面通知又是什么,它有哪些类型呢?
切面通知是在方法执行前或者是方法执行后要做的动作,实际上是程序执行时要通过SpringAOP框架触发的代码。
Spring的切面(通知)可以分为五种类型的通知:
1、before:方法执行前被调用。
2、after:无论方法是否执行成功,方法执行后都会被调用。
3、after-returing:仅当方法执行成功后才会被调用。
4、after-throwing:在方法抛出异常退出时才会被调用的通知。
5、around:在方法执行之前和之后调用的通知。
5、使用AOP的场景
AOP常用的场景有以下几个:
1、为代码添加日志功能
2、JDBC事务管理
3、权限管理
十一、关于Spring框架中的事务
关于事务的知识点和Spring框架中的事务具体见我另一篇博客:Java事务
十一、Spring 和 SpringBoot 的区别
有关Spring 和 SpringBoot 的区别见我其他博客:Spring 和 SpringBoot 的区别