Spring框架
1. 了解Spring
1.1 spring是什么?
• Spring官网:https://spring.io/
• 容器框架
• Spring 是分层的javaee/javase应用,轻量级开源框架,以IOC(控制反转)和AOP(面向切面编程)为内核
1. 怎么使用spring
• spring也是一个容器,里面存放java对象
• 让容器完成对象的创建,对象之间关系的管理(属性赋值)
• 我们在程序中从容器中获取要使用的对象
2. 什么样的对象放到容器中
• dao类,service类,controller类,工具类e
• spring对象默认都是单例的(在容器中叫这个名称的对象就只有一个)
3. 不放入到spring容器中的对象
• 实体类对象,servlet、监听器、过滤器……
4. Spring的优势
• 方便解耦合,简化开发
• AOP编程的支持
• 声明式事务的支持
• 方便程序的测试
• 方便集成各种优秀的框架
• 降低javaee api的使用难度
• spring源码是经典的学习范例
1.2 Spring Maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.0.5.RELEASE</version>
</dependency>
spring核心技术
• IOC AOP 这两个能实现模块之间,类之间的解耦合
1.3 Spring对”依赖”的理解
• 在spring中有一个词叫做依赖:
• Class A 中使用了Class B的属性或者方法,叫做Class A 依赖 Class B
1.4 耦合
• 什么是耦合?
• 简单的来说就是程序之间的依赖性
• 都有什么耦合?
• 类之间的依赖
• 方法之间的依赖
• 解耦合
• 将低的程序间的依赖关系
• 解耦的思路
• 第一步:使用反射机制创建对象,而不是new关键字
• 第二步:通过读取配置文件来获取要创建的对象的全限定类名
2. IOC控制反转
2.1 IOC是什么?
• 英文:Inversion of control
• 描述的是:把对象的创建,赋值,管理工作都交给代码之外的容器实现,也就是对象的创建是有其他的外部资源来完成的
• 控制: 创建对象,对象属性赋值,对象之间的关系管理
• 反转:把原来的开发人员管理,创建对象的权限转移给代码之外的容器实现,由容器代替开发人员管理、创建、赋值。
• 正转:由开发人员在代码中使用new构造方法创建对象,开发人员主动管理对象
• 控制反转:在这个容器里面,这个容器代替了开发人员创建对象,赋值,管理的工作
• 容器:spring 管理所有的组件,主动的new 变成被动的 获取
2.2 为什么使用IOC?
• 对象的管理更加松散
• 解耦合
• 减少对代码的改动,也能实现不同的功能
2.3 在之前的学习中IOC的体现
servlet中体现出来了
所有的对象不需要你去创建,直接在web.xml中配置一下tomcat自动就会帮你创建
tomcat作为容器:里面它存放了 Listener对象,Filter对象,Servlet对象
2.4 IOC的技术实现DI
• DI是IOC的技术实现
• DI翻译过来是 依赖注入
• Dependency Injection
• 我们只需要在程序中提供要使用的对象的名称就可以了,对象如何在容器中创建,赋值,查找都由容器内部实现。
• spring是使用了DI实现了IOC的功能,spring底层创建对象使用的是反射。
• spring是一个容器,管理对象,给属性赋值,底层是反射机制创建对象
3. Spring第一个程序
1. 使用maven快速创建一个java项目
2. 添加maven依赖
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.5.RELEASE</version>
</dependency>
3. 创建类 (接口和他的实现类 随意创建)
4. 创建spring需要的配置文件
大家公认的配置文件的名字为 application.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创建对象
声明bean,告诉spring要创建哪个类的对象
id:对象的自定义名称,自己给对象起个名
class:类的全限定名称(不能是接口)
-->
<!-- 一个Bean 声明一个对象 -->
<bean id="test" class="com.yixuexi.service.impl.DoServiceImpl"></bean>
<bean id="myDate" class="java.util.Date"></bean>
<bean id="myString" class="java.lang.String"></bean>
</beans>
5. 使用Spring容器
创建ClassPathXmlApplicationContext 对象
@Test
public void doSomeSpringTest(){
//使用spring容器创建的对象
//1.指定spring配置文件
String config = "Test.xml";
//2.创建表示spring容器的对象,ApplicationContext(是个接口)
//ApplicationContext就是表示Spring的容器,通过容器能获取到对象
//ClassPathXmlApplicationContext表示从类路径中加载配置文件
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(config);
//得到对象 通过之前在配置文件中写的id得到,通过key得到value
//在进行强转一下,向下转型
DoService do1 = (DoService)ac.getBean("test");
}
3.1 spring 创建对象的时机
• 通过测试,发现在spring读取配置文件之后会立马创建出配置文件中已经配置了的对象信息
• 也就是说,在这行代码执行时 new ClassPathXmlApplicationContext(config); 所有以配置的对象都创建完毕
• 默认创建对象的时间是 在创建spring容器时,会创建配置文件中所有的对象
• spring创建对象默认调用的是对象的无参构造
1. 获取容器中定义好的对象的数量 容器就是ApplicationContext
int count = ac.getBeanDefinitionCount();
2. 获取容器中每个定义的对象的名称 也就是id 【key是什么】
// 返回一个String数组
String[] names = ac.getBeanDefinitionNames();
// 遍历数组
for (String name : names) {
System.out.println(name);
}
3. 创建一个非自定义类的对象,也就是说创建一个 Date类 String 类….
<bean id="myDate" class="java.util.Date"></bean>
<bean id="myString" class="java.lang.String"></bean>
4. XML注入/${}
4.1. 在spring配置文件中给java对象赋值
DI:依赖注入(创建对象,并给属性赋值 注入就是赋值的意思)
1. DI的实现方式有两种
1. 在spring的配置文件中,使用标签和属性完成,叫做基于xml的DI实现
2. 使用spring中的注解,完成属性赋值,叫做基于注解的DI实现
2. DI的语法分类
• set注入(设值注入) :spring调用类的set方法,在set方法可以实现属性的赋值【很多人用 80%】
• 构造注入:spring调用类的有参构造方法,创建对象,在构造中完成赋值
3. spring中对数据类型的定义
• 简单数据类型:spring中规定了java中的基本数据类型和String都是简单类型(包装类也是简单类)
• 引用数据类型:Object及子类
4.2 set注入
set注入 【xml方式】:通过set注入进行对里面属性的赋值(也叫设值注入)
简单数据类型的set注入(本质上是调用的是set方法)
<bean id="自己起一个id名" class="全限定类名">
<properties name="属性名" value="此属性的值" />
<properties name="属性名" value="此属性的值" />
</bean>
引用数据类型的set注入:
<bean id="school02" class="com.yixuexi.test02.School">
<property name="name" value="北京市第一小学"></property>
<property name="id" value="2222"></property>
</bean>
<bean id="student02" class="com.yixuexi.test02.Student">
<property name="id" value="999"></property>
<property name="name" value="张三"></property>
<!-- value改ref 写school的id -->
<property name="school" ref="school02"></property>
</bean>
把value换成ref,然后后面跟 对应类型对象的id(也就是bean的id)
1. set注入注意事项:
• 类中必须要有set方法
• 不管是什么值 在value="都必须在引号内"
• 比如student类中有一个 setAddress()方法,但是并没有这个address属性,那么在配置文件中这么写<properties name="address" value="北京市"> 他也会执行,并不会报错,spring找的就是类中的方法,他根据address判断出setAddress() 然后根据他的判断,他去找setAddress()这个方法,然后执行,不管有没有address属性。(只要有set方法 他就能用)
4.3 构造注入
spring调用类的有参数构造方法,在创建对象的同时,在构造方法中给属性赋值
使用 标签 :一个constructor-arg标签表示构造方法中的一个参数
• name:构造方法的形参名(切记 这是是形参名,一般的形参名都和属性名一致)
• index:构造方法参数的位置,参数从左往右 , 0 1 2 3
• value:简单类型的使用value
• ref:构造方法中的形参类型是引用类型的 放引用数据类型的id名
<!--通过构造方式注入来给对象属性赋值-->
<bean id="student03" class="com.yixuexi.test03.Student">
<constructor-arg name="id" value="10"></constructor-arg>
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="school" ref="school02"></constructor-arg>
</bean>
4.4 在配置文件中也支持${}写法
1. 在类路径下添加一个properties的配置文件
2. 然后在里面写好值 key=value
3. 然后在xml文件中写
<context:property-placeholder location="classpath:bean.properties"/>
4. 然后在对象value的地方进行 ${}
5. 自动注入
5.1 引用类型的自动注入
• 引用类型的自动注入:spring框架根据某些规则可以给引用类型赋值
• 只针对引用类型的赋值,简单类型做不了
1. byName
• byName: (按名称注入) java类中引用类型的属性名和spring容器中(配置文件中)<bean>的id一样
• 并且数据类型是一致的,这样的容器中的bean spring能够赋值给引用类型
<bean id="school" class="com.yixuexi.test.School">
<property name="id" value="666"></property>
<property name="name" value="北京市第一中学"></property>
</bean>
<bean id="student01" class="com.yixuexi.test.Student" autowire="byName">
<property name="name" value="张三"></property>
<property name="id" value="999"></property>
</bean>
设置 autowire=”byName”
并且 在student这个类中的school属性名 和 上面这个school bean的id一致 才行
2. byType
byType:(按类型注入,了解即可) java类中引用类型的数据类型和spring容器中(配置文件中)
同源:
1. java类中的引用类型的数据类型和bean的class值是一样的
2. java类中引用类型的数据类型和bean是class的值父子类关系的
3. java类中引用类型的数据类型和bean的class的值是接口或者实现类关系的
设置 autowire=”byType”
• 注意:在byType中,在xml配置文件中声明bean 只能有一个符合条件的,多余一个是错误的
• 下图表示的是byType注入,其中两个类都在同一个包下,所以符合同源的第一条,所以可以自动注入成功
6. 使用使用多个配置文件的优势
1. 分担了一个文件的大小
2. 避免多人编写带来的冲突
• 多文件的分配方式
• 按功能模块分类,一个模块一个配置文件(学生成绩,学生选课)
• 按类的功能,数据库相关的配置一个配置文件,事务的功能一个配置文件
6.1 包含关系的配置文件
• 有三个配置文件,分别是spring-student.xml ,spring-school.xml,
• 还有一个主配置文件spring-total.xml
• 主配置文件一般都不定义对象,而是用来包含其他配置文件
语法:
<import resource="其他配置文件的路径"/>
关键字 "classpath:" 表示类路径的(class文件所在的目录)
在spring中如果需要指定别的文件的话 需要classpath:
【idea中指的是 tagert目录下的路径】
<import resource="classpath:spring-student.xml"/>
<import resource="classpath:spring-school.xml"/>
• 当在spring-total.xml文件中集成了这些文件之后,当读取这一个文件的时候这里面的被继承文件也都读取到了
• 并且也可以支持引用类型的注入
• Spring-student.xml里面需要一个school类型的属性而spring-school.xml里面有,这样的话,就算隔着一个文件也可以引用注入
• Spring-total.xml叫包含关系的配置文件
6.2 统配符方式
<import resource="classpath:spring-*.xml"/>
这样的话 最终的包含配置文件不能叫spring-total.xml 改名为total.xml
• 主配置文件不能包含在通配符的范围内
• 最好是放在同一级目录中