AI智能
改变未来

02-Spring5 IOC容器


概念与原理

  1. 什么是IOC
  1. 控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理
  2. 使用IOC目的:为了降低耦合度
  1. 做入门案例就是IOC实现
  1. IOC底层原理
  1. XML解析,工厂模式,反射
  1. 画图讲解IOC底层原理

IOC(BeanFactory接口)

  1. IOC思想基于IOC容器完成,IOC容器底层就是对象工厂
  2. Spring提供IOC容器实现的两种方式:(两个接口)
  1. BeanFactory: IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用
  1. *加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象
  1. ApplicationContext: BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员进行使用
  1. *加载配置文件时候就会把在配置文件对象进行创建
  1. ApplicationContext接口有实现类

IOC操作Bean管理(概念)

  1. 什么是Bean管理
  1. Bean管理指的是两个操作
  1. Spring创建对象
  2. Spring注入属性
  1. Bean管理操作有两种方式
  1. 基于XML配置文件实现
  2. 基于注解方式实现

IOC操作Bean管理(基于XML方式)

  1. 基于XML方式创建对象
  1. 在Spring配置文件中,使用Bean标签,标签里面添加对应属性,就可以实现对象创建
  1. ID属性: 唯一标识
  2. class属性: 类全路径(包类路径)
  1. 创建对象的时候,默认也是执行无参数构造方法完成对象创建
  1. 基于XML方式注入属性
  1. DI : 依赖注入,就是注入属性
  1. 第一种注入方式: 使用set方法进行注入

使用Set方法进行注入

package com.dance.spring5;public class Book {//创建属性private String bname;private String bauthor;//创建属性对应的 set 方法public void setBname(String bname) {this.bname = bname;}public void setBauthor(String bauthor) {this.bauthor = bauthor;}@Overridepublic String toString() {return \"Book{\" +\"bname=\'\" + bname + \'\\\'\' +\", bauthor=\'\" + bauthor + \'\\\'\' +\'}\';}public static void main(String[] args) {Book book = new Book();book.setBname(\"flower\");System.out.println(book);}}

在Spring配置文件配置对象创建,配置属性注入

<!--name : 属性名value : 属性值--><bean id=\"book\" class=\"com.dance.spring5.Book\"><property name=\"bname\" value=\"dance\" /></bean>

新建测试类

@Testpublic void testBook(){// 加载Spring配置文件ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(\"spring.xml\");// 获取BeanBook book = classPathXmlApplicationContext.getBean(\"book\", Book.class);// 调用方法System.out.println(book);}

执行结果

Book{bname=\'dance\', bauthor=\'null\'}
  1. 第二种注入方式:使用有参构造进行注入
  1. 创建类,定义属性,创建属性对应有参数构造方法

使用有参构造方法进行注入

package com.dance.spring5;public class Orders {//属性private String oname;private String address;//有参数构造public Orders(String oname,String address) {this.oname = oname;this.address = address;}@Overridepublic String toString() {return \"Orders{\" +\"oname=\'\" + oname + \'\\\'\' +\", address=\'\" + address + \'\\\'\' +\'}\';}public static void main(String[] args) {Orders orders = new Orders(\"flower\", \"北京\");System.out.println(orders);}}

在Spring配置文件中进行配置

<!-- 有参构造注入属性 --><bean id=\"orders\" class=\"com.dance.spring5.Orders\"><constructor-arg name=\"oname\" value=\"flower\"/><constructor-arg name=\"address\" value=\"北京\"/></bean>

新检测试类

@Testpublic void testOrders(){// 加载Spring配置文件ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(\"spring.xml\");// 获取BeanOrders orders = classPathXmlApplicationContext.getBean(\"orders\", Orders.class);// 调用方法System.out.println(orders);}

执行结果

Orders{oname=\'flower\', address=\'北京\'}
  1. P命名空间注入(了解)
  1. 使用P命名空间注入可以简化XML配置方式

使用P命名空间进行注入

在配置文件中加入P命名空间的校验

xmlns:p=\"http://www.springframework.org/schema/p\"

配置Spring文件

<!--    使用P命名空间注入--><bean id=\"ordersP\" class=\"com.dance.spring5.Orders\" p:oname=\"dance\" p:address=\"河北\" />

修改Orders类

注意:因为P命名空间注入依赖于Set方法所以增加setter and getter

package com.dance.spring5;public class Orders {//属性private String oname;private String address;public String getOname() {return oname;}public void setOname(String oname) {this.oname = oname;}public String getAddress() {return address;}public void setAddress(String address) {this.address = address;}public Orders() {}//有参数构造public Orders(String oname,String address) {this.oname = oname;this.address = address;}@Overridepublic String toString() {return \"Orders{\" +\"oname=\'\" + oname + \'\\\'\' +\", address=\'\" + address + \'\\\'\' +\'}\';}public static void main(String[] args) {Orders orders = new Orders(\"flower\", \"北京\");System.out.println(orders);}}

新建测试类

@Testpublic void testOrdersP(){// 加载Spring配置文件ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(\"spring.xml\");// 获取BeanOrders orders = classPathXmlApplicationContext.getBean(\"ordersP\", Orders.class);// 调用方法System.out.println(orders);}

执行结果

Orders{oname=\'dance\', address=\'河北\'}

IOC操作Bean管理(XML注入其他类型属性)

字面量

null值

<bean id=\"orderType\" class=\"com.dance.spring5.Orders\"><property name=\"address\"><null /></property></bean>

属性值包含特殊符号

属性值包含特殊符号

  1. 把<>进行转义 < >
  2. 使用CDATA
<bean id=\"orderType\" class=\"com.dance.spring5.Orders\"><property name=\"address\"><null /></property><property name=\"oname\"><!--CDATA--><value><![CDATA[ <<Spring5 API>> ]]></value></property></bean>

注入属性-外部Bean

(1)创建两个类 service 类和 dao 类

(2)在 service 调用 dao 里面的方法

(3)在 spring 配置文件中进行配置

新建UserDao

package com.dance.spring5.dao;public class UserDao {public void update(){System.out.println(\"update to database .....\");}}

新建UserService

package com.dance.spring5.service;import com.dance.spring5.dao.UserDao;public class UserService {public UserDao userDao;public void add(){System.out.println(\"add......\");userDao.update();}public void setUserDao(UserDao userDao){this.userDao = userDao;}}

配置Spring文件

<!-- 创建UserDao --><bean id=\"userDao\" class=\"com.dance.spring5.dao.UserDao\" /><!-- 创建UserService --><bean id=\"userService\" class=\"com.dance.spring5.service.UserService\"><!-- 采用ref引用已有的Bean --><property name=\"userDao\" ref=\"userDao\" /></bean>

新建测试类

@Testpublic void testUserService(){// 加载Spring配置文件ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(\"spring.xml\");// 获取BeanUserService userService = classPathXmlApplicationContext.getBean(\"userService\", UserService.class);// 调用方法userService.add();}

执行结果

add......update to database .....

注入属性-内部Bean

(1)一对多关系:部门和员工 一个部门有多个员工,一个员工属于一个部门 部门是一,员工是多

(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示

新建部门类

package com.dance.spring5;public class Dept {private String dname;public void setDname(String dname) {this.dname = dname;}@Overridepublic String toString() {return \"Dept{\" +\"dname=\'\" + dname + \'\\\'\' +\'}\';}}

新建员工类

package com.dance.spring5;public class Emp {private String ename;private String gender;private Dept dept;public void setEname(String ename) {this.ename = ename;}public void setGender(String gender) {this.gender = gender;}public void setDept(Dept dept) {this.dept = dept;}@Overridepublic String toString() {return \"Emp{\" +\"ename=\'\" + ename + \'\\\'\' +\", gender=\'\" + gender + \'\\\'\' +\", dept=\" + dept +\'}\';}}

配置Spring文件

<bean id=\"emp\" class=\"com.dance.spring5.Emp\"><property name=\"ename\" value=\"flower\" /><property name=\"gender\" value=\"男\" /><property name=\"dept\"><bean id=\"dept\" class=\"com.dance.spring5.Dept\"><property name=\"dname\" value=\"研发部\" /></bean></property></bean>

新建测试类

@Testpublic void testEmp(){// 加载Spring配置文件ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(\"spring.xml\");// 获取BeanEmp emp = classPathXmlApplicationContext.getBean(\"emp\", Emp.class);// 调用方法System.out.println(emp);}

执行结果

Emp{ename=\'flower\', gender=\'男\', dept=Dept{dname=\'研发部\'}}

注入属性-级联赋值

第一种写法

<bean id=\"dept2\" class=\"com.dance.spring5.Dept\"><property name=\"dname\" value=\"研发部\" /></bean><bean id=\"emp2\" class=\"com.dance.spring5.Emp\"><property name=\"ename\" value=\"dance\" /><property name=\"gender\" value=\"女\" /><property name=\"dept\" ref=\"dept2\" /></bean>

第二种写法

emp类增加get方法

public Dept getDept() {return dept;}
<bean id=\"emp3\" class=\"com.dance.spring5.Emp\"><property name=\"ename\" value=\"dance\" /><property name=\"gender\" value=\"女\" /><property name=\"dept\" ref=\"dept2\" /><property name=\"dept.dname\" value=\"财务部\" /></bean>

IOC操作Bean管理(xml注入集合属性)

XML注入集合属性

  • 注入数组类型属性
  • 注入List集合类型属性
  • 注入Map集合类型属性

新建学生类

package com.dance.spring.learn.collection;import java.util.Arrays;import java.util.List;import java.util.Map;import java.util.Set;public class Stu {//1 数组类型属性private String[] courses;//2 list 集合类型属性private List list;//3 map 集合类型属性private Map<String,String> maps;//4 set 集合类型属性private Set sets;public void setSets(Set sets) {this.sets = sets;}public void setCourses(String[] courses) {this.courses = courses;}public void setList(List list) {this.list = list;}public void setMaps(Map<String, String> maps) {this.maps = maps;}@Overridepublic String toString() {return \"Stu{\" +\"courses=\" + Arrays.toString(courses) +\", list=\" + list +\", maps=\" + maps +\", sets=\" + sets +\'}\';}}

在Spring中进行配置

<bean id=\"stu\" class=\"com.dance.spring.learn.collection.Stu\"><!--        数组--><property name=\"courses\"><array><value>Java</value><value>Spring</value></array></property><!--        集合--><property name=\"list\"><list><value>IOC</value><value>AOP</value></list></property><!--        Set--><property name=\"sets\"><set><value>Mysql</value><value>Oracle</value></set></property><!--        map--><property name=\"maps\"><map><entry key=\"name\" value=\"flower\" /><entry key=\"age\" value=\"21\" /></map></property></bean>

新建测试类

@Testpublic void test1(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext(\"Spring.xml\");Stu stu = applicationContext.getBean(\"stu\", Stu.class);System.out.println(stu);}

执行结果

Stu{courses=[Java, Spring], list=[IOC, AOP], maps={name=flower, age=21}, sets=[Mysql, Oracle]}

在集合中设置对象类型值

新建课程类

package com.dance.spring.learn.collection;/*** 课程类*/public class Course {private String cname;public String getCname() {return cname;}public void setCname(String cname) {this.cname = cname;}@Overridepublic String toString() {return \"Course{\" +\"cname=\'\" + cname + \'\\\'\' +\'}\';}}

修改学生类

package com.dance.spring.learn.collection;import java.util.Arrays;import java.util.List;import java.util.Map;import java.util.Set;public class Stu {//1 数组类型属性private String[] courses;//2 list 集合类型属性private List list;//3 map 集合类型属性private Map<String,String> maps;//4 set 集合类型属性private Set sets;// 5 list 对象集合private List courseList;public void setCourseList(List courseList) {this.courseList = courseList;}public void setSets(Set sets) {this.sets = sets;}public void setCourses(String[] courses) {this.courses = courses;}public void setList(List list) {this.list = list;}public void setMaps(Map<String, String> maps) {this.maps = maps;}@Overridepublic String toString() {return \"Stu{\" +\"courses=\" + Arrays.toString(courses) +\", list=\" + list +\", maps=\" + maps +\", sets=\" + sets +\", courseList=\" + courseList +\'}\';}}

在Spring中进行配置

<!--    创建多个Course--><bean id=\"cs1\" class=\"com.dance.spring.learn.collection.Course\"><property name=\"cname\" value=\"语文\" /></bean><bean id=\"cs2\" class=\"com.dance.spring.learn.collection.Course\"><property name=\"cname\" value=\"数学\" /></bean><bean id=\"stu\" class=\"com.dance.spring.learn.collection.Stu\"><!--        数组--><property name=\"courses\"><array><value>Java</value><value>Spring</value></array></property><!--        集合--><property name=\"list\"><list><value>IOC</value><value>AOP</value></list></property><!--        Set--><property name=\"sets\"><set><value>Mysql</value><value>Oracle</value></set></property><!--        map--><property name=\"maps\"><map><entry key=\"name\" value=\"flower\" /><entry key=\"age\" value=\"21\" /></map></property><!--        list Object--><property name=\"courseList\"><list><ref bean=\"cs1\" /><ref bean=\"cs2\" /></list></property></bean>

测试

使用之前的测试类

执行结果

Stu{courses=[Java, Spring], list=[IOC, AOP], maps={name=flower, age=21}, sets=[Mysql, Oracle], courseList=[Course{cname=\'语文\'}, Course{cname=\'数学\'}]}

提取集合注入部分

新建书类

package com.dance.spring.learn.collection;import java.util.List;public class Book {private List books;public void setBooks(List books) {this.books = books;}@Overridepublic String toString() {return \"Book{\" +\"books=\" + books +\'}\';}}

在Spring中进行配置

增加命名空间

xmlns:util=\"http://www.springframework.org/schema/util\"http://www.springframework.org/schema/utilhttp://www.springframework.org/schema/util/spring-util.xsd

配置bookList

<util:list id=\"bookList\"><value>Java</value><value>C++</value><value>Go</value></util:list><bean id=\"book\" class=\"com.dance.spring.learn.collection.Book\"><property name=\"books\" ref=\"bookList\" /></bean>

新建测试类

@Testpublic void test2(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext(\"Spring.xml\");Book book = applicationContext.getBean(\"book\", Book.class);System.out.println(book);}

执行结果

Book{books=[Java, C++, Go]}

IOC操作Bean管理(FactoryBean)

  1. Spring有两种类型Bean,一种普通Bean,另外一种是工厂Bean(FactoryBean)

普通Bean

在配置文件中定义Bean的类型就是返回类型

创建MyBean类

package com.dance.spring.learn.factorybean;public class MyBean {public void speak(){System.out.println(\"哈哈哈\");}}

在Spring中配置

<bean id=\"myBean\" class=\"com.dance.spring.learn.factorybean.MyBean\" />

新建测试类

@Testpublic void test3(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext(\"Spring.xml\");MyBean myBean = applicationContext.getBean(\"myBean\", MyBean.class);myBean.speak();}

执行结果

哈哈哈

工厂Bean

在配置文件定义Bean类型可以和返回类型不一致

修改MyBean

实现FactoryBean接口,泛型为Course

实现接口里面的方法,在实现的方法中定义返回的 bean 类型

package com.dance.spring.learn.factorybean;import com.dance.spring.learn.collection.Course;import org.springframework.beans.factory.FactoryBean;public class MyBean implements FactoryBean {public void speak(){System.out.println(\"哈哈哈\");}@Overridepublic Course getObject() throws Exception {Course course = new Course();course.setCname(\"JDOS实战\");return course;}@Overridepublic Class<?> getObjectType() {return null;}@Overridepublic boolean isSingleton() {return FactoryBean.super.isSingleton();}}

测试

使用普通Bean的测试

org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named \'myBean\' is expected to be of type \'com.dance.spring.learn.factorybean.MyBean\' but was actually of type \'com.dance.spring.learn.collection.Course\'at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:395)at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:207)at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1114)at com.dance.spring.learn.testdemo.TestSpring5Demo.test3(TestSpring5Demo.java:39)at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)at java.lang.reflect.Method.invoke(Method.java:498)at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)at org.junit.runners.ParentRunner.run(ParentRunner.java:413)at org.junit.runner.JUnitCore.run(JUnitCore.java:137)at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:235)at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:54)

显示类型错误

修改测试类

@Testpublic void test3(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext(\"Spring.xml\");Course myBean = applicationContext.getBean(\"myBean\", Course.class);System.out.println(myBean);}

执行结果

Course{cname=\'JDOS实战\'}

IOC操作Bean管理(Bean的作用域)

Bean的默认作用域

新建测试类

去掉Book类的toString方法

package com.dance.spring.learn.collection;import java.util.List;public class Book {private List books;public void setBooks(List books) {this.books = books;}}

新建单元测试

@Testpublic void test4(){ApplicationContext applicationContext = new ClassPathXmlApplicationContext(\"Spring.xml\");Book book1 = applicationContext.getBean(\"book\", Book.class);Book book2 = applicationContext.getBean(\"book\", Book.class);System.out.println(book1);System.out.println(book2);}

执行结果

com.dance.spring.learn.collection.Book@2a40cd94com.dance.spring.learn.collection.Book@2a40cd94

通过执行结果可以看出,在Spring中Bean的作用域默认是单例的

设置Bean的作用域

  1. 在Spring配置文件Bean标签里面有属性(Scope)用于设置单实例还是多实例
  2. Scope属性值
  1. 第一个值 默认值,singleton, 表示单实例对象
  2. 第二个值, prototype, 表示是多实例对象
  1. Singleton和Prototype的区别
  1. singleton 单实例, prototype 多实例
  2. 设置scope值为singleton时,加载Spring配置文件时就会创建单实例对象,设置scope值为prototype时,不是在加载Spring配置文件时候创建对象,在调用getBean方法时,才会创建多实例对象(就是每次New一个新的)

其他的我记得还有

request和session

request:一次请求

session:一次会话

想详细了解的话可以看一下:https://blog.csdn.net/kongmin_123/article/details/82048392

我感觉写的很好,但是一般没啥用,一般使用的话都是单例的,也就是默认的,在SpringBoot中也都是单例使用的

修改Spring配置

修改为多实例对象

<bean id=\"book\" class=\"com.dance.spring.learn.collection.Book\" scope=\"prototype\"><property name=\"books\" ref=\"bookList\" /></bean>

使用Test4测试

就是上面默认作用域的测试类

执行结果

com.dance.spring.learn.collection.Book@2a40cd94com.dance.spring.learn.collection.Book@f4168b8

通过结果可以看出,对象的内存地址不一样,所以是多实例对象

IOC操作Bean管理(Bean的生命周期)

生命周期

从对象创建到对象销毁的过程

Bean的生命周期

  1. 通过构造器创建Bean实例(无参数构造)
  2. 为Bean的属性设置值和对其他Bean的引用(调用Set方法)
  1. 调用Bean的初始化方法(需要进行配置初始化方法)
  2. Bean可以使用了(对象获取到了)
  1. 当容器关闭时,调用Bean的销毁方法(需要进行配置销毁的方法)

生命周期样例

新建Orders类

package com.dance.spring.learn.factorybean;public class Orders {private String oname;public Orders() {System.out.println(\"生命周期调用链: 第一步\");}public void setOname(String oname) {this.oname = oname;System.out.println(\"生命周期调用链: 第二步\");}public void init(){System.out.println(\"生命周期调用链: 第三步\");}public void destroy(){System.out.println(\"生命周期调用链: 第五步\");}}

在Spring中配置

<bean id=\"orders\" class=\"com.dance.spring.learn.factorybean.Orders\" init-method=\"init\" destroy-method=\"destroy\"><property name=\"oname\" value=\"啊哈哈哈~\" /></bean>

新建测试类

@Testpublic void test5(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(\"Spring.xml\");Orders orders = applicationContext.getBean(\"orders\", Orders.class);System.out.println(\"生命周期调用链: 第四步\");// 手动销毁容器applicationContext.close();}

执行结果

生命周期调用链: 第一步生命周期调用链: 第二步生命周期调用链: 第三步生命周期调用链: 第四步生命周期调用链: 第五步

Bean的后置处理器

后置处理器的生命周期位于初始化第三步的前后,整合后就是7步

  1. 通过构造器创建Bean实例(无参数构造)
  2. 为Bean的属性设置值和对其他Bean的引用(调用Set方法)
  1. 把Bean的实例传递给Bean的后置处理器(postProcessBeforeInitialization)
  2. 调用Bean的初始化方法(需要进行配置初始化方法)
  1. 把Bean的实例传递给Bean的后置处理器(postProcessAfterInitialization)
  2. Bean可以使用了(对象获取到了)
  1. 当容器关闭时,调用Bean的销毁方法(需要进行配置销毁的方法)

后置处理器样例

新建后置处理器Bean

package com.dance.spring.learn.factorybean;import org.springframework.beans.BeansException;import org.springframework.beans.factory.config.BeanPostProcessor;public class MyBeanPostProcessor implements BeanPostProcessor {@Overridepublic Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {System.out.println(\"生命周期调用链: 第三步之前\");return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);}@Overridepublic Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {System.out.println(\"生命周期调用链: 第三步之后\");return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);}}

在Spring中进行配置

<bean id=\"myBeanPostProcessor\" class=\"com.dance.spring.learn.factorybean.MyBeanPostProcessor\" />

测试

调用Bean的生命周期样例测试

执行结果

生命周期调用链: 第一步生命周期调用链: 第二步生命周期调用链: 第三步之前生命周期调用链: 第三步生命周期调用链: 第三步之后生命周期调用链: 第四步生命周期调用链: 第五步

IOC操作Bean管理(XML自动装配)

什么是自动装配

根据指定装配规则(属性名称或者属性类型),Spring自动将匹配的属性值进行注入

演示自动装配过程

根据属性名称自动注入

新建Dept类

package com.dance.spring.learn.autowire;public class Dept {}

新建Emp类

package com.dance.spring.learn.autowire;public class Emp {private Dept dept;public void setDept(Dept dept) {this.dept = dept;}@Overridepublic String toString() {return \"Emp{\" +\"dept=\" + dept +\'}\';}}

在Spring中进行配置

<bean id=\"dept\" class=\"com.dance.spring.learn.autowire.Dept\" /><bean id=\"emp\" class=\"com.dance.spring.learn.autowire.Emp\" autowire=\"byName\"></bean>

byName:根据名称自动注入

byType:根据类型自动注入

新建测试类

@Testpublic void test6(){ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(\"Spring2.xml\");Emp emp = applicationContext.getBean(\"emp\", Emp.class);System.out.println(emp);}

执行结果

Emp{dept=com.dance.spring.learn.autowire.Dept@25bbf683}

根据类型自动注入

在Spring中进行配置

<bean id=\"dept\" class=\"com.dance.spring.learn.autowire.Dept\" /><bean id=\"emp\" class=\"com.dance.spring.learn.autowire.Emp\" autowire=\"byType\"></bean>

测试

使用test6进行测试

执行结果

Emp{dept=com.dance.spring.learn.autowire.Dept@3578436e}

IOC操作Bean管理(外部属性文件)

直接配置数据库信息

引入德鲁伊连接池的包

配置德鲁伊连接池

<bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\"><property name=\"driver\" value=\"com.mysql.jdbc.Driver\" /><property name=\"url\" value=\"jdbc:mysql://localhost:3306/userDb\" /><property name=\"username\" value=\"root\" /><property name=\"password\" value=\"123456\" /></bean>

引入外部属性文件配置数据库信息

创建外部属性文件

在src下创建jdbc.properties

jdbc.driverClass=com.mysql.jdbc.Driverjdbc.url=jdbc:mysql://localhost:3306/userDbjdbc.username=rootjdbc.password=123456

引入Context命名空间

xmlns:context=\"http://www.springframework.org/schema/context\"http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd

在Spring中进行配置

<context:property-placeholder location=\"classpath:jdbc.properties\" /><bean id=\"dataSource\" class=\"com.alibaba.druid.pool.DruidDataSource\"><property name=\"driver\" value=\"${jdbc.driverClass}\" /><property name=\"url\" value=\"${jdbc.url}\" /><property name=\"username\" value=\"${jdbc.username}\" /><property name=\"password\" value=\"${jdbc.password}\" /></bean>

IOC操作Bean管理(基于注解开发)

什么是注解

  1. 注解是代码特殊标记,格式:@注解名称 (属性名称=属性值,属性名称=属性值)
  2. 注解作用范围, 类,方法,字段
  1. 使用注解的目的:简化xml配置

Spring针对Bean管理中创建对象提供的注解

  1. @Component
  2. @Service
  1. @Controller
  2. @Repository

上面四个注解的功能是一样的,都可用来创建Bean实例

基于注解的方式创建对象

引入依赖

开启注解扫描

<!--开启组件扫描多包配置可以使用逗号隔开,也可以写父包--><context:component-scan base-package=\"com.dance.spring.learn.service\" />

创建UserService类

@Servicepublic class UserService {public void add(){System.out.println(\"add ......\");}}

新建测试类

@Testpublic void test7(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(\"Spring3-annotation.xml\");UserService userService = classPathXmlApplicationContext.getBean(\"userService\", UserService.class);userService.add();}

执行结果

add ......

开启组件扫描细节配置

<!--只扫描@Controlleruse-default-filters=\"false\" : 不使用默认的扫描过滤器context:include-filter: 包含过滤器type=\"annotation\": 类型为注解expression=\"org.springframework.stereotype.Controller\": 只扫描@Controller--><context:component-scan base-package=\"com.dance.spring.learn.service\" use-default-filters=\"false\"><context:include-filter type=\"annotation\" expression=\"org.springframework.stereotype.Controller\"/></context:component-scan><!--不扫描@Controllercontext:exclude-filter: 排除过滤器type=\"annotation\": 类型为注解expression=\"org.springframework.stereotype.Controller\": 不扫描@Controller--><context:component-scan base-package=\"com.dance.spring.learn.service\"><context:exclude-filter type=\"annotation\" expression=\"org.springframework.stereotype.Controller\"/></context:component-scan>

基于注解实现属性注入

@Autowired

根据类型进行自动装配

新建Userdao

package com.dance.spring.learn.dao;import org.springframework.stereotype.Repository;@Repositorypublic class UserDao {public void add(){System.out.println(\"add to db.....\");}}

修改UserService

package com.dance.spring.learn.service;import com.dance.spring.learn.dao.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Service;@Servicepublic class UserService {@Autowiredpublic UserDao userDao;public void add(){System.out.println(\"add ......\");userDao.add();}}

新建Spring配置文件

因为之前的已经配置了很多的配置,所以在Src下新建Spring4.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\"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.xsdhttp://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsdhttp://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd\"><!--  扫描父包 learn  --><context:component-scan base-package=\"com.dance.spring.learn\"/></beans>

新建测试类

@Testpublic void test8(){ClassPathXmlApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext(\"Spring4.xml\");UserService userService = classPathXmlApplicationContext.getBean(\"userService\", UserService.class);userService.add();}

执行结果

add ......add to db.....

@Qualifier

需要配合Autowired一期使用,默认为根据类型自动装配,添加@Qualifier后将根据Qualifier的value值进行按名称自动装配

修改UserService

package com.dance.spring.learn.service;import com.dance.spring.learn.dao.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;@Servicepublic class UserService {@Autowired@Qualifier(value = \"userDao\")public UserDao userDao;public void add(){System.out.println(\"add ......\");userDao.add();}}

测试

使用test8进行测试

执行结果

add ......add to db.....

@Resource

既可以使用类型注入也可以使用名称注入,默认为名称注入,如果没有相同的名称那么就按类型注入,name和type都指定时,取都符合条件的

修改UserService

package com.dance.spring.learn.service;import com.dance.spring.learn.dao.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.stereotype.Service;import javax.annotation.Resource;@Servicepublic class UserService {//    @Autowired//    @Qualifier(value = \"userDao\")//    public UserDao userDao;@Resourcepublic UserDao userDao;public void add(){System.out.println(\"add ......\");userDao.add();}}

测试

使用test8进行测试

执行结果

add ......add to db.....

@Value

用于对普通值进行注入,也可以配合上面的外部属性文件采用${}方式获取配置文件值

修改UserService

package com.dance.spring.learn.service;import com.dance.spring.learn.dao.UserDao;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.beans.factory.annotation.Qualifier;import org.springframework.beans.factory.annotation.Value;import org.springframework.stereotype.Service;import javax.annotation.Resource;@Servicepublic class UserService {//    @Autowired//    @Qualifier(value = \"userDao\")//    public UserDao userDao;@Resourcepublic UserDao userDao;@Value(value = \"flower\")public String name;public void add(){System.out.println(\"add ......:\"+name);userDao.add();}}

测试

使用test8进行测试

测试结果

add ......:floweradd to db.....

去除XML,纯注解开发

创建配置类,取代XML

package com.dance.spring.learn.config;import org.springframework.context.annotation.ComponentScan;import org.springframework.context.annotation.Configuration;@Configuration@ComponentScan(basePackages = {\"com.dance.spring.learn\"})public class SpringConfig {}

新建测试类

@Testpublic void test9(){AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);UserService userService = annotationConfigApplicationContext.getBean(\"userService\", UserService.class);userService.add();}

执行结果

add ......:floweradd to db.....

完结撒花花

若有收获,就点个赞吧

作者:彼岸舞

时间:2021\\12\\13

内容关于:Java

本文属于作者原创,未经允许,禁止转发

赞(0) 打赏
未经允许不得转载:爱站程序员基地 » 02-Spring5 IOC容器