• Java框架 Spring5--IOC


    1. IOC的概念和原理

    1.1 什么是 IOC

            (1)控制反转,把对象创建和对象之间的调用过程,交给 Spring 进行管理
            (2)使用 IOC 目的:为了耦合度降低
            (3)做入门案例就是 IOC 实现

    1.2 IOC 底层原理(xml 解析、工厂模式、反射

    1.2.1 原始方式和工厂模式的对象创建和对象之间的调用过程

     1.2.2 IOC的对象创建和对象之间的调用过程

     2. IOC 接口

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

    3. IOC 操作 Bean 管理(基于 xml 方式)

    3.1 IOCBean 管理(概念)

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

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

    3.2.1 基于 xml 方式创建对象

    (1)在 spring 配置文件中,使用 bean 标签,标签里面添加对应属性,就可以实现对象
             创建
    (2)在 bean 标签有很多属性,介绍常用的属性
            * id 属性:唯一标识
            * class 属性:类全路径(包类路径)
    (3)创建对象时候,默认也是执行无参数构造方法完成对象创建

    3.2.2 基于 xml 方式注入属性

    DI :依赖注入,就是注入属性
            DI是IOC中的一种具体实现
            DI需要在创建对象的基础上实现的

    3.2.3 注入方式1:使用 set 方法进行注入

    1.创建类,定义属性和对应的 set 方法

    1. public class Book {
    2. private String bname;
    3. private String bauthor;
    4. public void setBname(String bname) {
    5. this.bname = bname;
    6. }
    7. public void setBauthor(String bauthor) {
    8. this.bauthor = bauthor;
    9. }
    10. @Override
    11. public String toString() {
    12. return "Book{" +
    13. "bname='" + bname + '\'' +
    14. ", bauthor='" + bauthor + '\'' +
    15. '}';
    16. }
    17. }

    2. 在 spring 配置文件配置对象创建,配置属性注入

    1. <bean id="book" class="com.chenyixin.spring5.demo_2_ioc.pojo.Book">
    2. <property name="bname" value="Java从入门到放弃"/>
    3. <property name="bauthor" value="张三"/>
    4. bean>

    3. 测试:

    1. public class Test {
    2. @org.junit.Test
    3. public void test1() {
    4. // 1 加载 spring 配置文件
    5. ApplicationContext context = new ClassPathXmlApplicationContext("demo2_ioc.xml");
    6. // 2 获取配置创建的对象
    7. Book book = context.getBean("book", Book.class);
    8. System.out.println(book.toString());
    9. }
    10. }

    4. 结果:

    3.2.4 注入方式2:使用有参数构造进行注入

    1. 创建类,定义属性,创建属性对应有参数构造方法
    1. public class Orders {
    2. private String oName;
    3. private String oAddress;
    4. public Orders(String oName, String oAddress) {
    5. this.oName = oName;
    6. this.oAddress = oAddress;
    7. }
    8. @Override
    9. public String toString() {
    10. return "Orders{" +
    11. "oName='" + oName + '\'' +
    12. ", oAddress='" + oAddress + '\'' +
    13. '}';
    14. }
    15. }
    2. 在 spring 配置文件中进行配置

    1. <bean id="orders" class="com.chenyixin.spring5.demo_2_ioc.pojo.Orders">
    2. <constructor-arg name="oName" value="A1111"/>
    3. <constructor-arg name="oAddress" value="China"/>
    4. bean>

    3.测试

    1. public void test2() {
    2. // 1 加载 spring 配置文件
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo2_ioc.xml");
    4. // 2 获取配置文件创建的对象
    5. Orders orders = context.getBean("orders", Orders.class);
    6. System.out.println(orders.toString());
    7. }

    4. 结果:

    3.2.5 p 名称空间注入

    使用 p 名称空间注入,可以简化基于 xml 配置方式
    1. 添加 p 名称空间在配置文件中

    2. 代码示例:

    创建类

    1. public class User {
    2. private Integer id;
    3. private String name;
    4. public void setId(Integer id) {
    5. this.id = id;
    6. }
    7. public void setName(String name) {
    8. this.name = name;
    9. }
    10. @Override
    11. public String toString() {
    12. return "User{" +
    13. "id=" + id +
    14. ", name='" + name + '\'' +
    15. '}';
    16. }
    17. }

    xml配置:

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xmlns:p="http://www.springframework.org/schema/p"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. http://www.springframework.org/schema/beans/spring-beans.xsd">
    6. <bean id="user" class="com.chenyixin.spring5.demo_2_ioc.pojo.User" p:id="1" p:name="张三"/>
    7. beans>

    测试:

    1. @org.junit.Test
    2. public void test3() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo2_ioc.xml");
    4. User user = context.getBean("user", User.class);
    5. System.out.println(user.toString());
    6. }

    结果:

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

    3.3.1 字面量

    1null
    < property name= "address" >
    < null />
    property >
    (2)属性值包含特殊符号

    < property name= "address" >
    < value >>]]> value >
    property >

    代码示例:

    创建类:

    1. public class Student1 {
    2. private Integer id;
    3. private String name;
    4. private String address;
    5. public Student1(Integer id, String name, String address) {
    6. this.id = id;
    7. this.name = name;
    8. this.address = address;
    9. }
    10. @Override
    11. public String toString() {
    12. return "Student1{" +
    13. "id=" + id +
    14. ", name='" + name + '\'' +
    15. ", address='" + address + '\'' +
    16. '}';
    17. }
    18. }

    xml配置

    1. <bean id="student1" class="com.chenyixin.spring5.demo_2_ioc.pojo.Student1">
    2. <constructor-arg name="id">
    3. <null/>
    4. constructor-arg>
    5. <constructor-arg name="name" value="<张三>"/>
    6. <constructor-arg name="address">
    7. <value>>]]>value>
    8. constructor-arg>
    9. bean>

    测试:

    1. @org.junit.Test
    2. public void test4() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo2_ioc.xml");
    4. Student1 student1 = context.getBean("student1", Student1.class);
    5. System.out.println(student1.toString());
    6. }

    结果:

    3.3.2 注入属性-外部 bean

    需求:

    (1)创建两个类 service 类和 dao 类
    (2)在 service 调用 dao 里面的方法
    (3)在 spring 配置文件中进行配置

    代码示例:

    创建类:

    1. public interface UserDao {
    2. public void update();
    3. }
    4. public class UserDaoImpl implements UserDao {
    5. @Override
    6. public void update() {
    7. System.out.println(" 这是 实现了UserDao接口的UserDaoImpl类 的update方法!!! ");
    8. }
    9. }
    1. public class UserService {
    2. private UserDao userDao;
    3. public void setUserDao(UserDao userDao) {
    4. this.userDao = userDao;
    5. }
    6. public void add() {
    7. System.out.println(" 这是UserService类的 add 方法");
    8. userDao.update();
    9. }
    10. }

    配置xml文件:

    1. <bean id="userDaoImpl" class="com.chenyixin.spring5.demo_2_ioc.dao.impl.UserDaoImpl"/>
    2. <bean id="userService" class="com.chenyixin.spring5.demo_2_ioc.service.UserService">
    3. <property name="userDao" ref="userDaoImpl"/>
    4. bean>

    测试:

    1. @org.junit.Test
    2. public void test5() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo2_ioc.xml");
    4. UserService userService = context.getBean("userService", UserService.class);
    5. userService.add();
    6. }

    结果:

    3.3.3 注入属性-内部 bean

    需求:

    (1)一对多关系:部门和员工
            一个部门有多个员工,一个员工属于一个部门
            部门是一,员工是多
    (2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示
      ( 3 )在 spring 配置文件中进行配置

    代码示例:

    1. 创建类

    1. // 部门类
    2. public class Dept {
    3. private String dname;
    4. public void setDname(String dname) {
    5. this.dname = dname;
    6. }
    7. @Override
    8. public String toString() {
    9. return "Dept{" +
    10. "dname='" + dname + '\'' +
    11. '}';
    12. }
    13. }
    14. // 员工类
    15. public class Emp {
    16. private String name;
    17. private String gender;
    18. private Dept dept;
    19. public void setName(String name) {
    20. this.name = name;
    21. }
    22. public void setGender(String gender) {
    23. this.gender = gender;
    24. }
    25. public void setDept(Dept dept) {
    26. this.dept = dept;
    27. }
    28. @Override
    29. public String toString() {
    30. return "Emp{" +
    31. "name='" + name + '\'' +
    32. ", gender='" + gender + '\'' +
    33. ", dept=" + dept +
    34. '}';
    35. }
    36. }

    2. 在 spring 配置文件中进行配置

    这里学习内部Bean,所以使用内部Bean,但推荐使用外部Bean,可读性高

    1. <bean id="emp" class="com.chenyixin.spring5.demo_2_ioc.pojo.Emp">
    2. <property name="name" value="张三"/>
    3. <property name="gender" value="女"/>
    4. <property name="dept">
    5. <bean id="dept" class="com.chenyixin.spring5.demo_2_ioc.pojo.Dept">
    6. <property name="dname" value="安保部"/>
    7. bean>
    8. property>
    9. bean>

    3.测试:

    1. @org.junit.Test
    2. public void test6() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo2_ioc.xml");
    4. Emp emp = context.getBean("emp", Emp.class);
    5. System.out.println(emp.toString());
    6. }

    4.结果:

    3.3.4 注入属性-级联赋值

            使用上个例子

    代码示例:

    写法一:

    1. <bean id="emp" class="com.chenyixin.spring5.demo_2_ioc.pojo.Emp">
    2. <property name="name" value="张三"/>
    3. <property name="gender" value="女"/>
    4. <property name="dept" ref="dept"/>
    5. bean>
    6. <bean id="dept" class="com.chenyixin.spring5.demo_2_ioc.pojo.Dept">
    7. <property name="dname" value="财务部"/>
    8. bean>

    结果:

    写法2:

    1.先给dept属性加个get方法

    1. public Dept getDept() {
    2. return dept;
    3. }

    2.编写配置文件:

    1. <bean id="emp" class="com.chenyixin.spring5.demo_2_ioc.pojo.Emp">
    2. <property name="name" value="张三"/>
    3. <property name="gender" value="女"/>
    4. <property name="dept" ref="dept"/>
    5. <property name="dept.dname" value="技术部"/>
    6. bean>
    7. <bean id="dept" class="com.chenyixin.spring5.demo_2_ioc.pojo.Dept">
    8. <property name="dname" value="财务部"/>
    9. bean>

    结果:

    3.3.5 小结(个人理解)

    1. property,constructor-arg使用双标签时,两标签之间 所放入的标签(转义标签除外)

        可当成该属性的value值

    2. 级联赋值 可当成需要赋值的 外部Bean

    3. 注入属性对象时,需使用ref属性,而不是使用value属性(使用内部级联除外)

    4. 在注入属性对象时,推荐使用 级联赋值方式或外部Bean方式

    3.4 IOC 操作 Bean 管理(xml 注入数组、集合属性)

    3.4.1 xml 注入数组、集合属性

    需求:

            1、注入数组类型属性
            2、注入 List 集合类型属性
            3、注入 Set 集合类型属性
            4、注入 Map 集合类型属性

    代码示例:

    1. 创建类

    1. public class Student {
    2. // 1 数组类型的属性
    3. private String[] arr;
    4. // 2 List类型的属性
    5. private List list;
    6. // 3 Set类型的属性
    7. private Set set;
    8. // 4 Map类型的属性 map;
    9. private Map map;
    10. public Student(String[] arr, List list, Set set, Map map) {
    11. this.arr = arr;
    12. this.list = list;
    13. this.set = set;
    14. this.map = map;
    15. }
    16. public void test(){
    17. System.out.println(Arrays.toString(arr));
    18. System.out.println(list);
    19. System.out.println(set);
    20. System.out.println(map);
    21. }
    22. }

    2. xml配置文件编写

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="student" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Student">
    5. <constructor-arg name="arr">
    6. <array>
    7. <value>Javavalue>
    8. <value>pythonvalue>
    9. array>
    10. constructor-arg>
    11. <constructor-arg name="list">
    12. <list>
    13. <value>张三value>
    14. <value>小三value>
    15. list>
    16. constructor-arg>
    17. <constructor-arg name="set">
    18. <set>
    19. <value>黄焖鸡value>
    20. <value>蛋炒饭value>
    21. set>
    22. constructor-arg>
    23. <constructor-arg name="map">
    24. <map>
    25. <entry key="Java" value="90"/>
    26. <entry key="python" value="85"/>
    27. map>
    28. constructor-arg>
    29. bean>
    30. beans>

    3.测试

    1. public class Test {
    2. @org.junit.Test
    3. public void testStudent() {
    4. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_colliction.xml");
    5. Student student = context.getBean("student", Student.class);
    6. student.test();
    7. }
    8. }

    4.结果:

    3.4.2 在集合里面设置对象类型值

    代码示例:

    1. 创建类

    1. // 图书类
    2. // 图书类
    3. public class Book {
    4. private Integer id;
    5. private String name;
    6. public Integer getId() {
    7. return id;
    8. }
    9. public String getName() {
    10. return name;
    11. }
    12. public void setId(Integer id) {
    13. this.id = id;
    14. }
    15. public void setName(String name) {
    16. this.name = name;
    17. }
    18. @Override
    19. public String toString() {
    20. return "Book{" +
    21. "id=" + id +
    22. ", name='" + name + '\'' +
    23. '}';
    24. }
    25. }
    1. // 书柜类
    2. public class Books {
    3. private Book[] arr;
    4. private List list;
    5. private Set set;
    6. private Map map;
    7. public Book[] getArr() {
    8. return arr;
    9. }
    10. public void setArr(Book[] arr) {
    11. this.arr = arr;
    12. }
    13. public List getList() {
    14. return list;
    15. }
    16. public void setList(List list) {
    17. this.list = list;
    18. }
    19. public Set getSet() {
    20. return set;
    21. }
    22. public void setSet(Set set) {
    23. this.set = set;
    24. }
    25. public Map getMap() {
    26. return map;
    27. }
    28. public void setMap(Map map) {
    29. this.map = map;
    30. }
    31. public void test(){
    32. System.out.println(Arrays.toString(arr));
    33. System.out.println(list);
    34. System.out.println(set);
    35. System.out.println(map);
    36. }
    37. }

    2. 编写xml配置文件:

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    4. <bean id="book1" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Book">
    5. <property name="id" value="111"/>
    6. <property name="name" value="java从入门到放弃"/>
    7. bean>
    8. <bean id="book2" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Book">
    9. <property name="id" value="222"/>
    10. <property name="name" value="c从入门到入土"/>
    11. bean>
    12. <bean id="book3" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Book">
    13. <property name="id" value="333"/>
    14. <property name="name" value="c++从入门到入坟"/>
    15. bean>
    16. <bean id="books" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Books">
    17. <property name="arr">
    18. <array>
    19. <ref bean="book1"/>
    20. <ref bean="book3"/>
    21. array>
    22. property>
    23. <property name="list">
    24. <list>
    25. <ref bean="book1"/>
    26. <ref bean="book2"/>
    27. <ref bean="book3"/>
    28. list>
    29. property>
    30. <property name="set">
    31. <set>
    32. <ref bean="book2"/>
    33. <ref bean="book3"/>
    34. set>
    35. property>
    36. <property name="map">
    37. <map>
    38. <entry key-ref="book1" value="28.8"/>
    39. <entry key-ref="book2" value="88.8"/>
    40. <entry key-ref="book3" value="888.8"/>
    41. map>
    42. property>
    43. bean>
    44. beans>

    3. 测试:

    1. @org.junit.Test
    2. public void testBooks() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_colliction2.xml");
    4. Books books = context.getBean("books", Books.class);
    5. books.test();
    6. }

    4.结果:

    1. [Book{id=111, name='java从入门到放弃'}, Book{id=333, name='c++从入门到入坟'}]
    2. [Book{id=111, name='java从入门到放弃'}, Book{id=222, name='c从入门到入土'}, Book{id=333, name='c++从入门到入坟'}]
    3. [Book{id=222, name='c从入门到入土'}, Book{id=333, name='c++从入门到入坟'}]
    4. {Book{id=111, name='java从入门到放弃'}=28.8, Book{id=222, name='c从入门到入土'}=88.8, Book{id=333, name='c++从入门到入坟'}=888.8}

    3.4.3 把集合注入部分提取出来

    1. 在 spring 配置文件中引入名称空间 util

    红色部分为添加部分

    2.xml配置文件代码:

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xmlns:util="http://www.springframework.org/schema/util"
    4. xsi:schemaLocation=
    5. "http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    6. http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    7. <bean id="book1" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Book">
    8. <property name="id" value="111"/>
    9. <property name="name" value="java从入门到放弃"/>
    10. bean>
    11. <bean id="book2" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Book">
    12. <property name="id" value="222"/>
    13. <property name="name" value="c从入门到入土"/>
    14. bean>
    15. <bean id="book3" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Book">
    16. <property name="id" value="333"/>
    17. <property name="name" value="c++从入门到入坟"/>
    18. bean>
    19. <util:list id="list">
    20. <ref bean="book1"/>
    21. <ref bean="book3"/>
    22. util:list>
    23. <util:set id="set">
    24. <ref bean="book2"/>
    25. <ref bean="book3"/>
    26. util:set>
    27. <util:map id="map">
    28. <entry key-ref="book1" value="39.99"/>
    29. <entry key-ref="book2" value="99.99"/>
    30. <entry key-ref="book3" value="999.99"/>
    31. util:map>
    32. <bean id="books2" class="com.chenyixin.spring5.demo_3_ioc_collection.collection.Books">
    33. <property name="arr">
    34. <array>
    35. <ref bean="book1"/>
    36. <ref bean="book3"/>
    37. array>
    38. property>
    39. <property name="list" ref="list"/>
    40. <property name="set" ref="set"/>
    41. <property name="map" ref="map"/>
    42. bean>
    43. beans>

    3.测试:

    1. @org.junit.Test
    2. public void testBooks2() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_colliction3.xml");
    4. Books books2 = context.getBean("books2", Books.class);
    5. books2.test();
    6. }

    4.结果:

    1. [Book{id=111, name='java从入门到放弃'}, Book{id=333, name='c++从入门到入坟'}]
    2. [Book{id=111, name='java从入门到放弃'}, Book{id=333, name='c++从入门到入坟'}]
    3. [Book{id=222, name='c从入门到入土'}, Book{id=333, name='c++从入门到入坟'}]
    4. {Book{id=111, name='java从入门到放弃'}=39.99, Book{id=222, name='c从入门到入土'}=99.99, Book{id=333, name='c++从入门到入坟'}=999.99}

    3.5 IOC 操作 Bean 管理(FactoryBean)

    1、Spring 有两种类型 bean,一种普通 bean,另外一种工厂 bean(FactoryBean)
    2、普通 bean:在配置文件中定义 bean 类型就是返回类型
    3、工厂 bean:在配置文件定义 bean 类型可以和返回类型不一样
           工厂Bean可以返回普通类型的Bean,降低普通Bean与调用者的耦合度
             第一步 创建类,实现接口 FactoryBean,让这个类作为工厂 bean
            第二步 实现接口里面的方法,在实现的方法中定义返回的 bean 类型

    代码示例:

    1.创建类,实现接口 FactoryBean,让这个类作为工厂 bean,并实现getObject方法

    1. // 创建工厂Bean
    2. public class MyBean implements FactoryBean {
    3. @Override
    4. //定义返回 bean :要与泛型一致
    5. public Book getObject() throws Exception {
    6. Book book = new Book();
    7. book.setId(111);
    8. book.setName("aaa");
    9. return book;
    10. }
    11. @Override
    12. public Class getObjectType() {
    13. return null;
    14. }
    15. @Override
    16. public boolean isSingleton() {
    17. return FactoryBean.super.isSingleton();
    18. }
    19. }

    2. 编写xml配置文件

    <bean id="myBean" class="com.chenyixin.spring5.demo_3_ioc_collection.factorybean.MyBean"/>

    3.测试:

    1. @Test
    2. public void testMyBean() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_factorybean.xml");
    4. Book book = context.getBean("myBean", Book.class);
    5. System.out.println(book);
    6. }

    4.结果:

     

    3.6 IOC 操作 Bean 管理(bean 作用域)

            在 Spring 里面,设置创建 bean 实例是单实例还是多实例

    3.6.1 在 Spring 里面,设置创建 bean 实例 在默认情况下,bean 是单实例对象

    代码验证:

    1.创建类:

    1. public class Person {
    2. private String name;
    3. public void setName(String name) {
    4. this.name = name;
    5. }
    6. }

    2.xml代码:

    1. <bean id="person" class="com.chenyixin.spring5.demo_3_ioc_collection.factorybean.Person">
    2. <property name="name" value="张三"/>
    3. bean>

    3.验证:

    1. @Test
    2. public void testPerson() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_factorybean.xml");
    4. Person person1 = context.getBean("person", Person.class);
    5. Person person2 = context.getBean("person", Person.class);
    6. System.out.println(person1);
    7. System.out.println(person2);
    8. }

    4. 结果:

    Person对象实例的地址值相同,说明这是单例对象

    3.6.2 设置单实例还是多实例

    (1)在 spring 配置文件 bean 标签里面有属性(scope)用于设置单实例还是多实例
    (2)scope 属性值
             singleton(默认值),表示是单实例对象
             prototype,表示是多实例对象
              request, 表示一次请求域 (了解)
             session, 表示一个会话域(了解)

    代码示例:

    1.更改xml配置文件:

    1. <bean id="person" class="com.chenyixin.spring5.demo_3_ioc_collection.factorybean.Person" scope="prototype">
    2. <property name="name" value="张三"/>
    3. bean>

    2. 测试:

    1. @Test
    2. public void testPerson() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_factorybean.xml");
    4. Person person1 = context.getBean("person", Person.class);
    5. Person person2 = context.getBean("person", Person.class);
    6. System.out.println(person1);
    7. System.out.println(person2);
    8. }

    3.结果:

     Person对象实例的地址值不相同,说明这是多例对象

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

    生命周期 就是 从对象创建到对象销毁的过程

    3.7.1 bean 生命周期

    1 )通过构造器创建 bean 实例(无参数构造)
    (2)为 bean 的属性设置值和对其他 bean 引用(调用 set 方法)
    (3)调用 bean 的初始化的方法(需要进行配置初始化的方法)
    (4) bean 可以使用了(对象获取到了)
    (5)当容器关闭时候,调用 bean 的销毁的方法(需要进行配置销毁的方法)
    如果创建的是有参构造器的实例对象,则第一二步合成一步,共四步

    3.7.2 演示 bean 生命周期

    1.创建类

    1. public class Order {
    2. private String oname;
    3. public Order() {
    4. System.out.println("第一步 执行无参数构造创建 bean 实例");
    5. }
    6. public void setOname(String oname) {
    7. this.oname = oname;
    8. System.out.println("第二步 调用 set 方法设置属性值");
    9. }
    10. // 初始化方法
    11. public void initMethod() {
    12. System.out.println("第三步 执行初始化的方法");
    13. }
    14. // 销毁方法
    15. public void destroyMethod() {
    16. System.out.println("第五步 执行销毁的方法");
    17. }
    18. }

    2.编写xml文件

    1. <bean id="order" class="com.chenyixin.spring5.demo_3_ioc_collection.bean.Order"
    2. init-method="initMethod"
    3. destroy-method="destroyMethod">
    4. <property name="oname" value="手机"/>
    5. bean>

    3.演示:

    1. @Test
    2. public void testOrder() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_bean.xml");
    4. Order order = context.getBean("order", Order.class);
    5. System.out.println("第四步 获取创建 bean 实例对象");
    6. System.out.println(order);
    7. // 对象需要手动销毁
    8. // close方法是 ClassPathXmlApplicationContext 中方法
    9. ((ClassPathXmlApplicationContext)context).close();
    10. }

    4.结果:

     

    3.7.3 添加 bean 的后置处理器,bean 生命周期+2步

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

    3.7.4 如何添加bean 的后置处理器

    1. 创建类,实现接口 BeanPostProcessor,创建后置处理器

    2. 实现 BeanPostProcessor 中的 postProcessBeforeInitialization 方法                                                    与 postProcessAfterInitialization 方法

    3. 在配置文件中 创建该类的 bean标签,因为该类实现接口 BeanPostProcessor,使该类成为了后置处理器,该类的 bean标签会对其所在的xml配置文件中的所有bean标签的类添加后置处理器

    3.7.5 演示添加后置处理器效果

    1. 创建 后置处理器 类

    1. public class MyBeanPost implements BeanPostProcessor {
    2. @Override
    3. public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    4. System.out.println("在初始化之前执行的方法");
    5. return bean;
    6. }
    7. @Override
    8. public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    9. System.out.println("在初始化之后执行的方法");
    10. return bean;
    11. }
    12. }

    2. 在xml配置文件中添加后置处理器

    1. <bean id="order" class="com.chenyixin.spring5.demo_3_ioc_collection.bean.Order"
    2. init-method="initMethod"
    3. destroy-method="destroyMethod">
    4. <property name="oname" value="手机"/>
    5. bean>
    6. <bean id="myBeanPost" class="com.chenyixin.spring5.demo_3_ioc_collection.bean.MyBeanPost"/>

    3.测试:

    1. @Test
    2. public void testOrder() {
    3. ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_bean.xml");
    4. Order order = context.getBean("order", Order.class);
    5. System.out.println("第四步 获取创建 bean 实例对象");
    6. System.out.println(order);
    7. // 对象需要手动销毁
    8. // close方法是 ClassPathXmlApplicationContext 中方法
    9. context.close();
    10. }

    4.结果:

     

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

    3.8.1 什么是自动装配

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

            就是对类中的对象属性值自动注入

    Spring IOC容器可以自动装配Bean,需要做的是在的autowire属性里面指定自动装配的模式;
            byType(根据类型自动装配),若在IOC容器中有多个与目标Bean类型一致的bean,在这种情况下,Spring将无法判断哪个Bean最合适该属性,所以不能执行自动装配。
            byName(根据名称自动装配),必须将目标bean的名称和属性名设置的完全相同;


            constructor(通过构造器自动装配),当bean中存在多个构造器时候,此种自动装配方式将会很复杂(不推荐使用)。
     

    3.8.2 演示自动装配过程

    1. 创建bean类

    1. public class Dept {
    2. private Integer did;
    3. private String dname;
    4. public void setDid(Integer did) {
    5. this.did = did;
    6. }
    7. public void setDname(String dname) {
    8. this.dname = dname;
    9. }
    10. @Override
    11. public String toString() {
    12. return "Dept{" +
    13. "did=" + did +
    14. ", dname='" + dname + '\'' +
    15. '}';
    16. }
    17. }
    1. public class Emp {
    2. private Integer eid;
    3. private String ename;
    4. private Dept dept;
    5. public void setEid(Integer eid) {
    6. this.eid = eid;
    7. }
    8. public void setEname(String ename) {
    9. this.ename = ename;
    10. }
    11. public void setDept(Dept dept) {
    12. this.dept = dept;
    13. }
    14. @Override
    15. public String toString() {
    16. return "Emp{" +
    17. "eid=" + eid +
    18. ", ename='" + ename + '\'' +
    19. ", dept=" + dept +
    20. '}';
    21. }
    22. }

    2. 编写配置文件

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xmlns:p="http://www.springframework.org/schema/p"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. http://www.springframework.org/schema/beans/spring-beans.xsd">
    6. <bean id="dept" class="com.chenyixin.spring5.demo_3_ioc_collection.auto.Dept"
    7. p:did="100" p:dname="技术部"/>
    8. <bean id="emp" class="com.chenyixin.spring5.demo_3_ioc_collection.auto.Emp"
    9. p:eid="005" p:ename="王五" p:dept-ref="dept">
    10. bean>
    11. <bean id="emp" class="com.chenyixin.spring5.demo_3_ioc_collection.auto.Emp"
    12. p:eid="005" p:ename="王五" autowire="byName"/>
    13. <bean id="emp" class="com.chenyixin.spring5.demo_3_ioc_collection.auto.Emp"
    14. p:eid="005" p:ename="王五" autowire="byType"/>
    15. beans>

    3.测试

    1. @org.junit.Test
    2. public void test() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo3_ioc_auto.xml");
    4. Emp emp = context.getBean("emp", Emp.class);
    5. System.out.println(emp);
    6. }

    4.结果:

    3.8.3 XML配置里面Bean自动装配的缺点

            在Bean配置文件里面设置autowire进行自动装配将会装配Bean的所有属性,然而,若只希望装配个别属性的时候,autowire属性就不够灵敏了;


            autowire属性要么根据类型自动装配,要么根据名称自动装配,不能两者兼而得之;


            一般情况下,在实际的项目中,很少使用自动装配的功能,因为和自动装配功能所带来的的好处比起来,明确清晰的配置文档更有说服力一些。

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

            在很多时候,我们的类中属性可能不止一个,那么我们按照xml方式进行配置的时候就需要多次使用property标签进行属性的注入,一旦属性多了,使用起来就会很麻烦。

            那么我们可以将一些固定的值提前配置好,使用时直接引用就行。

            常见的就是针对数据库操作时的连接!我们可以将数据库名称、用户名、密码、url等提前配置好,然后使用的时候直接引入即可。(我们这边就以德鲁伊为例)

    前提准备:引入德鲁伊连接池依赖 jar

    3.9.1 直接配置数据库信息

    1. <bean id="driverClassName" class="com.alibaba.druid.pool.DruidDataSource">
    2. <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
    3. <property name="url" value="jdbc:mysql://localhost:3306/userDb"/>
    4. <property name="username" value="root"/>
    5. <property name="password" value="root"/>
    6. bean>

    3.9.2 把外部 properties 属性文件引入到 spring 配置文件中

    1. 创建外部属性文件,properties 格式文件,写数据库信息

    2. 引入 context 名称空间 (操作与之前util相同) 

    红色部分为添加的部分

    2. 编写xml文件

    在 spring 配置文件使用标签引入外部属性文件
    1. <context:property-placeholder location="jdbc.properties"/>
    2. <bean id="driverClassName" class="com.alibaba.druid.pool.DruidDataSource">
    3. <property name="driverClassName" value="${prop.driverClassName}"/>
    4. <property name="url" value="${prop.url}"/>
    5. <property name="username" value="${prop.username}"/>
    6. <property name="password" value="${prop.password}"/>
    7. bean>

    3.9.3 通过属性文件实现属性注入

            org.springframework.beans.factory.config.PropertyPlaceholderConfigurer 类可以将 .properties(key/value形式)文件中一些动态设定的值(value),在XML中替换为占位该键($key$)的值,.properties文件可以根据客户需求,自定义一些相关的参数,这样的设计可提供程序的灵活性。

    1. 创建外部属性文件,properties 格式文件

     2. 创建类

    1. public class Person {
    2. private Integer id;
    3. private String name;
    4. private String sex;
    5. public void setId(Integer id) {
    6. this.id = id;
    7. }
    8. public void setName(String name) {
    9. this.name = name;
    10. }
    11. public void setSex(String sex) {
    12. this.sex = sex;
    13. }
    14. @Override
    15. public String toString() {
    16. return "Person{" +
    17. "id=" + id +
    18. ", name='" + name + '\'' +
    19. ", sex='" + sex + '\'' +
    20. '}';
    21. }
    22. }

    3.编写xml文件

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xmlns:context="http://www.springframework.org/schema/context"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. http://www.springframework.org/schema/beans/spring-beans.xsd
    6. http://www.springframework.org/schema/context
    7. http://www.springframework.org/schema/context/spring-context.xsd">
    8. <bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
    9. <property name="locations">
    10. <list>
    11. <value>person.propertiesvalue>
    12. list>
    13. property>
    14. bean>
    15. <bean id="person" class="com.chenyixin.spring5.demo_4_ioc_druid.Person">
    16. <property name="id" value="${prop.id}"/>
    17. <property name="name" value="${prop.name}"/>
    18. <property name="sex" value="${prop.sex}"/>
    19. bean>
    20. beans>

    4.测试:

    1. @Test
    2. public void test() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo4_ioc_person.xml");
    4. Person person = context.getBean("person", Person.class);
    5. System.out.println(person);
    6. }

    5.结果:

     

    4.IOC 操作 Bean 管理(基于注解方式)

    4.1 什么是注解

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

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

       ⑴ @Conponent:通用注解

       ⑵ @Service:通常用于业务层注释

       ⑶ @Contruller:通常用于Web层注释

       ⑷ @Repository:通常用于持久层(Dao层)注释

            * 上面四个注解功能是一样的,都可以用来创建 bean 实例,放哪都一样,只是可以增加可读性

    4.3 基于注解方式实现对象创建

    1. 引入依赖

    2. 在xml文件中 开启组件扫描

    开启组件扫描,XML文件识别规定路径下的注释内容
            如果扫描多个包,多个包使用逗号隔开,也可以直接扫描包的上层目录。

    1. <beans xmlns="http://www.springframework.org/schema/beans"
    2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    3. xmlns:context="http://www.springframework.org/schema/context"
    4. xsi:schemaLocation="http://www.springframework.org/schema/beans
    5. http://www.springframework.org/schema/beans/spring-beans.xsd
    6. http://www.springframework.org/schema/context
    7. http://www.springframework.org/schema/context/spring-context.xsd">
    8. <context:component-scan base-package="com.chenyixin.spring5"/>
    9. beans>

    3. 创建类,在类上面添加创建对象注解

            在需要用注解方式创建的类上面加上可被XML解析识别的注解

            Spring针对Bean管理中创建对象提供的注解的value属性是用来标识当前类(相当于bean标签中的id值),默认值是类名称的第一个字母小写

    1. // @Service(value = "userService")
    2. @Service // 相当于
    3. public class UserService {
    4. public void add() {
    5. System.out.println("我是 UserService 的 add 方法!!!");
    6. }
    7. }

    4. 测试:

    1. @Test
    2. public void testUserService() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo5_ioc2.xml");
    4. UserService userService = context.getBean("userService", UserService.class);
    5. userService.add();
    6. }

    5.结果:

     

    4.4 开启组件扫描细节配置

    ①user-default-filters="false"表示现在不使用默认的filter,使用自己配置的filter,context:include-filter,是指需要扫描的注释

    1. <context:component-scan base-package="com.chenyixin.spring5" use-default-filters="false">
    2. <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    3. context:component-scan>

    ② context:exclude-filter,设置不进行扫描的注释内容

    1. <context:component-scan base-package="com.chenyixin.spring5">
    2. <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    3. context:component-scan>

    4.5 基于注解方式实现属性注入

    可以注入属性的标签@Autowired,@Qualifier,@Resource,@Value

    4.5.1 @Autowired:根据属性类型进行自动装配

    @Autowired:使用在字段上用于根据类型依赖注入,使用该注解定义属性,不需要添加该属性的Set方法

    1. 把 service dao 对象创建,在 service dao 类添加创建对象注解
    2.在 service 注入 dao 对象,在 service 类添加 dao 类型属性,在属性上面使用注解

    代码示例:

    1. public interface UserDao {
    2. public void update();
    3. }
    4. @Repository
    5. public class UserDaoImpl implements UserDao {
    6. @Override
    7. public void update() {
    8. System.out.println("我是 UserDaoImpl 类的 update 方法");
    9. }
    10. }
    1. // @Service(value = "userService")
    2. @Service // 相当于
    3. public class UserService {
    4. //定义 dao 类型属性
    5. //不需要添加 set 方法
    6. //添加注入属性注解
    7. @Autowired
    8. private UserDao userDao;
    9. public void add() {
    10. System.out.println("我是 UserService 的 add 方法!!!");
    11. userDao.update();
    12. }
    13. }

    测试:

    1. @Test
    2. public void testUserService() {
    3. ApplicationContext context = new ClassPathXmlApplicationContext("demo5_ioc2.xml");
    4. UserService userService = context.getBean("userService", UserService.class);
    5. userService.add();
    6. }

    结果:

     

    4.5.2 @Qualifier:根据名称进行注入

    这个 @Qualifier 注解的使用,和上面 @Autowired 一起使用

       ⑴@Qualifier注解用来标识是调用哪一个Bean类

       ⑵注意:需要加载的Bean类也要加上注解,XML加载时才会扫描到他,进行加载

       ⑶注意:Value值填的是Bean类的注解的唯一标识值,如果未指定,是其Bean类的首字母小写

    代码示例:

    1. @Repository(value = "userDaoImpl2")
    2. public class UserDaoImpl2 implements UserDao {
    3. @Override
    4. public void update() {
    5. System.out.println("我是 UserDaoImpl2 类的 update 方法");
    6. }
    7. }
    1. // @Service(value = "userService")
    2. @Service // 相当于
    3. public class UserService {
    4. //添加注入属性注解
    5. @Autowired // 根据类型进行注入
    6. @Qualifier(value = "userDaoImpl2") //根据名称进行注入
    7. private UserDao userDao;
    8. public void add() {
    9. System.out.println("我是 UserService 的 add 方法!!!");
    10. userDao.update();
    11. }
    12. }

    测试代码同上

    结果:

     

    4.5.3 @Resource:可以根据类型注入,可以根据名称注入

    @Resource:相当于@autowired+@Qualifier,按照名称进行注入

    代码示例:

    1. // @Service(value = "userService")
    2. @Service // 相当于
    3. public class UserService {
    4. // //添加注入属性注解
    5. // @Autowired // 根据类型进行注入
    6. // @Qualifier(value = "userDaoImpl2") //根据名称进行注入
    7. // private UserDao userDao;
    8. // @Resource // 根据类型进行注入
    9. @Resource(name="userDaoImpl") //根据名称进行注入
    10. private UserDao userDao;
    11. public void add() {
    12. System.out.println("我是 UserService 的 add 方法!!!");
    13. userDao.update();
    14. }
    15. }

    4.5.4 @Value:注入普通类型属性

    1. // @Service(value = "userService")
    2. @Service // 相当于
    3. public class UserService {
    4. // //添加注入属性注解
    5. // @Autowired // 根据类型进行注入
    6. // @Qualifier(value = "userDaoImpl2") //根据名称进行注入
    7. // private UserDao userDao;
    8. // @Resource // 根据类型进行注入
    9. @Resource(name="userDaoImpl") //根据名称进行注入
    10. private UserDao userDao;
    11. @Value(value = "aaa")
    12. private String name;
    13. public void add() {
    14. System.out.println("我是 UserService 的 add 方法!!!"+name);
    15. userDao.update();
    16. }
    17. }

    结果:

    4.6 完全注解开发 

    4.6.1 创建配置类,完全替代XML配置文件

       ⑴为该类添加注解@Configuration,以示是注解配置类

       ⑵添加注解@ComponentScan,设置注解扫描路径

    代码示例:

    1. @Configuration //作为配置类,替代 xml 配置文件
    2. @ComponentScan(basePackages = {"com.chenyixin.spring5"})
    3. public class SpringConfig {
    4. }

    4.6.2 编写测试方法获取IOC容器的语句

    1. @Test
    2. public void test() {
    3. ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
    4. UserService userService = context.getBean("userService", UserService.class);
    5. userService.add();
    6. }

    结果:

  • 相关阅读:
    android 默认开启谷歌定位精准度
    270_JSON_设置xxxValue为一个JSON对象类型且复制上一层value数据到xxxValue中
    【WLAN】Android 13 WIFI 连接流程
    Java—修饰符
    6.9平衡二叉树(LC110-E)
    估计流量矩阵的方法
    CAN 通信-底层
    每日一题:2022.11.11最后的简单模拟题
    [CISCN 2019 初赛]Love Math
    STM8S系列基于STVD开发,标准外设库函数开发环境搭建
  • 原文地址:https://blog.csdn.net/weixin_65637841/article/details/126140100