IOC容器
概念和原理
1、什么是IOC
- 控制反转,把对象的创建和对象之间的调用过程,交给Spring进行管理
- 使用IOC的目的:为了耦合度降低
- 入门案例是IOC的实现
2、IOC底层实现原理
- xml解析、工厂模式、反射
3、画图讲解IOC底层原理
4、IOC思想是基于IOC容器完成,IOC容器底层就是对象工厂
IOC接口
1、Spring提供了IOC容器实现的两种方式(两个接口):
- BeanFactory:IOC容器最基本实现的,是Spirng里面内部使用的接口,一般不提供开发 人员使用,特点是加载配置文件时不会创建里面的对象,在获取对象时才创建对象(懒汉式)。
- ApplicationContext:BeanFactory的子接口,提供了更多更加强大的接口,一般由 开发人员进行使用。在加载配置文件就会把在配置文件对象进行创建(饿汉式)
2、ApplicationContext接口有实现类:
IOC操作Bean管理(概念)
1、什么时Bean管理
- Bean管理指的两个操作
- Spring创建对象
- Spring注入属性
2、Bean管理的操作有两种实现方式
- 基于xml配置文件方式实现
- 基于注解方式实现
IOC操作Bean管理(基于xml方式)
1、基于xml方式创建对象
<bean id="user" class="com.sunrise.spring5.User"></bean>
- 在spring配置文件中,使用bean标签,标签里卖弄添加对应的属性,就可以实现对象的创建。
- id属性:唯一标识
- class属性:类全路径(包类属性)
- 创建对象时,默认执行无参构造方法完成对象的创建。
2、基于xml方式注入属性
- DI:依赖注入,就是注入属性
1. 使用使用set方法注入
public class Book {
private String bname;
private String bouthor;
public void setBname(String bname) {
this.bname = bname;
}
public void setBouthor(String bouthor) {
this.bouthor = bouthor;
}
}
2. 使用有参数的构造注入:spring配置中property作为bean的属性。也就是指一个类中的成员。同时这个成员必须有get和set方法。
<bean id = "book" class="com.sunrise.spring5.Book">
<!--使用priperty完成属性注入-->
<property name="bname" value="三体"></property>
<property name="bouthor" value="刘慈欣"></property>
</bean>
3、第二种注入方法:使用有参构造进行注入
- 创建类,定义属性,创建属性对应有参数构造方法
public class Order {
private String oname;
private String oaddress;
public void setOname(String oname) {
this.oname = oname;
}
public void setOaddress(String oaddress) {
this.oaddress = oaddress;
}
public Order(String oname, String oaddress) {
this.oname = oname;
this.oaddress = oaddress;
}
public void show(){
System.out.println("订单名:"+oname + "\n地址:"+ oaddress);
}
}
- 在 spring 配置文件中进行配置
<bean id="order" class="com.sunrise.spring5.Order">
<constructor-arg name="oaddress" value="China"></constructor-arg>
<constructor-arg name="oname" value="电脑"></constructor-arg>
</bean>
4、P名称空间注入
- 使用p名称空间注入,可以简化xml配置方式
a 添加p名称空间在配置文件中
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>
b 进行属性注入,在bean标签里面进行操作
<bean id="book" class="com.sunrise.spring5.Book" p:bname="斗罗大陆" p:bauthor="唐家三少"></bean>
IOC操作Bean管理(xml注入其他类型属性)
1、字面量
- 注入null值
<property name="address">
<null/>
</property>
- 属性值包含特殊符号
<property name="address">
<null/>
</property>
2、注入属性-外部Bean
- 创建两个类service类和dao类
- 在service调用dao里面的方法
- 在spring配置文件中进行配置
public class UserService {
//创建UserDao类型属性,生产set方法
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void add(){
System.out.println("service add.....");
userDao.update();
//创建UserDao对象
// UserDao userDao = new UserDaoImpl();
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- service和dao对象创建-->
<bean id = "userService" class="com.sunrise.spring5.service.UserService">
<!-- 注入userDao对象
name属性值:类里面的属性名称
ref属性:创建userDao对象bean标签的id值-->
<property name="userDao" ref="userDao" ></property>
</bean>
<bean id="userDao" class="com.sunrise.spring5.dao.UserDaoImpl"></bean>
</beans>
3、注入属性-内部bean
- 一对多关系:部门与员工,一个部门里面可以有多个员工,一个员工属于一个部门,部门是一,员工是多。
- 在实体类中表示他们的关系
public class Dept {
private String dname;
public void setDname(String dname) {
this.dname = dname;
}
}
public class Emp {
private String ename;
private String gender;
//员工属于某一个部门
private Dept dept;
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public void setGender(String gender) {
this.gender = gender;
}
}
- 在spring完成配置文件
<?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="emp" class="com.sunrise.spring5.Bean.Emp">
<property name="ename" value="jack" ></property>
<property name="gender" value="女"></property>
<property name="dept" >
<bean id="dept" class="com.sunrise.spring5.Bean.Dept">
<property name="dname" value="IT部"></property>
</bean>
</property>
</bean>
</beans>
4、注入属性的级联赋值
- 第一种写法
<?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="emp" class="com.sunrise.spring5.Bean.Emp">
<property name="ename" value="jack" ></property>
<property name="gender" value="女"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
</bean>
<bean id="dept" class="com.sunrise.spring5.Bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
</beans>
- 第二种写法
在Dept类中生成getDept()方法
public Dept getDept() {
return dept;
}
<?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="emp" class="com.sunrise.spring5.Bean.Emp">
<property name="ename" value="jack" ></property>
<property name="gender" value="女"></property>
<!-- 级联赋值-->
<property name="dept" ref="dept"></property>
<property name="dept.dname" value="技术部"></property>
</bean>
<bean id="dept" class="com.sunrise.spring5.Bean.Dept">
<property name="dname" value="财务部"></property>
</bean>
</beans>
IOC操作bean管理(xml注入集合属性)
1、注入数组类型属性
2、注入List集合类型属性
3、注入Map集合类型属性
- 生成包含集合的类
public class Stu {
//数组类型的属性
private String[] courses;
//创建list集合
private List<String> lists;
private Map<String, String> maps;
public void setCourses(String[] courses) {
this.courses = courses;
}
public void setLists(List<String> lists) {
this.lists = lists;
}
public void setMaps(Map<String, String> maps) {
this.maps = maps;
}
}
- 在spring配置文件中进行配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--集合类型属性的注入-->
<bean id="stu" class="com.sunrise.spring5.collectionType.Stu">
<!-- 属性注入-->
<property name="courses" >
<array >
<value >JAVA课程</value>
<value >数据库课程</value>
</array>
</property>
<property name="lists">
<list >
<value>张三</value>
<value>李四</value>
</list>
</property>
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
</bean>
</beans>
4、在集合里面设置对象类型值
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--集合类型属性的注入-->
<bean id="stu" class="com.sunrise.spring5.collectionType.Stu">
<!-- 属性注入-->
<property name="courses" >
<array >
<value >JAVA课程</value>
<value >数据库课程</value>
</array>
</property>
<property name="lists">
<list >
<value>张三</value>
<value>李四</value>
</list>
</property>
<property name="maps">
<map>
<entry key="JAVA" value="java"></entry>
<entry key="PHP" value="php"></entry>
</map>
</property>
<property name="courses1">
<list>
<ref bean="course1"></ref>
<ref bean="course2"></ref>
</list>
</property>
</bean>
<bean name="course1" class="com.sunrise.spring5.collectionType.Course">
<property name="cname" value="Spring5框架"></property>
</bean>
<bean name="course2" class="com.sunrise.spring5.collectionType.Course">
<property name="cname" value="MyBatis框架"></property>
</bean>
</beans>
5、把集合注入部分提取出来
- 在Spring配置文件中引入名称空间util
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--集合类型属性的注入-->
- 使用util标签完成list集合属性注入
<util:list id="booklist">
<value>傲世丹神</value>
<value>太容易坏</value>
<value>三体</value>
</util:list>
<bean id="book" class="com.sunrise.spring5.collectionType.Book">
<property name="list" ref="booklist"></property>
</bean>
IOC操作Bean管理(FactoryBean)
1、Spring有两种类型的Bean,一种普通的bean,另外有一种工厂bean(FactoryBean)
2、普通的Bean:在配置文件中定义的Bean类型就是返回类型
3、工厂bean:在配置文件中定义的bean类型可以和返回的类型不一致
第一步 创建一个类,让此类作为工厂bean。实现接口FactoryBean
第二步 实现接口里面的方法
public class MyBean implements FactoryBean<Course> {
//定义返回bean
@Override
public Course getObject() throws Exception {
Course course = new Course();
course.setCname("sd");
return course;
}
@Override
public Class<?> getObjectType() {
return null;
}
@Override
public boolean isSingleton() {
return false;
}
}
@Test
public void test3(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean3.xml");
Course course = context.getBean("myBean", Course.class);
System.out.println(course);
}
IOC操作Bean管理(Bean的作用域和生命周期)
1、在Spring里面可以设置创建的bean实例时单实例还是多实例
2、在Spring,默认情况下创建的bean实例是单实例对象
public void test2(){
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean2.xml");
Book book1 = context.getBean("book", Book.class);
Book book2 = context.getBean("book", Book.class);
System.out.println(book1);
System.out.println(book2);
}
com.sunrise.spring5.collectionType.Book@5c18298f
com.sunrise.spring5.collectionType.Book@5c18298f
3、如何设置单实例还是多实例
1 在spring配置文件bean标签里面有属性(scope)用于设置单实例还是多实例对象
2 scope属性值
- 默认值:singleton 表示单实例对象
- prottotype表示多实例对象
<bean id="book" class="com.sunrise.spring5.collectionType.Book" scope="prototype">
<property name="list" ref="booklist"></property>
</bean>
com.sunrise.spring5.collectionType.Book@5c18298f
com.sunrise.spring5.collectionType.Book@31f924f5
如上打印的地址值不同。
- singleton和prototype区别:singleton表示单实例,prototype表示多实例。设置scope值时singleton时候,在加载配置文件时就会创建单实例对象。设置为scope为prototype,不是在加载spring配置文件时就创建对象,而是在调用getBean方法时创建多实例对象。
3 request属性:表示一次请求
4 session:表示一次会话
IOC操作Bean管理(Bean的生命周期)
1、生命周期
从对象创建到对象销毁的过程。
2、bean的生命周期
a 通过构造器创建bean实例(无参数构造)
b 为bean的属性设置值和对其他bean的引用(调用类中的set方法)
c 调用bean的初始化方法(需要进行配置)
d bean可以使用了(对象获取到了)
e 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)
3、演示bean的生命周期
public class Orders {
private String oname;
//五参数的构造
public Orders() {
System.out.println("第一步执行无参数的构造创建bean实例");
}
public void setOname(String oname) {
this.oname = oname;
System.out.println("第二部 调用set方法设置值");
}
//创建执行的初始化方法
public void initMethod(){
System.out.println("第三步 执行初始化方法");
}
//创建销毁执行的方法
public void destoryMethod(){
System.out.println("第五步 执行销毁方法");
}
}
@Test
public void test4(){
ApplicationContext context = new ClassPathXmlApplicationContext("bean4.xml");
Orders orders = context.getBean("orders", Orders.class);
System.out.println("第四步, 获取创建bean实例的对象");
System.out.println(orders);
//手动让bean实例销毁
((ClassPathXmlApplicationContext)context).close();
}
<bean id="orders" class="com.sunrise.spring5.bean.Orders" init-method="initMethod" destroy-method="destoryMethod">
<property name="oname" value="手机"></property>
</bean>
4、bean的后置处理器,bean的生命周期一共有7步
a 通过构造器创建bean实例(无参数构造)
b 为bean的属性设置值和对其他bean的引用(调用类中的set方法)
c 把bean的实例传递给bean的后置处理器的方法postProcessBeforeInitialization
d 调用bean的初始化方法(需要进行配置)
e 把bean的实例传递给bean的后置处理器的方法postProcessAfterInitialization
f bean可以使用了(对象获取到了)
g 当容器关闭的时候,调用bean的销毁方法(需要进行配置销毁的方法)
5、演示调价后置处理器的效果
a 创建一个类实现接口BeanPostProcessor
public class MyBeanPost implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之前执行此方法");
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("在初始化之后执行此方法");
return bean;
}
}
<bean id="myBeanPost" class="com.sunrise.spring5.bean.MyBeanPost"></bean>
第一步执行无参数的构造创建bean实例
第二部 调用set方法设置值
在初始化之前执行此方法
第三步 执行初始化方法
在初始化之后执行此方法
第四步, 获取创建bean实例的对象
com.sunrise.spring5.bean.Orders@4671e53b
第五步 执行销毁方法
IOC操作Bean管理(xml自动装配)
1、什么时自动装配
根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入
2、演示自动装配的过程
- 根据属性名称自动注入
<!-- 实现自动装配
bean标签属性autowire,配置自动装配
autowire属性常用的两个值,
byName根据属性名称注入,注入值bean的id值和类的属性名称必须一样
byType根据属性类型注入, -->
<bean id="emp" class="com.sunrise.spring5.autowire.Emp" autowire="byName">
<!-- <property name="deot" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.sunrise.spring5.autowire.Dept"></bean>
- 根据属性类型自动注入
<!-- 实现自动装配
bean标签属性autowire,配置自动装配
autowire属性常用的两个值,
byName根据属性名称注入,注入值bean的id值和类的属性名称必须一样
byType根据属性类型注入, -->
<bean id="emp" class="com.sunrise.spring5.autowire.Emp" autowire="byType">
<!-- <property name="deot" ref="dept"></property>-->
</bean>
<bean id="dept" class="com.sunrise.spring5.autowire.Dept"></bean>
IOC操作Bean管理(外部属性文件)
1、直接配置数据库信息
- 配置连接池
- 引入德鲁伊连接池jar包
<!--直接配置连接池-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/userDb"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
2、通过引入外部属性文件配置数据库连接池
- 创建一个外部属性文件,properties格式文件,
prop.driverClass=com.mysql.jdbc.Driver
prop.url=jdbc:mysql://localhost:3306/userDb
prop.userName=root
prop.password=root
- 把外部properties属性文件引入到spring配置文件中
- 引入context名称空间
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
- 在spring配置文件中使用标签引入外部属性文件
<context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!-- 获取properties文件内容,根据key获取,使用spring表达式获取 -->
<property name="driverClassName" value="${prop.driverClass}"></property>
<property name="url" value="${prop.url}"></property>
<property name="username" value="${prop.userName}"></property>
<property name="password" value="${prop.password}"></property>