我们首先要学习的就是 Spring Framework ,
Spring Framework是Spring生态圈中最基础的项目,是其他项目的根基
spring核心概念:
IOC 控制反转,对象的创建控制权交给spring核心容器
DI 依赖注入,实现功能,属性的值由spring容器主动提供
目标:
-
充分解耦
-
使用IoC容器管理bean(IOC)
-
在IOC容器内将有依赖关系的bean进行关系绑定(DI)
-
-
最终效果
-
使用对象时不仅可以直接从IoC容器中获取,并且获取到的bean已经绑定了所有的依赖关系
-
我们先来体验一下spring,下面编写一个入门程序
【第一步】maven导入Spring坐标
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.2.10.RELEASE</version>
</dependency>
【第二步】定义Spring管理的类(接口)
public interface BookDao {
public void save();
}
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
}
public interface BookService {
public void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
}
【第三步】创建Spring配置文件,配置对应类作为Spring管理的bean对象
-
定义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.itheima.service.impl.BookServiceImpl"></bean>
</beans>
==注意事项:bean定义时id属性在同一个上下文中(IOC容器中)不能重复==
【第四步】初始化IOC容器(Spring核心容器/Spring容器),通过容器获取Bean对象
public class App {
public static void main(String[] args) {
//1.创建IoC容器对象,加载spring核心配置文件
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
//2 从IOC容器中获取Bean对象(BookService对象)
BookService bookService= (BookService)ctx.getBean("bookService");
//3 调用Bean对象(BookService对象)的方法
bookService.save();
}
}
运行结果:
好了,入门程序已经完成,我们接下来学习DI入门
通过上面代码我们发现在BookServiceImpl里面 我们new了一个Dao,这样的话还是增加了耦合性
那么怎么解决呢:
【第一步】删除使用new的形式创建对象的代码
【第二步】提供依赖对象对应的setter方法
【第三步】配置service与dao之间的关系
<?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="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
<!--配置server与dao的关系
property标签:表示配置当前bean的属性
name属性:表示配置哪一个具体的属性
ref属性:表示参照哪一个bean
-->
<property name="bookDao" ref="bookDao"/>
</bean>
</beans>
下面我们来学习Bean的基础配置(重点)
功能:定义spring核心容器管理的对象
属性列表: id:Bean的id,使用容器可以通过id值获取对应的Bean,在一个容器中id值唯一
class:bean的类型,配置的bean全路径类名
Bean还可以配置别名:可以定义多个,使用逗号,空格, 分号,()分隔 (了解)
Bean的作用范围配置(重点):
名称:scope
功能,定义bean的作用范围,
singleton :单例(默认的,不写也是单例)
prototype:非单例
我们暂时只需要了解这两个就可以了,
扩展:scope的取值不仅仅只有singleton和prototype,还有request、session、application、 websocket ,表示创建出的对象放置在web容器(tomcat)对应的位置。比如:request表示保存到request域中。
最后说明一下:在我们的实际开发当中,绝大部分的Bean是单例的,也就是说绝大部分Bean不需要配置scope属性。
Bean的实例化:
实例化Bean的三种方式
1:构造方法方式(重点)
BookDaoImpl实现类:
public class BookDaoImpl implements BookDao {
public BookDaoImpl() {
System.out.println("book dao constructor is running ....");
}
public void save() {
System.out.println("book dao save ...");
}
}
applicationContext.xml配置:
<!--方式一:构造方法实例化bean-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
运行结果:
2:静态工厂方式
OrderDao接口和OrderDaoImpl实现类
public interface OrderDao {
public void save();
}
public class OrderDaoImpl implements OrderDao {
public void save() {
System.out.println("order dao save ...");
}
}
OrderDaoFatory工厂类
//静态工厂创建对象
public class OrderDaoFactory {
public static OrderDao getOrderDao(){
System.out.println("factory setup....");
return new OrderDaoImpl();
}
}
applicationContext.xml配置
<!--方式二:使用静态工厂实例化bean-->
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
3:实例工厂方式
UserDao接口和UserDaoImpl实现类
public interface UserDao {
public void save();
}
public class UserDaoImpl implements UserDao {
public void save() {
System.out.println("user dao save ...");
}
}
UserDaoFactory工厂类
//实例工厂创建对象
public class UserDaoFactory {
public UserDao getUserDao(){
return new UserDaoImpl();
}
}
applicationContext.xml配置
<!--方式三:使用实例工厂实例化bean-->
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/>
<bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
3.1:
实现FactoryBean<T>方式(扩展,了解)
-
定义UserDaoFactoryBean实现FactoryBean<UserDao>
-
UserDaoFactoryBean中实例化什么类型的对象泛型就是该类型。
-
//FactoryBean创建对象 public class UserDaoFactoryBean implements FactoryBean<UserDao> { //代替原始实例工厂中创建对象的方法 public UserDao getObject() throws Exception { return new UserDaoImpl(); } public Class<?> getObjectType() { return UserDao.class; } }
applicationContext.xml配置
-
<!--方式四:使用FactoryBean实例化bean--> <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
Bean的生命周期:
-
生命周期:从创建到消亡的完整过程
-
bean生命周期:bean从创建到销毁的整体过程
-
bean生命周期控制:在bean创建后到销毁前做一些事情
我们来代码实现一下,随便定义两个方法,然后配置文件配一下
public class BookDaoImpl implements BookDao {
public void save() {
System.out.println("book dao save ...");
}
//表示bean初始化对应的操作
public void init(){
System.out.println("init...");
}
//表示bean销毁前对应的操作
public void destory(){
System.out.println("destory...");
}
}
applicationContext.xml配置
<!--init-method:设置bean初始化生命周期回调函数,此处填写init方法名-->
<!--destroy-method:设置bean销毁生命周期回调函数,仅适用于单例对象,此处填写destory方法名-->
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/>
测试类
public class AppForLifeCycle {
public static void main( String[] args ) {
//此处需要使用实现类类型,接口类型没有close方法
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//关闭容器,执行销毁的方法
ctx.close();
}
}
其实spring已经给我们提供了一个规则
那就是实现InitializingBean, DisposableBean接口
public class BookServiceImpl implements BookService, InitializingBean, DisposableBean {
private BookDao bookDao;
public void setBookDao(BookDao bookDao) {
System.out.println("set .....");
this.bookDao = bookDao;
}
public void save() {
System.out.println("book service save ...");
bookDao.save();
}
public void destroy() throws Exception {
System.out.println("service destroy");
}
public void afterPropertiesSet() throws Exception {
System.out.println("service init");
}
}
Bean的销毁时机:
-
容器关闭前触发bean的销毁
-
关闭容器方式:
-
手工关闭容器
ConfigurableApplicationContext
接口close()
操作 -
注册关闭钩子,在虚拟机退出前先关闭容器再退出虚拟机
ConfigurableApplicationContext
接口registerShutdownHook()
操作
-
public class AppForLifeCycle {
public static void main( String[] args ) {
//此处需要使用实现类类型,接口类型没有close方法
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
//注册关闭钩子函数,在虚拟机退出之前回调此函数,关闭容器
ctx.registerShutdownHook();
//关闭容器
//ctx.close();
}
}
关于Bean的知识我们就讲完了,下面开始学习DI
1:依赖注入的方式(重点)
1.1 依赖注入的两种方式
-
setter注入
-
简单类型
-
==引用类型(很常用)==
-
构造器注入
-
简单类型
-
引用类型
setter方式注入使用什么子标签?
首先我们需要在bean中提供引用类型属性并且提供可访问的set方法
引用类型:
基本类型+字符串:
构造器注入:
引用类型:
在bean中定义引用类型的属性并提供可以访问的构造方法
基本类型+字符串:
在bean中定义引用类型的属性并提供可以访问的构造方法
参数适配【了解】
1.4 依赖注入方式选择
-
强制依赖使用构造器进行,使用setter注入有概率不进行注入导致null对象出现
-
可选依赖使用setter注入进行,灵活性强
-
Spring框架倡导使用构造器,第三方框架内部大多数采用构造器注入的形式进行数据初始化,相对严谨
-
如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入
-
实际开发过程中还要根据实际情况分析,如果受控对象没有提供setter方法就必须使用构造器注入
-
==自己开发的模块推荐使用setter注入==
有没感觉配过来配过去的好麻烦呢,其实啊,spring给我们提供了自动装配
自动装配:IOC容器根据bean所依赖的资源在容器中自动查找并注入到bean中的过程称为自动装配
我们在配置中使用bean标签autowire属性设置自动装配的类型
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
依赖自动装配特征
-
自动装配用于引用类型依赖注入,不能对简单类型进行操作
-
使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
-
使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
-
自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效
集合注入:
1:注入数组类型
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
2:注入List类型
<property name="list">
<list>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>chuanzhihui</value>
</list>
</property>
3:注入Set类型
<property name="set">
<set>
<value>itcast</value>
<value>itheima</value>
<value>boxuegu</value>
<value>boxuegu</value>
</set>
</property>
4:注入Map类型
<property name="map">
<map>
<entry key="country" value="china"/>
<entry key="province" value="henan"/>
<entry key="city" value="kaifeng"/>
</map>
</property>
5:注入Properties类型数据
<property name="properties">
<props>
<prop key="country">china</prop>
<prop key="province">henan</prop>
<prop key="city">kaifeng</prop>
</props>
</property>
说明:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签
好了,我们第一天的学习就到这里,下面总结一下我们需要掌握的:
1.IOC概念DI概念
2.实现spring容器创建管理bean的操作
3.依赖注入:setter注入,构造器注入
4.自动注入
5.bean 的作用范围 scope 单例singleton,prototype