Spring技术是JavaEE开发必备技能,企业开发技术选型命中率>90%。
专业角度:
简化开发,降低企业级开发的复杂性。
框架整合,高效整合其他技术,提高企业级应用开发与运行效率。
Spring Framework系统架构
Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基。

代码书写现状:耦合度偏高
解决方案:使用对象时,在程序中不要主动使用new产生对象,转换为由外部提供对象
IoC(Inversion of Control)控制反转:对象的创建控制权由程序转移到外部,这种思想称为控制反转
IoC(Inversion of Control)控制反转
使用对象时,由主动new产生对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
Spring技术对IoC思想进行了实现
Spring提供了一个容器,称为IoC容器,用来充当IoC思想中的“外部”
IoC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
DI(Dependency Injection)依赖注入
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入

目标:充分解耦
使用IoC容器管理bean(IoC)
在IoC容器内将有依赖关系的bean进行关系绑定(DI)
最终效果:使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
1、在pom.xml中导入Spring坐标
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> </dependencies>
2、定义Spring管理的类(接口)
BookDao接口和BookDaoImpl实现类
1 public interface BookDao { 2 public void save(); 3 } 4 5 public class BookDaoImpl implements BookDao { 6 public void save() { 7 System.out.println("book dao save ..."); 8 } 9 }
BookService接口和BookServiceImpl实现类
1 public interface BookService { 2 public void save(); 3 } 4 5 public class BookServiceImpl implements BookService { 6 private BookDao bookDao = new BookDaoImpl(); 7 public void save() { 8 System.out.println("book service save ..."); 9 bookDao.save(); 10 } 11 }
3、创建Spring配置文件,配置对应类作为Spring管理的bean对象
在resources下定义applicationContext.xml配置文件并配置BookServiceImpl
<?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标签:表示配置bean id属性:表示给bean起名字 class属性:表示给bean定义类型 --> <bean id="bookService" class="com.test.service.impl.BookServiceImpl"></bean> </beans>
注:bean定义时id属性在同一个上下文中(IOC容器中)不能重复
4、初始化IOC容器(Spring核心容器/Spring容器),通过容器获取Bean对象
1 public class App { 2 public static void main(String[] args) { 3 //1.创建IoC容器对象,加载spring核心配置文件 4 ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 5 //2 从IOC容器中获取Bean对象(BookService对象) 6 BookService bookService= (BookService)ctx.getBean("bookService"); 7 //3 调用Bean对象(BookService对象)的方法 8 bookService.save(); //book service save ... book dao save ... 9 } 10 }
DI入门案例
1、删除使用new的形式创建对象的代码
1 public class BookServiceImpl implements BookService { 2 private BookDao bookDao; //【第一步】删除使用new的形式创建对象的代码 3 public void save() { 4 System.out.println("book service save ..."); 5 bookDao.save(); 6 } 7 }
2、提供依赖对象对应的setter方法
1 public class BookServiceImpl implements BookService { 2 private BookDao bookDao; 3 public void save() { 4 System.out.println("book service save ..."); 5 bookDao.save(); 6 } 7 //【第二步】提供依赖对象对应的setter方法 8 public void setBookDao(BookDao bookDao) { 9 this.bookDao = bookDao; 10 } 11 }
3、配置service与dao之间的关系
在applicationContext.xml中配置
1 <?xml version="1.0" encoding="UTF-8"?> 2 <beans xmlns="http://www.springframework.org/schema/beans" 3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 4 xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"> 5 <!-- 6 bean标签:表示配置bean 7 id属性:表示给bean起名字 8 class属性:表示给bean定义类型 9 --> 10 <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/> 11 12 <bean id="bookService" class="com.test.service.impl.BookServiceImpl"> 13 <!--配置server与dao的关系 14 property标签:表示配置当前bean的属性 15 name属性:表示配置哪一个具体的属性 16 ref属性:表示参照哪一个bean 17 --> 18 <property name="bookDao" ref="bookDao"/> 19 </bean> 20 </beans>

bean
bean配置
bean基础配置(重点)


注:获取bean无论是通过id还是name获取,如果无法获取到,将抛出异常NoSuchBeanDefinitionException
NoSuchBeanDefinitionException: No bean named 'bookServiceImpl' available


扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。
注:在我们的实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
bean实例化
bean本质上就是对象,创建bean使用构造方法完成
1 public class BookDaoImpl implements BookDao { 2 public BookDaoImpl() { 3 System.out.println("book dao constructor is running ...."); 4 } 5 public void save() { 6 System.out.println("book dao save ..."); 7 } 8 }
applicationContext.xml配置
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>
无参构造方法如果不存在,将抛出异常BeanCreationException
实例化bean的三种方式——静态工厂(了解)
OrderDao接口和OrderDaoImpl实现类
1 public interface OrderDao { 2 public void save(); 3 } 4 public class OrderDaoImpl implements OrderDao { 5 public void save() { 6 System.out.println("order dao save ..."); 7 } 8 }
OrderDaoFatory工厂类
1 //静态工厂创建对象 2 public class OrderDaoFactory { 3 public static OrderDao getOrderDao(){ 4 System.out.println("factory setup...."); 5 return new OrderDaoImpl(); 6 } 7 }
applicationContext.xml配置
<bean id="orderDao" class="com.test.factory.OrderDaoFactory" factory-method="getOrderDao"/>

实例化bean的三种方式——实例工厂(了解)
UserDao接口和UserDaoImpl实现类
1 public interface UserDao { 2 public void save(); 3 } 4 public class UserDaoImpl implements UserDao { 5 public void save() { 6 System.out.println("user dao save ..."); 7 } 8 }
UserDaoFactory工厂类
1 //实例工厂创建对象 2 public class UserDaoFactory { 3 public UserDao getUserDao(){ 4 return new UserDaoImpl(); 5 } 6 }
applicationContext.xml配置
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>

实例化bean的第四种方式————(
定义UserDaoFactoryBean实现FactoryBean<UserDao>
UserDaoFactoryBean中实例化什么类型的对象泛型就是该类型。
1 //FactoryBean创建对象 2 public class UserDaoFactoryBean implements FactoryBean<UserDao> { 3 //代替原始实例工厂中创建对象的方法 4 public UserDao getObject() throws Exception { 5 return new UserDaoImpl(); 6 } 7 8 public Class<?> getObjectType() { 9 return UserDao.class; 10 } 11 }
applicationContext.xml配置
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
生命周期:从创建到消亡的完整过程。
bean生命周期:bean从创建到销毁的整体过程。
bean生命周期控制:在bean创建后到销毁前做一些事情。
1 public class BookDaoImpl implements BookDao { 2 public void save() { 3 System.out.println("book dao save ..."); 4 } 5 //表示bean初始化对应的操作 6 public void init(){ 7 System.out.println("init..."); 8 } 9 //表示bean销毁前对应的操作 10 public void destory(){ 11 System.out.println("destory..."); 12 } 13 }
applicationContext.xml配置
<!--init-method:设置bean初始化生命周期回调函数,此处填写init方法名--> <!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,此处填写destory方法名--> <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
测试类
1 public class AppForLifeCycle { 2 public static void main( String[] args ) { 3 //此处需要使用实现类类型,接口类型没有close方法 4 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 5 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 6 bookDao.save(); 7 //关闭容器,执行销毁的方法 8 ctx.close(); 9 } 10 }
2、实现InitializingBean, DisposableBean接口
1 public class BookServiceImpl implements BookService, InitializingBean, DisposableBean { 2 private BookDao bookDao; 3 public void setBookDao(BookDao bookDao) { 4 System.out.println("set ....."); 5 this.bookDao = bookDao; 6 } 7 public void save() { 8 System.out.println("book service save ..."); 9 bookDao.save(); 10 } 11 public void destroy() throws Exception { 12 System.out.println("service destroy"); 13 } 14 public void afterPropertiesSet() throws Exception { 15 System.out.println("service init"); 16 } 17 }
初始化容器
1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入(set操作)
4.执行bean初始化方法
使用bean
1.执行业务操作
关闭/销毁容器
1.执行bean销毁方法
容器关闭前触发bean的销毁。
关闭容器方式:
手工关闭容器;
ConfigurableApplicationContext接口close()操作
注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机。
ConfigurableApplicationContext接口registerShutdownHook()操作
1 public class AppForLifeCycle { 2 public static void main( String[] args ) { 3 //此处需要使用实现类类型,接口类型没有close方法 4 ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); 5 6 BookDao bookDao = (BookDao) ctx.getBean("bookDao"); 7 bookDao.save(); 8 //注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器 9 ctx.registerShutdownHook(); 10 //关闭容器 11 //ctx.close(); 12 } 13 }
依赖注入的两种方式:
1、setter注入
简单类型
引用类型(很常用)
2、构造器注入
简单类型
引用类型
1.1 setter注入——引用类型
在bean中定义引用类型属性并提供可访问的set方法
1 public class BookServiceImpl implements BookService{ 2 private BookDao bookDao; 3 public void setBookDao(BookDao bookDao) { 4 this.bookDao = bookDao; 5 } 6 }
配置中使用property标签ref属性注入引用类型对象
<bean id="bookService" class="com.test.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>

1.2 setter注入——简单类型
在bean中定义简单类型属性并提供可访问的set方法
1 public class BookDaoImpl implements BookDao { 2 private int connectionNumber; 3 public void setConnectionNumber(int connectionNumber) { 4 this.connectionNumber = connectionNumber; 5 } 6 }
配置中使用property标签value属性注入简单类型数据
1 <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> 2 <property name="connectionNumber" value="10"/> 3 </bean>

2.1 构造器注入——引用类型
在bean中定义引用类型属性并提供可访问的构造方法
1 public class BookServiceImpl implements BookService{ 2 private BookDao bookDao; 3 public BookServiceImpl(BookDao bookDao) { 4 this.bookDao = bookDao; 5 } 6 }
配置中使用constructor-arg标签ref属性注入引用类型对象
<bean id="bookService" class="com.test.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="bookDao"/> </bean> <bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/>

2.2 构造器注入——简单类型
在bean中定义简单类型属性并提供可访问的构造方法
1 public class BookDaoImpl implements BookDao { 2 private int connectionNumber; 3 public void BookDaoImpl(int connectionNumber) { 4 this.connectionNumber = connectionNumber; 5 } 6 }
配置中使用constructor-arg标签value属性注入简单类型数据
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> <constructor-arg name="connectionNumber" value="10"/> </bean>

2.3 构造器注入——参数适配(了解)
配置中使用constructor-arg标签type属性设置按形参类型注入
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean>
配置中使用constructor-arg标签index属性设置按形参位置注入
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"> <constructor-arg index="0" value="10"/> <constructor-arg index="1" value="mysql"/> </bean>
依赖注入方式选择
1.强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
2.可选依赖使用setter注入进行,灵活性强
3.Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
4.如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
5.实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
6.自己开发的模块推荐使用setter注入
依赖自动装配(理解)
IoC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
自动装配方式:
按类型(常用)
按名称
按构造方法
不启用自动装配
配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.test.dao.impl.BookDaoImpl"/> <bean id="bookService" class="com.test.service.impl.BookServiceImpl" autowire="byType"/>
依赖自动装配特征:
1.自动装配用于引用类型依赖注入,不能对简单类型进行操作;
2.使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用;
3.使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用;
4.自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效。