- 概述
Spring是全栈型(full - stack)的 轻量级开源框架。 他能整合许多“开源”的第三方架构。 使其逐渐成为使用最多的Java EE企业应用开源架构。 以IOC (Inverse- of -Control) 控制反转,AOP 面向切面编程 为内核。
-
Spring 的优势
- 方便解耦,简化开发
- AOP编程 (面向切面编程) 的支持
- 声明式事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 源码特别的经典,设计巧妙、结构清晰
-
Spring的体系结构
- Core Container :核心容器。 是Spring的 IOC部分。 Spring 框架任何其他部分的运行都必须 要有核心容器的支持。
- 程序的耦合 :程序间的依赖关系,我们只能降低不能没有。
- 耦合:
程序间的依赖关系
类之间的依赖关系 - 解耦:使用工厂模式
降低程序间的依赖关系
(1):使用反射技术创建对象,而不是使用new 关键字。 这样类的依赖就是 一个“字符串”了
(2):通过配置文件(properties,xml)的方式来 获取要创建的对象全限定类名。
- 耦合:
案例说明: 程序的耦合。
表现层 new创建一个业务层接口实体类,该业务实体类中有个持久层接口实体类(对象映射关系)对象。业务层的saveAccount方法中是持久层实体类调用 saveAccount方法打印表示 创建账户成功。
表现层调用业务层,业务层调用持久层。 其中的调用就是类与类的嵌套。 如下:
//业务层调用持久层,所以需要 来IAccountDao
private IAccountDao accountDao=new AccountDaoImpl();
public void saveAccount() {
accountDao.saveAccount();
//getResourceAsStream():这个方法是获取资源目录下的文件输入流。 建议使用类加载器去获取。
}
从上面的例子可以看出类与类之间的耦合(依赖关系)是非常严重的。 表现层调用业务层,业务层内部new创建持久层,并调用方法打印输出提示成功。
解决: 工厂模式解耦。自定义一个工具类 根据传入的全限定类名来返回不同的对象。
工厂模式改善: 由于我们是直接创建的 业务层对象与持久层接口对象。并没有保存 所以每当 表现层调用业务层时都是一个新的对象。 这样开发的效率并不是很高。
解决: 工厂类定义一个容器存放创建的对象。 一个全限定类名只有一个对象也就是单列对象。
- IOC
概念: 通过上面的案例说明,可以发现我们 使用了一个 “工厂对象” 来获取想要的接口实体类。并使其一个全限定类名永远只返回一个对象。 其实这就是 控制反转(IOC):将创建对象的权力交给框架。
作用: 削减程序的依赖。 但是肯定无法没有依赖。
4.Spring的IOC Spring框架的核心之一。 使用工厂模式解耦,降低程序间的依赖。
使用xml文件作为配置文件,进行信息配置。如下:
<!--约束网上找-->
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--把对象的创建交给Spring架构来管理-->
<!--id :唯一标识符。 核心容器通过 id来返回对象。 SpringIOC控制反转:创建对象交给Spring架构,是Spring的核心之一。
,class:实体类 的全限定类名,也可以是jar包里面的class文件。 通过反射技术生产对象,降低程序间的 耦合度。-->
<bean id="AccountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
<!--综上所述:就是上面介绍的工厂模式的体现-->
</beans>
通过核心容器获取对象 如下:
//获取核心容器 (是一个接口,有三个实现类。) 对象, 并直定配置文件方便读取配置信息。
ApplicationContext ac= new ClassPathXmlApplicationContext("bean.xml");
//通过核心容器对象获取 对象。
IAccountService as= (IAccountService) ac.getBean("AccountService");
IAccountDao adao=ac.getBean("accountDao", AccountDaoImpl.class);
System.out.println(as);
System.out.println(adao);
核心容器接口(ApplicationContext)的实现类区别:
(1):ClassPathXmlApplicationContext,他可以加载类路径下的配置文件。 要求配置文件必须在类路径下。
(2):FileSystemXmlApplicationContext,它可以加载磁盘路径下的配置文件。 要求必须要有访问权限。
(3):AnnotationConfigApplicationContext, 读取注解的方式创建核心容器对象。
//立即加载。 只要下面的核心容器接口对象一旦被创建,xml里面的bean标签 指定的类、jar包中的class文件 都会马上创建一个对象 存放到核心容器中,无论怎样获取都是哪一个对象。
//如果bean标签指定的 内容重复,则创建多个实体类对象。
ApplicationContext ac= new ClassPathXmlApplicationContext("bean.xml");
ApplicationContext ac=new FileSystemXmlApplicationContext("D:\\idea_\\project\\day01_eesy_03spring\\src\\main\\resources\\bean.xml");
第一种方式更贴切实际开发
配置文件使用bean 标签创建对象的三种方式。
指定该xml核心容器一经创建 则bean标签指定的实体类就会被创建并存放至核心容器中。
<!--把对象的创建交给Spring架构来管理-->
<!--id :唯一标识符,class:实体类的全限定类名,也可以是jar包中的class文件-->
<!--第一种:默认构造函数创建对象,并存放到核心容器中,如果实体类没有构造函数则对象无法创建。-->
<bean id="AccountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!--第二种:使用工厂的方法获取对象(使用某个类的方法创建对象,并返回创建的对象)。并存放到核心容器中
具体方法里面是怎么创建的对象 应该有参构造可以,无参构造也可以。这样就解决了只能使用
默认构造方法创建对象。-->
<bean id="beanFactory" class="com.itheima.factory.InstanceFactory"></bean>
<bean id="AccountService______2" factory-bean="beanFactory" factory-method="getAccoutnService"></bean>
<!--第三种:使用工厂的静态方法获取对象(使用某个类的静态方法创建对象,并返回创建的对象)存入容器中。 直接将第二种压缩至一行-->
<bean id="AccountService_______3" class="com.itheima.factory.StaticFactory" factory-method="getAccoutnService"></bean>
配置文件使用bean 标签的作用范围
<!--bean的作用范围调整
Scope属性:
singleton:单例的(默认值)
prototype:多列的
request:作用于web应用的请求范围
session:作用于web应用的会话范围
global-session:作用于集群环境的会话范围,如果不是集群环境,那就是session-->
global-session图解
配置文件使用bean 标签 指定的实体类或者class文件 他们的对象生命周期
<!--bean的生命周期:
单例对象:singleton,每次从核心容器获取对象都是一样的对象。 采用立即加载
出生: 读取配置文件完成时,创建对象。
活着: 核心容器存在,对象就存在。
死亡: 核心容器销毁,对象销毁
总结:容器在,对象在。 容器亡,对象亡。
多例对象:prototype,每次从核心容器获取对象都是不一样的对象。 采用延迟加载。
出生: 从核心容器获取对象时创建。
活着: 只要是在使用过程中都活着。
死亡:java垃圾回收机制。 当对象长时间没有使用,会被Java垃圾处理器回收。因为Spring不知到什么时候销毁对象, 所以不销毁多例对象。
-->
<!--spring 的依赖注入
依赖注入: Dependency Injection
IOC(控制反转)的作用: 降低程序之间、类之间的依赖
依赖关系的管理: 交由Spring框架来维护。 当我们需要对象时由Spring框架为我们
提供。 而我们要做的就是 在配置文件中声明bean即可。
依赖关系的维护(依赖关系的注入):
能注入的数据,三类:
经常变化的数据,并不适用注入的方式。
经常变化的数据,并不适用注入的方式。
经常变化的数据,并不适用注入的方式。
基本数据类型,String类型。 为了对象的初始化????
bean类型(在配置文件中或者注解配置过的bean)
复杂类型/集合类型
注入的方式,三种:
使用构造函数提供,涉及 <constructor-arg name="name" value="名称"></constructor-arg>标签。
标签出现位置:bean标签的内部。
标签属性:
name: 用于指定参数(名称匹配)
value: 给基本数据类型和String类型赋值
ref: 用于指定其他的bean数据类型。也就是拿在配置文件中的bean 类为参数赋值。
弊端: 由于实际开发中业务复杂,我们无法确定需要传入多少个参数。但是如果没
有创造对应的构造函数又没法使用Spring来为我们创建对象。 所以这种注入方
式 一般是在 没有选择余地的时候使用。
使用实体类的set方法提供, 涉及标签<constructor-arg name="name" value="名称"></constructor-arg>
标签出现的位置:bean标签内部
标签属性:
name: 用于指定实体类的set方法名称(除去set)
value: 同上。
ref: 同上。
优势: 解决了用构造函数注入数据的弊端。
使用注解提供
-->
代码展示 如下:
<!--使用默认构造函数提供、指定参数类型提供。
注意:但是单例对象 同一实体类会被创建多个对象-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>
<!--配置一个日期对象-->
<bean id="now" class="java.util.Date"></bean>
<bean id="accountService2" class="com.itheima.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="名称"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>
</bean>
<!--类属性的set方法 注入-->
<bean id="accountService3" class="com.itheima.service.impl.AccountServiceImpl2">
<property name="userName" value="name的参数值"></property>
<property name="age" value="22"></property>
<property name="birthday" ref="now"></property>
</bean>
<!--复杂类型和集合类型的数据注入。 注入方式: 实体类的set方法注入数据、通过构造方法注入。 推荐使用set方式注入
<property></property>内部嵌入 <value></value>标签 赋值。具体请百度。
用于给list结构标签注入数据的标签有
list、set、array
用于给Map结构标签注入数据的标签有
map、properties
总结:结构相同, 注入数据的标签可以互换。
-->
<bean id="accountService4" class="com.itheima.service.impl.AccountServiceImpl3">
<property name="mystrs">
<array>
<value>AAA</value>
<value>BBB</value>
<value>CCC</value>
</array>
</property>
<property name="myList">
<list>
<value>list1</value>
<value>list2</value>
<value>list3</value>
<value>list4</value>
</list>
</property>
<property name="mySet">
<array>
<value>set2222</value>
<value>set3333</value>
<value>set5555</value>
</array>
</property>
<property name="myMap">
<props>
<prop key="AAA">aaa</prop>
<prop key="BBB">bbb</prop>
<prop key="CCC">ccc</prop>
</props>
</property>
<property name="myProps">
<map>
<entry key="test1">
<value>1111</value>
</entry>
<entry key="test2" value="22222"></entry>
</map>
</property>
</bean>