Spring框架IOC容器和DI依赖注入
目录
- Spring框架IOC容器和DI依赖注入
-
- 介绍
- 入门案例
-
- pom.xml依赖引入
- BookDao
- BookDaoImpl
- BookService
- BookServiceImpl
- applicationContext.xml
- 测试类
- Bean实例化
-
- 静态工厂实例化
-
- OrderDao
- OrderDaoImpl
- OrderDaoFactory
- applicatoinContext.xml
- 测试类
- 实例工厂实例化
-
- UserDao
- UserDaoImpl
- UserDaoFactory
- applicationContext.xml
- 测试类
- 使用实例工厂实现FactoryBean接口实例化
-
- UserDaoFactoryBean
- applicationContext.xml
- 测试类
- Bean的生命周期
-
- BrandService
- BrandServiceImpl
- BrandDao
- BrandDaoImpl
- applicatonContext.xml
- 测试类
- 其他类型依赖注入
-
- applicationContext.xml
Spring框架IOC容器和DI依赖注入
介绍
IOC(Invertion Of Control):控制反转,使用对象时,由使用new创建对象转变为由外部提供对象,此过程中对象的创建控制权由程序转移到外部的思想称之为控制反转.
DI(Dependency Injection):依赖注入,在容器中建立bean与bean之间的关系的过程,称之为依赖注入
入门案例
pom.xml依赖引入
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.shifan</groupId><artifactId>spring-01-ioc-di-bean</artifactId><version>1.0-SNAPSHOT</version><properties><maven.compiler.source>11</maven.compiler.source><maven.compiler.target>11</maven.compiler.target></properties><dependencies><!--导入spring依赖,导入后才有spring类型的配置文件--><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>5.2.10.RELEASE</version></dependency><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.13.1</version></dependency></dependencies></project>
BookDao
public interface BookDao {void save();
}
BookDaoImpl
public class BookDaoImpl implements BookDao {@Overridepublic void save() {System.out.println("BookDao save...");}
}
BookService
public interface BookService {void save();
}
BookServiceImpl
public class BookServiceImpl implements BookService {private BookDao bookDao;//给spring容器注入提供set方法public void setBookDao(BookDao bookDao) {this.bookDao = bookDao;}@Overridepublic void save() {bookDao.save();}
}
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,将该类对象的创建交由Spring容器管理id为bean的唯一标识,不可重复class为bean的类型,该属性不能写接口全类名,因为接口无法创建对象name为bean的别名,ref属性可以使用其他bean的别名,别名可以有多个,用逗号,空格,分号隔开都行scope为bean的作用范围,默认是singleton单例,可设置为prototype非单例若是有状态的对象,即该对象有成员变量用于存储数据,则不适合交给容器管理,可能存在线程安全问题spring通过反射获取类中的无参构造创建对象--><bean id="bookDaoImpl" class="com.shifan.dao.impl.BookDaoImpl" name="bookDao"/><!--配置service和dao的关系使用property标签配置当前bean中的的属性name="bookDao"中`bookDao`的作用是让Spring的IOC容器在获取到名称后,将首字母大写,前面加set找对应的`setBookDao()`方法进行对象注入ref为参照的容器中的beanautowire="byType" 按照类型自动注入,要求容器中相同类型的bean唯一autowire="byName" 按照名称注入,要求容器中有指定名称的bean,因变量名与配置耦合,不推荐使用自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效--><bean id="bookServiceImpl" class="com.shifan.service.impl.BookServiceImpl" autowire="byType"><property name="bookDao" ref="bookDaoImpl"/></bean>
</beans>
测试类
//获取spring容器ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");@Testpublic void testGetBean(){//获取bean
/* BookDao bookDao = (BookDao) applicationContext.getBean("bookDaoImpl");bookDao.save();*/BookService bookServiceImpl = (BookService) applicationContext.getBean("bookServiceImpl");bookServiceImpl.save();}@Testpublic void testBeanAlias(){//根据别名获取beanBookDao bookDao = (BookDao) applicationContext.getBean("bookDao");bookDao.save();}
Bean实例化
静态工厂实例化
OrderDao
public interface OrderDao {void order();
}
OrderDaoImpl
public class OrderDaoImpl implements OrderDao {@Overridepublic void order() {System.out.println("ordering orders...");}
}
OrderDaoFactory
package com.shifan.factory;import com.shifan.dao.OrderDao;
import com.shifan.dao.impl.OrderDaoImpl;public class OrderDaoFactory {public static OrderDao getOrderDao(){System.out.println("order dao service options...");//模拟对象创建前的必要业务操作return new OrderDaoImpl();}
}
applicatoinContext.xml
<!--静态工厂实例化(了解)指定静态工厂类全类名及其创建对象的方法--><bean id="orderDao" class="com.shifan.factory.OrderDaoFactory" factory-method="getOrderDao"/>
测试类
@Test
public void testStaticFactory(){//获取通过静态工厂创建的对象OrderDao orderDao = (OrderDao) applicationContext.getBean("orderDao");orderDao.order();
}
实例工厂实例化
UserDao
public interface UserDao {void save();
}
UserDaoImpl
public class UserDaoImpl implements UserDao {@Overridepublic void save() {System.out.println("user dao save...");}
}
UserDaoFactory
public class UserDaoFactory {public UserDao getUserDao(){System.out.println("user dao service options...");//模拟对象创建前的必要业务操作return new UserDaoImpl();}
}
applicationContext.xml
<!--实例工厂实例化(了解)配置实例工厂bean配置实例工厂创建的对象的bean:指定工厂bean,工厂创建bean的方法--><bean id="userDaoFactory" class="com.shifan.factory.UserDaoFactory"/><bean id="userDao" factory-method="getUserDao" factory-bean="userDaoFactory"/>
测试类
@Testpublic void testInstanceFactory(){//获取通过实例工厂bean创建的对象UserDao userDao = (UserDao) applicationContext.getBean("userDao");userDao.save();}
使用实例工厂实现FactoryBean接口实例化
UserDaoFactoryBean
/* 使用FactoryBean简化实例工厂方式实例化bean* FactoryBean还有一个方法boolean isSingleton()* 用于设置是否为单例,不重写则默认返回true,表示是单例*/
public class UserDaoFactoryBean implements FactoryBean<UserDao> {/* 被重写后,在方法中进行对象的创建并返回* @return* @throws Exception*/@Overridepublic UserDao getObject() throws Exception {return new UserDaoImpl();}/* 被重写后,主要返回的是被创建类的Class对象* @return*/@Overridepublic Class<?> getObjectType() {return UserDao.class;}}
applicationContext.xml
<!--使用实例工厂实现FactoryBean接口实例化bean(掌握)这种方式Spring整合其他框架时会用到--><bean id="userDaoFactoryBean" class="com.shifan.factory.UserDaoFactoryBean"/>
测试类
//使用FactoryBean简化@Testpublic void testFactoryBean(){UserDao userDao = (UserDao) applicationContext.getBean("userDaoFactoryBean");userDao.save();}
Bean的生命周期
BrandService
public interface BrandService {void save();
}
BrandServiceImpl
/实现InitializingBean和DisposableBean接口,重写方法,简化初始化方法和销毁方法的编写与配置,实现bean生命周期控制(了解)*/
public class BrandServiceImpl implements BrandService , InitializingBean, DisposableBean {private BrandDao brandDao;//使用构造器注入brandDaopublic BrandServiceImpl(BrandDao brandDao){this.brandDao = brandDao;}//使用set方法注入brandDao
/* public void setBrandDao(BrandDao brandDao) {System.out.println("set...");this.brandDao = brandDao;}*/@Overridepublic void save() {brandDao.save();}@Overridepublic void destroy() throws Exception {System.out.println("release resource...");}/*afterPropertiesSet:属性设置后即brandDao被注入后才执行*/@Overridepublic void afterPropertiesSet() throws Exception {System.out.println("initialize resource...");}
}
BrandDao
public interface BrandDao {void save();
}
BrandDaoImpl
public class BrandDaoImpl implements BrandDao {private String name;private int price;public void setName(String name) {this.name = name;}public void setPrice(int price) {this.price = price;}@Overridepublic void save() {System.out.println("brand dao save..."+name+","+price);}//初始化方法public void init(){System.out.println("init resource...");}//销毁方法public void destroy(){System.out.println("rel resource...");}
}
applicatonContext.xml
<!--bean的生命周期控制bean创建后方法:init-method,可用于初始化资源bean销毁前方法:destroy-method,可用于释放资源--><bean id="brandDao" class="com.shifan.dao.impl.BrandDaoImpl" init-method="init" destroy-method="destroy"><!--普通参数注入--><property name="name" value="飘柔"/><property name="price" value="20"/></bean><bean id="brandService" class="com.shifan.service.impl.BrandServiceImpl"><!--<property name="brandDao" ref="brandDao"/>--><!--构造器注入引用数据类型(name和ref)构造器也可用于注入普通参数(name和value)name属性需要保证和构造方法中的形参名一致,那么这就出现了耦合问题解决方案一:类型注入,使用type属性替换name属性,按照属性注入,但是当存在多个相同类型时就会无法精准注入方案二:索引注入,使用index属性替换name属性,按照索引下标0,1...注入,但当形参顺序发生变化时,又会出现耦合问题如何选择:强制依赖使用构造器注入,使用setter注入有概率不进行注入导致null对象出现强制依赖指对象创建过程中必须的参数可选依赖使用setter方法注入,灵活性更强可选依赖指对象创建过程中可有可无的参数自己开发的模块推荐使用setter注入--><constructor-arg name="brandDao" ref="brandDao"/></bean>
测试类
@Testpublic void testBeanLifeCycle(){
/* BrandDao brandDao = (BrandDao) applicationContext.getBean("brandDao");brandDao.save();*/BrandService brandService = (BrandService) applicationContext.getBean("brandService");brandService.save();/*调用ClassPathXmlApplicationContext类的close方法关闭容器避免IOC容器因为JVM退出而来不及销毁bean对象,导致销毁方法不执行((ClassPathXmlApplicationContext)applicationContext).close();*//*注册钩子关闭容器在容器未关闭之前,设置回调函数,让JVM在退出之前回调此函数关闭容器与close方法相比:两种方法都能关闭容器,close方法是调用后就关闭容器,而registerShutdownHook方法是在JVM退出之前调用关闭容器*/((ClassPathXmlApplicationContext)applicationContext).registerShutdownHook();}
其他类型依赖注入
applicationContext.xml
<!--集合注入- property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写`<array>`、`<list>`、`<set>`、`<map>`、`<props>`标签- List的底层也是通过数组实现的,所以`<list>`和`<array>`标签是可以混用- 集合中要添加引用类型,只需要把`<value>`标签改成`<ref>`标签,这种方式用的比较少--><!--数组类型数据<property name="array"><array><value>100</value><value>200</value><value>300</value></array></property>--><!--List类型数据<property name="list"><list><value>itcast</value><value>itheima</value><value>boxuegu</value><value>chuanzhihui</value></list></property>--><!--set类型数据<property name="set"><set><value>itcast</value><value>itheima</value><value>boxuegu</value><value>boxuegu</value></set></property>--><!--map类型数据<property name="map"><map><entry key="country" value="china"/><entry key="province" value="henan"/><entry key="city" value="kaifeng"/></map></property>--><!--Properties类型数据<property name="properties"><props><prop key="country">china</prop><prop key="province">henan</prop><prop key="city">kaifeng</prop></props></property>-->