Spring3-IoC1-IoC容器、基于xml管理bean

目录

IoC容器

概述

依赖注入

IoC容器在Spring中的实现

基于xml管理bean

获取bean

依赖注入

setter注入

构造器注入

特殊值处理

字面量赋值

null值

xml实体

CDATA节

特殊类型属性注入

对象类型属性注入

方式一:引用外部bean

方式二:内部bean

方式三:级联属性赋值

数组类型属性注入

集合类型属性注入

list、set集合类型

map集合类型

引用集合类型

p命名空间

引入外部属性文件

bean的作用域

bean的生命周期

FactoryBean

基于xml自动装配


IoC容器

概述

IoC 是 Inversion of Control 的简写,译为"控制反转",它不是一门技术,而是一种设计思想,是一个重要的面向对象编程法则,能够指导我们如何设计出松耦合、更优良的程序

Spring 通过 IoC 容器来管理所有 Java 对象的实例化和初始化,控制对象与对象之间的依赖关系。我们将由 IoC 容器管理的 Java 对象称为 Spring Bean,它与使用关键字 new 创建的 Java 对象没有任何区别

控制反转是一种思想

控制反转是为了降低程序耦合度,提高程序扩展力

控制反转,反转的是什么?

  • 将对象的创建权利交出去,交给第三方容器负责
  • 将对象和对象之间关系的维护权交出去,交给第三方容器负责

控制反转这种思想如何实现呢?

  • DI(Dependency Injection):依赖注入

依赖注入

DI(Dependency Injection):依赖注入,依赖注入实现了控制反转的思想

依赖注入:Spring创建对象的过程中,将对象依赖属性通过配置进行注入

依赖注入常见的实现方式包括两种:

  • set注入
  • 构造注入

Bean管理:Bean对象的创建以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)

IoC容器在Spring中的实现

Spring 的 IoC 容器就是 IoC思想的一个落地的产品实现。IoC容器中管理的组件也叫做 bean。在创建 bean 之前,首先需要创建IoC 容器。Spring 提供了IoC 容器的两种实现方式:

①BeanFactory

这是 IoC 容器的基本实现,是 Spring 内部使用的接口。面向 Spring 本身,不提供给开发人员使用

②ApplicationContext

BeanFactory 的子接口,提供了更多高级特性。面向 Spring 的使用者,几乎所有场合都使用ApplicationContext,而不是底层的 BeanFactory

ApplicationContext的主要实现类:

类型名 简介
ClassPathXmlApplicationContext 通过读取类路径下的 XML 格式的配置文件创建 IOC 容器对象
FileSystemXmlApplicationContext 通过文件系统路径读取 XML 格式的配置文件创建 IOC 容器对象
ConfigurableApplicationContext ApplicationContext 的子接口,包含一些扩展方法 refresh() 和 close() ,让 ApplicationContext 具有启动、关闭和刷新上下文的能力
WebApplicationContext 专门为 Web 应用准备,基于 Web 环境创建 IOC 容器对象,并将对象引入存入 ServletContext 域中

基于xml管理bean

依赖放入父模块

创建新模块spring-ioc-xml

java 复制代码
package com.qcby.spring;

public class User {
    private String name;
    private Integer age;

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

获取bean

①方式一:根据id获取

由于 id 属性指定了 bean 的唯一标识,所以根据 bean 标签的 id 属性可以精确获取到一个组件对象(入门案例)

bean.xml:

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--user对象创建-->
    <bean id="user" class="com.qcby.spring.User"></bean>
</beans>

测试类:

java 复制代码
package com.qcby.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

        //根据id获取bean
        User user = (User) context.getBean("user");
        System.out.println("根据id获取bean:"+user);
    }
}

②方式二:根据类型获取

java 复制代码
package com.qcby.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

        //根据id获取bean
//        User user = (User) context.getBean("user");
//        System.out.println("根据id获取bean:"+user);

        //根据类型获取bean
        User user = context.getBean(User.class);
        System.out.println("根据类型获取bean"+user);
    }
}

当根据类型获取bean时,要求IOC容器中指定类型的bean有且只能有一个

若配置多个,会抛出异常:org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type

③方式三:根据id和类型

java 复制代码
package com.qcby.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");

        //根据id获取bean
//        User user = (User) context.getBean("user");
//        System.out.println("根据id获取bean:"+user);

        //根据类型获取bean
//        User user = context.getBean(User.class);
//        System.out.println("根据类型获取bean"+user);

        //根据id和类型获取bean
        User user = context.getBean("user", User.class);
        System.out.println("根据id和类型获取bean:"+user);

    }
}

扩展:

如果组件类实现了接口,根据接口类型可以获取 bean 吗?

  • 可以,前提是bean唯一
java 复制代码
package com.qcby.spring;

public interface UserDao {
    public void run();
}
java 复制代码
package com.qcby.spring;

public class UserDaoImpl implements UserDao{
    @Override
    public void run() {
        System.out.println("run...");
    }
}
XML 复制代码
 <!--一个接口获取类过程-->
 <bean id="userDaoImpl" class="com.qcby.spring.bean.UserDaoImpl.UserDaoImpl"></bean>
java 复制代码
package com.qcby.spring;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUserDao {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //根据类型获取接口对应bean
        UserDao userDao = context.getBean(UserDao.class);
        System.out.println(userDao);
        userDao.run();
    }
}

如果一个接口有多个实现类,这些实现类都配置了 bean,根据接口类型可以获取 bean 吗?

  • 不行,因为bean不唯一

依赖注入

setter注入

第一步:创建类,生成属性set方法

第二步:在spring配置文件配置

java 复制代码
package com.qcby.spring.di;

public class Book {
    private String bname;
    private String author;

    //无参构造
    public Book() {
    }

    //有参构造
    public Book(String bname, String author) {
        this.bname = bname;
        this.author = author;
    }

    //生成get和set方法
    public void setBname(String bname) {
        this.bname = bname;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getBname() {
        return bname;
    }

    public String getAuthor() {
        return author;
    }

    @Override
    public String toString() {
        return "Book{" +
                "bname='" + bname + '\'' +
                ", author='" + author + '\'' +
                '}';
    }
}
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:cache="http://www.springframework.org/schema/cache"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd">

    <!--set方法注入-->
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <bean id="book" class="com.qcby.spring.di.Book">
        <property name="bname" value="前端开发"></property>
        <property name="author" value="张三"></property>
    </bean>
</beans>
java 复制代码
package com.qcby.spring;


import com.qcby.spring.di.Book;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestBook {
    @Test
    public void testSetter(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean_di.xml");
        Book book = context.getBean("book", Book.class);
        System.out.println(book);
    }

}

构造器注入

第一步:创建类,定义属性,生成有参构造方法

第二步:在spring配置文件配置

XML 复制代码
    <!--构造器注入-->
    <bean id="bookCon" class="com.qcby.spring.di.Book">
        <constructor-arg name="bname" value="java开发"></constructor-arg>
        <constructor-arg name="author" value="李四"></constructor-arg>
    </bean>

注意:

constructor-arg标签还有两个属性可以进一步描述构造器参数:

  • index属性:指定参数所在位置的索引(从0开始)
  • name属性:指定参数名
java 复制代码
    @Test
    public void testCon(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean_di.xml");
        Book book = context.getBean("bookCon", Book.class);
        System.out.println(book);
    }

特殊值处理

字面量赋值

什么是字面量?

int a = 10;

声明一个变量a,初始化为10,此时a不代表字母a,而是作为一个变量的名字。当引用a的时候,实际上拿到的值是10。

而如果a是带引号的:'a',那么它现在不是一个变量,它就是代表a这个字母本身,这就是字面量。所以字面量没有引申含义,就是我们看到的这个数据本身

XML 复制代码
<!-- 使用value属性给bean的属性赋值时,Spring会把value属性的值看做字面量 -->
<property name="name" value="张三"/>

null值

XML 复制代码
<property name="name">
    <null />
</property>

注意:以下写法为name所赋的值是字符串null

XML 复制代码
<property name="name" value="null"></property>

xml实体

XML 复制代码
<!-- 小于号在XML文档中用来定义标签的开始,不能随便使用 -->
<!-- 解决方案一:使用XML实体来代替 -->
<property name="expression" value="a &lt; b"/>

CDATA节

XML 复制代码
<property name="expression">
    <!-- 解决方案二:使用CDATA节 -->
    <!-- CDATA中的C代表Character,是文本、字符的含义,CDATA就表示纯文本数据 -->
    <!-- XML解析器看到CDATA节就知道这里是纯文本,就不会当作XML标签或属性来解析 -->
    <!-- 所以CDATA节中写什么符号都随意 -->
    <value><![CDATA[a < b]]></value>
</property>

特殊类型属性注入

对象类型属性注入

java 复制代码
package com.qcby.spring.ditest;

//部门类
public class Dept {
    private String dname;

    public void info(){
        System.out.println("部门名称:"+dname);
    }

    public void setDname(String dname) {
        this.dname = dname;
    }

    public String getDname() {
        return dname;
    }
}
java 复制代码
package com.qcby.spring.ditest;

//员工类
public class Emp {
    //对象类型属性:员工属于某个部门
    private Dept dept;

    private String ename;
    private Integer age;

    public void work(){
        System.out.println(ename+"emp work..."+age);
        dept.info();
    }

    public Dept getDept() {
        return dept;
    }

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    public String getEname() {
        return ename;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}
方式一:引用外部bean

使用ref属性

XML 复制代码
    <!--方式一:引入外部bean
      1.创建两个类对象:dept emp
      2.在emp的bean标签里,使用property引入dept的bean
    -->
    <bean id="dept" class="com.qcby.spring.ditest.Dept">
        <property name="dname" value="安保部"></property>
    </bean>

    <bean id="emp" class="com.qcby.spring.ditest.Emp">
        <!--普通属性注入-->
        <property name="ename" value="lucy"></property>
        <property name="age" value="50"></property>
        <!--对象属性注入
        ref属性:引用IOC容器中某个bean的id,将所对应的bean为属性赋值-->
        <property name="dept" ref="dept"></property>
    </bean>
方式二:内部bean
XML 复制代码
    <!--方式二:内部bean-->
    <!-- 在一个bean中再声明一个bean就是内部bean -->
    <!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
    <bean id="emp2" class="com.qcby.spring.ditest.Emp">
        <!--普通属性注入-->
        <property name="ename" value="mary"></property>
        <property name="age" value="20"></property>
        <!--对象属性注入-->
        <property name="dept">
            <bean id="dept2" class="com.qcby.spring.ditest.Dept">
                <property name="dname" value="财务部"></property>
            </bean>
        </property>
    </bean>
方式三:级联属性赋值
XML 复制代码
    <!--方式三:级联赋值-->
    <bean id="dept3" class="com.qcby.spring.ditest.Dept">
        <property name="dname" value="研发部"></property>
    </bean>
    <bean id="emp3" class="com.qcby.spring.ditest.Emp">
        <!--普通属性注入-->
        <property name="ename" value="tom"></property>
        <property name="age" value="30"></property>
        <!--对象属性注入-->
        <property name="dept" ref="dept3"></property>
        <property name="dept.dname" value="测试部"></property>
    </bean>

数组类型属性注入

员工类:

java 复制代码
    //爱好
    private String[] loves;

    public String[] getLoves() {
        return loves;
    }

    public void setLoves(String[] loves) {
        this.loves = loves;
    }

    public void work(){
        System.out.println(ename+"emp work..."+age);
        dept.info();
        System.out.println(Arrays.toString(loves));
    }
XML 复制代码
        <!--数组类型属性-->
        <property name="loves">
            <array>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>看电影</value>
            </array>
        </property>

完整的配置文件:

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">


    <bean id="dept" class="com.qcby.spring.ditest.Dept">
        <property name="dname" value="技术部"></property>
    </bean>
    <bean id="emp" class="com.qcby.spring.ditest.Emp">
        <!--普通属性-->
        <property name="ename" value="lucy"></property>
        <property name="age" value="20"></property>
        <!--对象类型属性-->
        <property name="dept" ref="dept"></property>
        <!--数组类型属性-->
        <property name="loves">
            <array>
                <value>吃饭</value>
                <value>睡觉</value>
                <value>看电影</value>
            </array>
        </property>
     </bean>
</beans>

集合类型属性注入

list、set集合类型

Dept类:

java 复制代码
    private List<Emp> empList;
    

    public void info(){
        System.out.println("部门名称:"+dname);
        for (Emp emp : empList) {
            System.out.println(emp.getEname());
        }
    }

    public List<Emp> getEmpList() {
        return empList;
    }

    public void setEmpList(List<Emp> empList) {
        this.empList = empList;
    }

}
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="empone" class="com.qcby.spring.ditest.Emp">
        <property name="ename" value="lucy"></property>
        <property name="age" value="20"></property>
    </bean>

    <bean id="emptwo" class="com.qcby.spring.ditest.Emp">
        <property name="ename" value="mary"></property>
        <property name="age" value="30"></property>
    </bean>

    <bean id="dept" class="com.qcby.spring.ditest.Dept">
        <property name="dname" value="技术部"></property>
        <property name="empList">
            <list>
                <ref bean="empone"></ref>
                <ref bean="emptwo"></ref>
            </list>
        </property>
    </bean>

</beans>

若为Set集合类型属性赋值,只需要将其中的list标签改为set标签即可

map集合类型

Student和Teacher类:

java 复制代码
package com.qcby.spring.dimap;

import java.util.Map;

public class Student {
    private Map<String,Teacher> teacherMap;

    private String sid;
    private String sname;

    public void run(){
        System.out.println("学生编号:"+sid+"学生名称:"+sname);
        System.out.println(teacherMap);
    }


    public Map<String, Teacher> getTeacherMap() {
        return teacherMap;
    }

    public void setTeacherMap(Map<String, Teacher> teacherMap) {
        this.teacherMap = teacherMap;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }
}
java 复制代码
package com.qcby.spring.dimap;

public class Teacher {
    private String teacherId;
    private String teacherName;

    public String getTeacherId() {
        return teacherId;
    }

    public void setTeacherId(String teacherId) {
        this.teacherId = teacherId;
    }

    public String getTeacherName() {
        return teacherName;
    }

    public void setTeacherName(String teacherName) {
        this.teacherName = teacherName;
    }

    @Override
    public String toString() {
        return "Teacher{" +
                "teacherId='" + teacherId + '\'' +
                ", teacherName='" + teacherName + '\'' +
                '}';
    }
}
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
      1.创建两个对象
      2.注入普通类型属性
      3.在学生bean注入map集合类型属性
    -->
    <bean id="teacherone" class="com.qcby.spring.dimap.Teacher">
        <!--注入普通类型属性-->
        <property name="teacherId" value="100"></property>
        <property name="teacherName" value="讲师1"></property>
    </bean>

    <bean id="teachertwo" class="com.qcby.spring.dimap.Teacher">
        <!--注入普通类型属性-->
        <property name="teacherId" value="200"></property>
        <property name="teacherName" value="讲师2"></property>
    </bean>

    <bean id="student" class="com.qcby.spring.dimap.Student">
        <!--注入普通类型属性-->
        <property name="sid" value="2000"></property>
        <property name="sname" value="李四"></property>
        <!--在学生bean注入map集合类型属性-->
        <property name="teacherMap">
            <map>
                <entry>
                    <!--key-->
                    <key>
                        <value>1</value>
                    </key>
                    <!--value为对象-->
                    <ref bean="teacherone"></ref>
                </entry>
                <entry>
                    <!--key-->
                    <key>
                        <value>2</value>
                    </key>
                    <!--value为对象-->
                    <ref bean="teachertwo"></ref>
                </entry>
            </map>
        </property>
    </bean>

</beans>
引用集合类型

Lesson类:

java 复制代码
package com.qcby.spring.dimap;

public class Lesson {
    private String lessonName;

    public String getLessonName() {
        return lessonName;
    }

    public void setLessonName(String lessonName) {
        this.lessonName = lessonName;
    }

    @Override
    public String toString() {
        return "Lesson{" +
                "lessonName='" + lessonName + '\'' +
                '}';
    }
}
java 复制代码
package com.qcby.spring.dimap;

import java.util.List;
import java.util.Map;

public class Student {
    private List<Lesson> lessonList;

    private Map<String,Teacher> teacherMap;

    private String sid;
    private String sname;

    public void run(){
        System.out.println("学生编号:"+sid+"学生名称:"+sname);
        System.out.println(teacherMap);
        System.out.println(lessonList);
    }

    public List<Lesson> getLessonList() {
        return lessonList;
    }

    public void setLessonList(List<Lesson> lessonList) {
        this.lessonList = lessonList;
    }

    public Map<String, Teacher> getTeacherMap() {
        return teacherMap;
    }

    public void setTeacherMap(Map<String, Teacher> teacherMap) {
        this.teacherMap = teacherMap;
    }

    public String getSid() {
        return sid;
    }

    public void setSid(String sid) {
        this.sid = sid;
    }

    public String getSname() {
        return sname;
    }

    public void setSname(String sname) {
        this.sname = sname;
    }
}

使用util:list、util:map标签必须引入相应的命名空间

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"
       xsi:schemaLocation="http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--
      1.创建三个对象
      2.注入普通类型属性
      3.使用util:类型定义
      4.在学生bean引入util:类型定义bean,完成list、map类型属性注入
    -->
    <bean id="lessonone" class="com.qcby.spring.dimap.Lesson">
        <property name="lessonName" value="java"></property>
    </bean>
    <bean id="lessontwo" class="com.qcby.spring.dimap.Lesson">
        <property name="lessonName" value="python"></property>
    </bean>

    <bean id="teacherone" class="com.qcby.spring.dimap.Teacher">
        <property name="teacherId" value="100"></property>
        <property name="teacherName" value="讲师1"></property>
    </bean>
    <bean id="teachertwo" class="com.qcby.spring.dimap.Teacher">
        <property name="teacherId" value="200"></property>
        <property name="teacherName" value="讲师2"></property>
    </bean>

    <bean id="student" class="com.qcby.spring.dimap.Student">
        <property name="sid" value="001"></property>
        <property name="sname" value="lucy"></property>
        <!--注入list、map类型属性-->
        <property name="lessonList" ref="lessonList"></property>
        <property name="teacherMap" ref="teacherMap"></property>
    </bean>
    <util:list id="lessonList">
        <ref bean="lessonone"></ref>
        <ref bean="lessontwo"></ref>
    </util:list>
    <util:map id="teacherMap">
        <entry>
            <key>
                <value>1001</value>
            </key>
            <ref bean="teacherone"></ref>
        </entry>
        <entry>
            <key>
                <value>1002</value>
            </key>
            <ref bean="teachertwo"></ref>
        </entry>
    </util:map>
</beans>

p命名空间

引入p命名空间:

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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/util
       http://www.springframework.org/schema/util/spring-util.xsd
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd">

引入p命名空间后,可以通过以下方式为bean的各个属性赋值:

XML 复制代码
<bean id="studentSix" class="com.qcby.spring6.bean.Student"
    p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMap-ref="teacherMap"></bean>

引入外部属性文件

1.加入依赖

XML 复制代码
<!-- MySQL驱动 -->
<dependency>
    <groupId>mysql</groupId>
    <artifactId>mysql-connector-java</artifactId>
    <version>8.0.30</version>
</dependency>

<!-- 数据源 -->
<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>druid</artifactId>
    <version>1.2.15</version>
</dependency>

2.创建外部属性文件

XML 复制代码
jdbc.user=root
jdbc.password=123456
jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
jdbc.driver=com.mysql.cj.jdbc.Driver

3.配置bean

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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <!--引入外部属性文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>

    <!--完成数据库信息注入-->
    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
</beans>

4.测试

java 复制代码
package com.qcby.spring;

import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestJdbc {
    @Test
    public void demo(){
        ApplicationContext context = new ClassPathXmlApplicationContext("bean_jdbc.xml");
        DruidDataSource dataSource = context.getBean(DruidDataSource.class);
        System.out.println(dataSource.getUrl());
    }
}

bean的作用域

在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围,各取值含义参加下表:

取值 含义 创建对象的时机
singleton(默认) 在IOC容器中,这个bean的对象始终为单实例 IOC容器初始化时
prototype 这个bean在IOC容器中有多个实例 获取bean时

如果是在WebApplicationContext环境下还会有另外几个作用域(但不常用):

取值 含义
request 在一个请求范围内有效
session 在一个会话范围内有效

演示:

1.创建Orders类

2.测试单实例:地址相同

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--通过scope属性配置单实例、多实例-->
    <bean id="orders" class="com.qcby.spring.scope.Orders"
    scope="singleton"></bean>
</beans>
java 复制代码
package com.qcby.spring;

import com.qcby.spring.scope.Orders;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestOrders {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean_scope.xml");
        Orders orders = context.getBean("orders", Orders.class);
        System.out.println(orders);
        Orders orders1 = context.getBean("orders", Orders.class);
        System.out.println(orders1);
    }
}

3.测试多实例:地址不同

XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <!--通过scope属性配置单实例、多实例-->
    <bean id="orders" class="com.qcby.spring.scope.Orders"
    scope="prototype"></bean>
</beans>

bean的生命周期

1.bean对象创建(调用无参构造器)

2.给bean对象设置相关属性

3.bean的后置处理器(初始化之前)

4.bean对象初始化(需在配置bean时指定初始化方法)

5.bean的后置处理器(初始化之后)

6.bean对象就绪可以使用

7.bean对象销毁(需在配置bean时指定销毁方法)

8.IoC容器关闭

演示:

java 复制代码
package com.qcby.spring.life;

public class User {
    private String name;

    //无参构造
    public User() {
        System.out.println("1.bean对象创建,调用无参构造");
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        System.out.println("2.给bean设置属性值");
        this.name = name;
    }

    //初始化的方法
    public void  initMethod(){
        System.out.println("4.bean对象初始化,调用指定的初始化的方法");
    }

    //销毁的方法
    public void destroyMethod(){
        System.out.println("7.bean对象销毁,调用指定的销毁的方法");
    }



}

bean的后置处理器会在生命周期的初始化前后添加额外的操作,需要实现BeanPostProcessor接口,且配置到IOC容器中,需要注意的是,bean后置处理器不是单独针对某一个bean生效,而是针对IOC容器中所有bean都会执行

java 复制代码
package com.qcby.spring.life;

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

public class MyBeanPost implements BeanPostProcessor {
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("3.bean后置处理器,初始化之前执行");
        System.out.println(beanName+"::"+bean);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("5.bean后置处理器,初始化之后执行");
        System.out.println(beanName+"::"+bean);
        return bean;
    }

}
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.qcby.spring.life.User"
    scope="singleton" init-method="initMethod" destroy-method="destroyMethod">
        <property name="name" value="lucy"></property>
    </bean>

    <!-- bean的后置处理器要放入IOC容器才能生效 -->
    <bean id="myBeanProcessor" class="com.qcby.spring.life.MyBeanPost"/>
</beans>
java 复制代码
package com.qcby.spring;

import com.qcby.spring.life.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("bean_life.xml");
        User user = context.getBean("user", User.class);
        System.out.println("6.bean对象创建完成,可以使用");
        System.out.println(user);
        context.close();
    }
}

FactoryBean

FactoryBean是Spring提供的一种整合第三方框架的常用机制。和普通的bean不同,配置一个FactoryBean类型的bean,在获取bean的时候得到的并不是class属性中配置的这个类的对象,而是getObject()方法的返回值。通过这种机制,Spring可以帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们,将来我们整合Mybatis时,Spring就是通过FactoryBean机制来帮我们创建SqlSessionFactory对象的

演示:

java 复制代码
package com.qcby.spring.factorybean;

import org.springframework.beans.factory.FactoryBean;

public class MyFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }

    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user" class="com.qcby.spring.factorybean.MyFactoryBean"></bean>
</beans>
java 复制代码
package com.qcby.spring;

import com.qcby.spring.factorybean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser1 {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean_factorybean.xml");
        User user = (User) context.getBean("user");
        System.out.println(user);
    }
}

基于xml自动装配

自动装配:根据指定的策略,在IOC容器中匹配某一个bean,自动为指定的bean中所依赖的类类型或接口类型属性赋值

使用bean标签的autowire属性设置自动装配效果

1.自动装配方式:byType(找的是class)

byType:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值

若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null

若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常NoUniqueBeanDefinitionException

2.自动装配方式:byName(找的是id)

byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值

byType演示:

java 复制代码
package com.qcby.spring.auto.controller;

import com.qcby.spring.auto.service.UserService;
import com.qcby.spring.auto.service.UserServiceImpl;

public class UserController {

    private UserService userService;

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void addUser(){
        System.out.println("controller中的方法执行了");
        //调用service的方法
        userService.addUserService();

    }
}
java 复制代码
package com.qcby.spring.auto.service;

public interface UserService {
    public void addUserService();
}
java 复制代码
package com.qcby.spring.auto.service;

import com.qcby.spring.auto.dao.UserDao;
import com.qcby.spring.auto.dao.UserDaoImpl;

public class UserServiceImpl implements UserService{
    private UserDao userDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void addUserService() {
        System.out.println("userService中的方法执行了");
        //调用dao中的方法
        userDao.addUserDao();
    }
}
java 复制代码
package com.qcby.spring.auto.dao;

public interface UserDao {
    public void addUserDao();
}
java 复制代码
package com.qcby.spring.auto.dao;

public class UserDaoImpl implements UserDao{
    @Override
    public void addUserDao() {
        System.out.println("userDao中的方法执行了");
    }
}
XML 复制代码
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="userController" class="com.qcby.spring.auto.controller.UserController"
          autowire="byType">
    </bean>

    <bean id="userService" class="com.qcby.spring.auto.service.UserServiceImpl"
          autowire="byType">
    </bean>

    <bean id="userDao" class="com.qcby.spring.auto.dao.UserDaoImpl"></bean>
</beans>
java 复制代码
package com.qcby.spring;


import com.qcby.spring.auto.controller.UserController;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestUser1 {
    public static void main(String[] args) {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean_auto.xml");
        UserController controller = context.getBean("userController", UserController.class);
        controller.addUser();
    }
}
相关推荐
计算机毕设指导62 小时前
基于 SpringBoot 的作业管理系统【附源码】
java·vue.js·spring boot·后端·mysql·spring·intellij-idea
ExiFengs3 小时前
实际项目Java1.8流处理, Optional常见用法
java·开发语言·spring
瓜牛_gn4 小时前
依赖注入注解
java·后端·spring
一元咖啡5 小时前
SpringCloud Gateway转发请求到同一个服务的不同端口
spring·spring cloud·gateway
java亮小白19976 小时前
Spring循环依赖如何解决的?
java·后端·spring
苏-言7 小时前
Spring IOC实战指南:从零到一的构建过程
java·数据库·spring
草莓base7 小时前
【手写一个spring】spring源码的简单实现--容器启动
java·后端·spring
冰帝海岸13 小时前
01-spring security认证笔记
java·笔记·spring
没书读了14 小时前
ssm框架-spring-spring声明式事务
java·数据库·spring
代码小鑫17 小时前
A043-基于Spring Boot的秒杀系统设计与实现
java·开发语言·数据库·spring boot·后端·spring·毕业设计