1.Spring简介
1.1.什么是Spring
- Spring是一个轻量级的框架,能够简化企业级应用开发,减少代码量。
Spring的核心框架是AOP(面向切面)与IOC(控制反转),IOC说白了就是跟容器要对象,DI(依赖注入)就是给属性赋值,AOP就是根据动态代理分为切面,切入点和通知。Spring还提供对JDBC的轻量级封装,还提供声明事务。Spring还根据MVC设计模式开发出SpringMVC框架。
(1)Spring框架目标
- 使用声明式事务,向EJB挑战
- 框架整合,像胶水一样整合多个框架.
(2)什么是JavaEE
- JAVAEE:Java Enterprise Edition(java企业级版本)是Sun制定的一套java开发规范
- 是由一系列的JSR组成
(3)什么是JSR
- Java Specification Requests Java规范提案
- (4)JAVAEE容器和组件
容器
Applet Container
Web Container
Application Client Container
EJB Container
组件
Applet
JSP Servlet
Java Bean
EJB JavaBean
(5)Spring特点
- Ioc:解耦使用IoC机制避免硬编码造成程序耦合
- AOP:Aspect Orentied Programing 面向切面的编程
- 声明式事务管理
- 对JDBC进行轻量级封装,更加灵活的操作数据库
- Spring提供MVC模式支持:SpringMVC
- 提供文件上传,定时器常用工具类
- 对其他优秀框架的支持(集成其他框架)
1.2.Spring框架结构
(1)Spring的核心功能
- IoC容器
- Bean生命周期管理
- SpEL
- AOP容器
- 注解体系
- 数据验证
(2)Spring的好处
- 方便解耦
- AOP编程支持
- 声明式事务的支持
- 方便程序的测试
- 方便集成各种优秀框架
- 降低JavaEE API的使用难度
2.Spring资源管理
2.1.Spring资源管理简介
(1)Spring资源管理的特点
- 隐藏底层的实现
- 新增资源存在判断、资源操作权限相关的功能
- 支持通配符获取资源
(2)Spring管理哪些资源
- UrlResource
- ClassPathResource
- FileSystemResource
- ServletContextResource
- InputStreamResource
- ByteArrayResource
(3)资源协议与路径
- classpath:从当前jvm的classpath根路径开始获取资源
- file:从操作系统的路径获取资源
- http(s):从互联网获取资源
- 无标记:根据应用上下文获取资源
(4)Spring使用什么访问底层资源
Spring使用Resource接口访问底层资源
(5)Spring使用什么接口加载资源
Spring使用ResourceLoader接口加载资源
IOC容器实现了ResourceLoader接口,可以随时使用它的**getResource(location)**加载资源
2.2.Spring资源管理案例
- 创建maven工程,写HelloService
public class HelloService { public void sayHello(String name){ System.out.println(name+":你好!"); } }
- 引入spring-framework依赖
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.0.15.RELEASE</version> </dependency> </dependencies>
- 在main/resources下创建applicationContext.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"> <bean id="helloService" class="com.tjetc.service.HelloService"> </bean> </beans>
- 编写测试类
public class Test { public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloService helloService = (HelloService) context.getBean("helloService"); helloService.sayHello("李祥"); } }
运行结果
李祥:你好!
3.Spring容器创建
3.1.IOC容器创建的三种方法
- 使用ClassPathXmlApplicationContext创建IOC容器
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
- 使用FileSystemXmlApplicationContext创建容器
此时,applicationContext.xml 的路径要写磁盘的物理路径
FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("D:\\ideaworkspaces\\0919-spring\\01-spring\\src\\main\\resources\\applicationContext.xml");
- 使用XmlWebApplicationContext创建容器
使用XmlWebApplicationContext时要导入Tomcat,和spring-webmvc依赖
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-web</artifactId> <version>5.2.8.RELEASE</version> </dependency>
XmlWebApplicationContext context = new XmlWebApplicationContext(); //设置配置文件位置 context.setConfigLocation("classpath:applicationContext.xml"); //调用refresh()方法 context.refresh(); HelloService helloService = context.getBean("helloService",HelloService.class); helloService.sayHello("李祥");
3.2.从IOC容器getBean的三种方法
- 容器对象.getBean(“bean的id”),精确定位,需要强制转换
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloService helloService = (HelloService) context.getBean("helloService"); helloService.sayHello("李祥");
- 容器对象.getBean(“bean的id”,bean.class),精确定位,不需要强制转换
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloService helloService = context.getBean("helloService",HelloService.class); helloService.sayHello("李祥");
- 容器对象.getBean(bean.class),不需要强制转换
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloService helloService = context.getBean(HelloService.class); helloService.sayHello("李祥");
3.3.Spring实例化bean的3种方法
- 使用默认的构造方法创建bean对象
容器实例化会调用bean的默认无参数的构造方法,代码请看入门案例
- 静态工厂方法创建bean对象
- 创建工厂类HelloServiceFactory
public class HelloServiceFactory { public static HelloService helloServiceFactory(){ //注意是静态方法 System.out.println("helloServiceFactory"); return new HelloService(); } }
- applicationContext.xml文件编写
<bean id="helloServiceFactory" class="com.tjetc.factory.HelloServiceFactory" factory-method="helloServiceFactory"> </bean>
- 测试代码
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloService helloService = context.getBean(HelloService.class); helloService.sayHello("李祥");
- 实例工程方法创建bean
- 创建工厂类HelloServiceFactory
public class HelloServiceFactory { public HelloService helloServiceFactory(){ //注意是非静态方法 System.out.println("helloServiceFactory"); return new HelloService(); } }
- applicationContext.xml文件
<bean id="helloServiceFactory" class="com.tjetc.factory.HelloServiceFactory"> </bean> <bean id="helloService" factory-bean="helloServiceFactory" factory-method="helloServiceFactory"> </bean>
- 测试代码
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); HelloService helloService = context.getBean(HelloService.class); helloService.sayHello("李祥");
4.SpringIOC依赖注入
4.1.SpringIOC依赖注入简介
(1)SpringIOC的特点
- Spring是轻量级容器+组件的管理模式
- (2)什么是控制反转
- 创建对象的权利由应程序创建改为由容器创建,控制权的转移称为控制反转.
(3)什么是依赖注入
- 把容器创建好的依赖对象注入进来的过程称为依赖注入.
- (4)依赖注入的目标
- 提升组件重用的概率
- 为系统搭建一个灵活、可扩展的平台
(5)Spring Framework的 IoC 容器操作基于两个包
org.springframework.beans 和 org.springframework.context
一个业务系统,由很多bean对象组成,bean之间存在调用关系,那么这些bean对象是如何协同工作的呢? 对象之间的调用,存在依赖关系,依赖对象的注入,称为依赖注入.
4.2.SpringIOC构造器注入
构造器注入bean子节点constructor-arg节点.可以使用constructor-arg节点属性index,name,type
基本类型注入:使用value
引用类型注入:使用ref
- index构造方法参数的索引
准备一个实体类
public class Student { private String name; private int age; public Student(String name, int age) { this.name = name; this.age = age; } @Override public String toString() { return "Student{" + "name='" + name + '\'' + ", age=" + age + '}'; } }
applicationContext.xml中配置
<bean id="student" class = "com.tjetc.domain.Student"> <constructor-arg index="0" value="张三"></constructor-arg> <!--构造器注入用constructor-arg--> <constructor-arg index="1" value="18"></constructor-arg> </bean>
测试代码
public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean(Student.class); System.out.println(student); }
- name构造方法的名称
实体类和测似代码不动,只要改变配置文件即可
<bean id="student" class = "com.tjetc.domain.Student"> <constructor-arg name="name" value="张三"></constructor-arg> <constructor-arg name="age" value="18"></constructor-arg> </bean>
- type构造方法参数的类型
实体类和测似代码不动,只要改变配置文件即可
<bean id="student" class = "com.tjetc.domain.Student"> <constructor-arg type="java.lang.String" value="张三"></constructor-arg> <constructor-arg type="int" value="16"></constructor-arg> </bean>
注意如果是引用类型的bean用ref=“bean的id”
4.3.SpringIOC属性set方法注入
name是setXxx() 方法后单词的首字母变小写后的单词,不是属性名。
value代表的是值
ref代表的是引用类型的bean的id 的值
实体类中必须要有setter 、getter方法,以及无参构造
public Student() { } public Student(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; }
applicationContext.xml配置文件
<bean id="student" class = "com.tjetc.domain.Student"> <property name="name" value="张三"></property> <property name="age" value="13"></property> </bean>
测试代码
public static void main(String[] args) { ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); Student student = context.getBean(Student.class); System.out.println(student); }
set注入与构造器注入的对比
Set注入模式代码更加简洁
构造器注入对依赖关系的表达更加清楚
Set注入可以避免循环依赖问题
4.4.SpringIOC集合属性的注入
- list、数组基本类型语法
<property name="hobbies"> <list> <value>吃</value> <value>喝</value> <value>玩</value> <value>乐</value> </list> </property>
- list、数组引用类型语法
<property name="books"> <list> <ref bean="book1"/> <ref bean="book2"/> <ref bean="book3"/> </list> </property>
- set基本数据类型语法
<property name="hobbies"> <set> <value>吃</value> <value>喝</value> <value>玩</value> <value>乐</value> <value>读书</value> </set> </property>
- set引用数据类型语法
<property name="books"> <set> <ref bean="book1"/> <ref bean="book2"/> <ref bean="book3"/> </set> </property>
- map基本类型语法
<property name="hobbies"> <map> <entry key="chi" value="吃"></entry> <entry key="he" value="喝"></entry> <entry key="wan" value="完"></entry> </map> </property>
- map引用类型语法
<property name="books"> <map> <entry key="xi" value-ref="book1"></entry> <entry key="dong" value-ref="book2"></entry> <entry key="nan" value-ref="book3"></entry> </map> </property>
<property name="properties"> <props> <prop key="pk1">pv1</prop> <prop key="pk2">pv2</prop> <prop key="pk3">pv3</prop> <prop key="pk4">pv4</prop> </props> </property>
4.5.SpringIOC空间命名
(1)p空间命名
先要引入p空间命名
xmlns:p="http://www.springframework.org/schema/p"
基本数据类型
p:属性=值
<bean id="student" class = "com.tjetc.domain.Student" p:name="张三" p:age="12"> </bean>
引用数据类型
p:属性-ref=另一个bean的id的值
<bean id="book" class="com.tjetc.domain.Book" p:name="西游记" p:price="30"> </bean> <bean id="student" class="com.tjetc.domain.Student" p:name="张三" p:book-ref="book"> </bean>
(2)c空间命名
先要引入c空间命名
xmlns:c="http://www.springframework.org/schema/c"
基本数据类型
c:构造方法参数名=值
<!--用属性名称注入--> <bean id="student" class = "com.tjetc.domain.Student" c:name="张三" c:age="12"> </bean>
<!--用索引下标注入--> <bean id="student" class = "com.tjetc.domain.Student" c:_0="张三" c:_1="12"> </bean>
引用数据类型
c:构造方法参数名-ref=另一个bean的id的值
<bean id="book" class="com.tjetc.domain.Book" p:name="西游记" p:price="30"> </bean> <bean id="student" class="com.tjetc.domain.Student" c:name="李四" c:book-ref="book"> </bean>
4.6.depends-on属性
B中没有A,在applicationContext.xml中配置depends-on=“a”,则先实例化A,再实例化B,销毁是先销毁B,再销毁A
依赖对象先创建后销毁.
public class Student { private String name; public Student() { System.out.println("Student()"); } public void init(){ System.out.println("Student.init()"); } public void destroy(){ System.out.println("Student.destroy()"); } }
public class MyClass { public String cname; public MyClass() { System.out.println("MyClass()"); } public void init(){ System.out.println("MyClass.init()"); } public void destroy(){ System.out.println("MyClass.destroy()"); } }
applicationContext.xml文件
<bean id="student" class="com.tjetc.domain.Student" depends-on="myClass" init-method="init" destroy-method="destroy"> </bean> <bean id="myClass" class="com.tjetc.domain.MyClass" init-method="init" destroy-method="destroy"> </bean>
测试代码
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml"); context.close();
运行结果
MyClass() MyClass.init() Student() Student.init()
Student.destroy() MyClass.destroy()
4.7.延迟加载lazy-init
ApplicationContext的默认行为就是在创建IOC容器时将所有singleton 的bean提前进行实例化。
系统默认配置是lazy-init=“false”
当配置lazy-init="true"后,当第一次调用bean对象时,才进行实例
- lazy-init="true"创建IOC容器时没有实例化bean,当第一次调用context.getBean(C.class)才进行实例化bean
<bean id="c" class="com.tjetc.domain.C" lazy-init="true"></bean>
- lazy-init="true"只对当前的bean有效,对其他的bean不起作用
<bean id="c" class="com.tjetc.domain.C" lazy-init="true"></bean> <bean id="d" class="com.tjetc.domain.D"></bean>
- beans节点设置 default-lazy-init=“true” ,让所有的bean都设置成懒加载.
<beans default-lazy-init="true" xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd "> <bean id="c" class="com.tjetc.domain.C"></bean> <bean id="d" class="com.tjetc.domain.D"></bean> </beans>
- default-lazy-init=“true” 所有bean懒加载的前提下,设置某个bean不懒加载 bean设置lazy-init=“false”
<bean id="d" class="com.tjetc.domain.D" lazy-init="false"></bean>