概念与原理

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

image.png

IOC(BeanFactory接口)

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

image.png

IOC操作Bean管理(概念)

  1. 什么是Bean管理
    1. Bean管理指的是两个操作
      1. Spring创建对象
      2. Spring注入属性
  2. Bean管理操作有两种方式

    1. 基于XML配置文件实现
    2. 基于注解方式实现

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

  3. 基于XML方式创建对象

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

    使用Set方法进行注入

    ```java package com.dance.spring5;

public class Book {

  1. //创建属性
  2. private String bname;
  3. private String bauthor;
  4. //创建属性对应的 set 方法
  5. public void setBname(String bname) {
  6. this.bname = bname;
  7. }
  8. public void setBauthor(String bauthor) {
  9. this.bauthor = bauthor;
  10. }
  11. @Override
  12. public String toString() {
  13. return "Book{" +
  14. "bname='" + bname + '\'' +
  15. ", bauthor='" + bauthor + '\'' +
  16. '}';
  17. }
  18. public static void main(String[] args) {
  19. Book book = new Book();
  20. book.setBname("flower");
  21. System.out.println(book);
  22. }

}

在Spring配置文件配置对象创建,配置属性注入
```xml
<!--
    name : 属性名
    value : 属性值
    -->
<bean id="book" class="com.dance.spring5.Book">
  <property name="bname" value="dance" />
</bean>

新建测试类

@Test
public void testBook(){

    // 加载Spring配置文件
    ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");

    // 获取Bean
    Book book = classPathXmlApplicationContext.getBean("book", Book.class);

    // 调用方法
    System.out.println(book);
}

执行结果

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

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

      ```java 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;
}

@Override
public String toString() {
    return "Orders{" +
            "oname='" + oname + '\'' +
            ", address='" + address + '\'' +
            '}';
}

public static void main(String[] args) {
    Orders orders = new Orders("flower", "北京");
    System.out.println(orders);
}

}

在Spring配置文件中进行配置
```xml
<!-- 有参构造注入属性 -->
<bean id="orders" class="com.dance.spring5.Orders">
  <constructor-arg name="oname" value="flower"/>
  <constructor-arg name="address" value="北京"/>
</bean>

新检测试类

@Test
public void testOrders(){

    // 加载Spring配置文件
    ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");

    // 获取Bean
    Orders 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"
      
      image.png
      配置Spring文件
      <!--    使用P命名空间注入-->
      <bean id="ordersP" class="com.dance.spring5.Orders" p:oname="dance" p:address="河北" />
      
      修改Orders类
      注意:因为P命名空间注入依赖于Set方法所以增加setter and getter ```java 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;
}

@Override
public String toString() {
    return "Orders{" +
            "oname='" + oname + '\'' +
            ", address='" + address + '\'' +
            '}';
}

public static void main(String[] args) {
    Orders orders = new Orders("flower", "北京");
    System.out.println(orders);
}

}

新建测试类
```java
@Test
public void testOrdersP(){

    // 加载Spring配置文件
    ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");

    // 获取Bean
    Orders 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

    ```java package com.dance.spring5.dao;

public class UserDao {

public void update(){
    System.out.println("update to database .....");
}

}

<a name="Uxq0c"></a>
### 新建UserService
```java
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>

新建测试类

@Test
public void testUserService(){

    // 加载Spring配置文件
    ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");

    // 获取Bean
    UserService 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;
    }

    @Override
    public 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;
    }

    @Override
    public 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>

新建测试类

@Test
public void testEmp(){

    // 加载Spring配置文件
    ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("spring.xml");

    // 获取Bean
    Emp 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集合类型属性

    新建学生类

    ```java 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 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 maps) { this.maps = maps; }

@Override
public String toString() {
    return "Stu{" +
            "courses=" + Arrays.toString(courses) +
            ", list=" + list +
            ", maps=" + maps +
            ", sets=" + sets +
            '}';
}

}

<a name="twRX0"></a>
### 在Spring中进行配置
```xml
<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>

新建测试类

@Test
public 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;
    }

    @Override
    public 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<String> list;
    //3 map 集合类型属性
    private Map<String,String> maps;
    //4 set 集合类型属性
    private Set<String> sets;
    // 5 list 对象集合
    private List<Course> courseList;

    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

    @Override
    public 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<String> books;

    public void setBooks(List<String> books) {
        this.books = books;
    }

    @Override
    public String toString() {
        return "Book{" +
                "books=" + books +
                '}';
    }
}

在Spring中进行配置

增加命名空间

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

image.png
配置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>

新建测试类

@Test
public 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类

    ```java package com.dance.spring.learn.factorybean;

public class MyBean {

public void speak(){
    System.out.println("哈哈哈");
}

}

<a name="YVY3z"></a>
### 在Spring中配置
```xml
<bean id="myBean" class="com.dance.spring.learn.factorybean.MyBean" />

新建测试类

@Test
public 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<Course> {

    public void speak(){
        System.out.println("哈哈哈");
    }

    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("JDOS实战");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public 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)

显示类型错误

修改测试类

@Test
public 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<String> books;

    public void setBooks(List<String> books) {
        this.books = books;
    }

}

新建单元测试

@Test
public 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@2a40cd94
com.dance.spring.learn.collection.Book@2a40cd94

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

设置Bean的作用域

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

image.png
其他的我记得还有
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@2a40cd94
com.dance.spring.learn.collection.Book@f4168b8

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

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

生命周期

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

Bean的生命周期

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

    生命周期样例

    新建Orders类

    ```java 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("生命周期调用链: 第五步");
}

}

<a name="Eo39u"></a>
### 在Spring中配置
```xml
<bean id="orders" class="com.dance.spring.learn.factorybean.Orders" init-method="init" destroy-method="destroy">
  <property name="oname" value="啊哈哈哈~" />
</bean>

新建测试类

@Test
public 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方法)
  3. 把Bean的实例传递给Bean的后置处理器(postProcessBeforeInitialization)
  4. 调用Bean的初始化方法(需要进行配置初始化方法)
  5. 把Bean的实例传递给Bean的后置处理器(postProcessAfterInitialization)
  6. Bean可以使用了(对象获取到了)
  7. 当容器关闭时,调用Bean的销毁方法(需要进行配置销毁的方法)

    后置处理器样例

    新建后置处理器Bean

    ```java package com.dance.spring.learn.factorybean;

import org.springframework.beans.BeansException; import org.springframework.beans.factory.config.BeanPostProcessor;

public class MyBeanPostProcessor implements BeanPostProcessor {

@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("生命周期调用链: 第三步之前");
    return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
}

@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("生命周期调用链: 第三步之后");
    return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
}

}

<a name="QsFFH"></a>
### 在Spring中进行配置
```xml
<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;
    }

    @Override
    public 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:根据类型自动注入

新建测试类

@Test
public 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管理(外部属性文件)

直接配置数据库信息

引入德鲁伊连接池的包

image.png

配置德鲁伊连接池

<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.Driver
jdbc.url=jdbc:mysql://localhost:3306/userDb
jdbc.username=root
jdbc.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. 注解作用范围, 类,方法,字段
  3. 使用注解的目的:简化xml配置

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

  4. @Component

  5. @Service
  6. @Controller
  7. @Repository

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

基于注解的方式创建对象

引入依赖

image.png

开启注解扫描

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

创建UserService类

@Service
public class UserService {

    public void add(){
        System.out.println("add ......");
    }

}

新建测试类

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

执行结果

add ......

开启组件扫描细节配置

<!--  
        只扫描@Controller
        use-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>

<!--  
        不扫描@Controller
        context: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;

@Repository
public 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;

@Service
public class UserService {

    @Autowired
    public 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.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd
        http://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>

新建测试类

@Test
public 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;

@Service
public 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;

@Service
public class UserService {

//    @Autowired
//    @Qualifier(value = "userDao")
//    public UserDao userDao;

    @Resource
    public 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;

@Service
public class UserService {

//    @Autowired
//    @Qualifier(value = "userDao")
//    public UserDao userDao;

    @Resource
    public UserDao userDao;

    @Value(value = "flower")
    public String name;

    public void add(){
        System.out.println("add ......:"+name);
        userDao.add();
    }

}

测试

使用test8进行测试

测试结果

add ......:flower
add 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 {

}

新建测试类

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

执行结果

add ......:flower
add to db.....

完结撒花花