Spring的控制反转/依赖注入
:Spring
1.简介
三层架构:
展现层web:controller(页面的跳转),jsp(页面)
持久层:dao(数据操作)
业务层:service(业务逻辑)
2.Spring的优点
- 方便解耦,简化开发
- AOP编程的支持
- 声明事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 降低JavaEE API的使用难度
- Spring源码是经典学习范例
3.spring的体系结构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XHZlBzUi-1616208112308)(assets/image-20201217223129165.png)]
模块:
Spring模块构建再核心容器之上,核心内容定义了创建、配置和管理bean的方式
每个模块的功能如下:
- 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是
BeanFactory
,它是工厂模式的实现。BeanFactory
使用控制反转 (IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。 - Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
- Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。
- Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
- Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
- Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
- Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
第二节:Spring的IOC控制反转
1.为什么要用Spring
目的:降低耦合
2.程序的耦合
耦合性也叫耦合度,是对模块艰难关系成都的度量。耦合的强弱取决于模块间接口的复杂性、调用模块的方式以及通过界面传送数据的多少。划分模块的一个准则就是高内聚低耦合
有如下分类:
(1)内容耦合。当一个模块直接修改或操作另一个模块的数据时,或一个模块不通过正常入口而转入另一个模块时,这样的耦合被称为内容耦合。内容耦合是最高程度的耦合,应该避免使用之。
(2)公共耦合。两个或两个以上的模块共同引用一个全局数据项,这种耦合被称为公共耦合。在具有大量公共耦合的结构中,确定究竟是哪个模块给全局变量赋了一个特定的值是十分困难的。
(3) 外部耦合 。一组模块都访问同一全局简单变量而不是同一全局数据结构,而且不是通过参数表传递该全局变量的信息,则称之为外部耦合。
(4) 控制耦合 。一个模块通过接口向另一个模块传递一个控制信号,接受信号的模块根据信号值而进行适当的动作,这种耦合被称为控制耦合。
(5)标记耦合 。若一个模块 A 通过接口向两个模块 B 和 C 传递一个公共参数,那么称模块 B 和 C 之间存在一个标记耦合。
(6) 数据耦合。模块之间通过参数来传递数据,那么被称为数据耦合。数据耦合是最低的一种耦合形式,系统中一般都存在这种类型的耦合,因为为了完成一些有意义的功能,往往需要将某些模块的输出数据作为另一些模块的输入数据。
(7) 非直接耦合 。两个模块之间没有直接关系,它们之间的联系完全是通过主模块的控制和调用来实现的。
**总结:**耦合是影响软件复杂程度和设计质量的一个重要因素,在设计上我们应采用以下原则:如果模块间必须存在耦合,就尽量使用数据耦合,少用控制耦合,限制公共耦合的范围,尽量避免使用内容耦合
3.什么是IOC
控制反转(缩写为IOC)。是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。其中最常见的方式叫做依赖注入(简称DI),使用对象的时候不再是直接new,而是将创建对象的权力交给框架中的核心容器,需要使用对象的时候直接从容器中获取
第三节:Spring项目的搭建
1.Spring目录结构
docs:API和开发规范
libs:jar包和源码
schema:约束
Bean Factory接口:
Spring容器顶层接口:获取Bean对象;管理类和类之间的关系(依赖关系)BeanFactory由org.springframework.beans.factory.BeanFactory接口定义 BeanFactory是工厂模式(Factory pattern)的实现,是IOC容器的核心接口,它的职责包括:实例化、定位、配置应用程序中的对象及建立这些对象间的依赖。
BeanFactory接口包含以下基本方法——ApplicationContext肯定都有,因为他是子接口,加强版 boolean containsBean(String beanName) 判断工厂中是否包含给定名称的bean定义,若有则返回true。
Object getBean(String str) 返回给定名称注册的bean实例。根据bean的配置情况,如果是singleton模式将返回一个共享实例,否则将返回一个新建的实例,如果没有找到指定bean,该方法可能会抛出异常。
Object getBean(String, Class) 返回以给定名称注册的bean实例,并转换为给定class类型
Class getType(String name) 返回给定名称的bean的Class,如果没有找到指定的bean实例,则排除NoSuchBeanDefinitionException异常
boolean isSingleton(String) 判断给定名称的bean定义是否为单例模式
String[] getAliases(String name) 返回给定bean名称的所有别名
ApplicationContext接口
是基于BeanFactory之上的,提供了应用程序框架服务,扩展的新功能如下:提供国际化的支持资源访问,如URL和文件 事件传递载入多个配置文件等 实现类常见有三个
ClassPathXmlApplicationContext:-classpath路径加载xml文件的FileSystemXmlApplicationContext:基于项目根路径进行加载xml文件的AnnotationConfigApplicationContext:基于注解的配置。基于类书写的配置。
面试题:BeanFactory 才是 Spring 容器中的顶层接口。
ApplicationContext 是它的子接口。
BeanFactory 和 ApplicationContext 的区别:
创建对象的时间点不一样。
ApplicationContext:(饿汉模式)只要一读取配置文件,马上就会创建配置文件中配置的对象。BeanFactory:(懒加载/懒汉模式)什么时候getBean("id"),也就是说当根据id获取对象时,才会创建。
2.2 getBean()的三种方式
A 通过bean.xml文件中bean标签的id的值获取bean(使用默认构造方法)
Object p1 = context.getBean("唯一标识id");//此处获取的是一个Object类型,可以转换成我们需要的类型。
B 通过类型去获取
People bean = context.getBean(类名.class);
确保bean的类型是唯一的 不然会报错:org.springframework.beans.factory.NoUniqueBeanDefinitionException
C 通过 id + 类型去获取
People bean = context.getBean("p1",People.class);
2.3 创建Bean对象的方式
bean的属性配置
id : 当前bean的唯一标识符
class:配置类的全限定名/全路径
name:配置当前bean的名字,并且可以配置多个。
-
第一种方式:使用默认构造创建(常用)
在spring的bean.xml文件中配置过bean标签,并且设置id和class属性后,会自动的调用默认构造创建对象,如果没有默认的空构造,则对象无法创建。
<bean id="唯一标识id" class="类的全限定名"></bean>
-
第二种方式:使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)
ServiceFactory factory = new ServiceFactory(); <bean id="普通工厂类的唯一标识" class="工厂类的全限定名"></bean> factory.getService(); <bean id="需要通过工厂创建的对象" factory-bean="上边bean的id" factory-method="工厂中的方法名"></bean>
-
第三种方式:使用普通工厂的静态方法创建对象
<!--使用静态工厂的方式创建bean对象--> ServiceFactory.getService(); <bean id="accountService" class="工厂类的全类名" factory-method="生产对象的静态方法"></bean>
2.4 bean对象的作用范围
bean对象的作用范围调整需要配置scope属性,设置单例还是多例(只针对ApplicationContext接口来说,默认是单例的)
scope:常用 singleton,prototype
singleton:单例的(默认值)当加载配置文件时,就会创建对象。
prototype:多例的(当getBean时才会创建对象)
request:作用于请求范围
session:作用于会话范围
global-session: 全局,作用于集群环境。如果不是集群环境,就是session
<bean id="唯一标识" class="全类名" scope="singleton/prototype"></bean>
默认为singleton单例的:整个程序运行期间对象只会被创建一次。
prototype 多例的,在程序运行期将,用了几次就创建几次对象。
多例对象java的GC垃圾回收机制,在检测到对象长时间不用时,会自动回收/销毁。
2.5 bean对象的生命周期
有的类 对象被创建的时候需要调用初始化函数,对象被回收的时候需要调用销毁函数。现在对象时由spring核心容器去管理的。所以这些函数的调用应该由spring负责。我们只需要通过配置告诉spring初始化函数是谁,销毁函数是谁。bean的生命周期函数。可以同过配置两个方法测试。
init-method:对象的初始化方法
destroy-method:销毁对象的方法(main方法测试时,不会调用销毁方法,是因为还没来得及,速度太快,可以手动销毁,调用close();方法,但是此时ApplicationContext对象应该是子类类型,不能再是ApplicationContext类型了);
-
单例对象:
出生:当容器创建时,对象出生
活着:只要容器还在,对象一直存在
死亡:容器销毁,对象也销毁
初始化方法会被调用,但是销毁方法如果是使用ApplicationContext接口类型,销毁方法无法被调用,需要使用子接口类型,才可以看到销毁方法被调用。context.close();
-
多例对象
出生:当使用对象时,才会创建
活着:只要使用,一直活着
[外链图片转存中…(img-hIn93rTa-1616208112315)]
初始化方法会被调用,但是销毁方法如果是使用ApplicationContext接口类型,销毁方法无法被调用,需要使用子接口类型,才可以看到销毁方法被调用。context.close();
-
多例对象
出生:当使用对象时,才会创建
活着:只要使用,一直活着
死亡:java垃圾回收机制,当对象长时间不用时,GC垃圾回收机制,自动回收。