Spring5 学习笔记(二)

本文详细介绍了Spring框架中的Inversion of Control(IOC)和Dependency Injection(DI)概念,以及如何通过XML配置和注解实现对象创建与属性注入。讲解了BeanFactory和ApplicationContext接口的区别,展示了基于XML配置文件的Bean管理和属性注入,包括set方法注入、有参构造器注入、简化注入、集合注入、级联赋值注入以及外部和内部bean注入。此外,还探讨了FactoryBean、Bean的作用域(singleton和prototype)、生命周期、后置处理器、自动装配、属性文件引入以及基于注解的开发方式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


学习内容来自 B站尚硅谷视频

IOC 概念

IOC 全称 Inversion of Control,也就是控制反转,是面向对象编程的一种设计原则,可以降低代码的耦合度

通俗的说,就是把创建对象、调用对象的过程交给 Spring 进行管理,这样做的目的是为了降低代码的耦合度

学习笔记一的入门案例就是 IOC 实现

IOC 底层原理

主要使用的技术:

  1. XML 解析
  2. 工厂模式
  3. 反射

例子

原始方式,Service 需要关联 Dao,Dao 关联具体类,这样耦合度较高,如果中间有类的路径改变,则需要挨个改变相关联的类
在这里插入图片描述
使用工厂模式解耦合:
在这里插入图片描述
IOC 过程:

  1. 创建 XML 配置文件,配置创建的对象
  2. 创建工厂类,在工厂类中通过解析配置文件获得类的全类名,然后使用反射创建对象实例
    在这里插入图片描述

IOC 接口(BeanFactory)

IOC 主要基于 IOC 容器,而 IOC 容器底层就是对象工厂

Spring 提供 IOC 容器的两种实现方式,即两个接口

  • BeanFactory:IOC 容器基本实现方式,Spring 内部使用接口,不建议开发人员使用

BeanFactory 在加载配置文件的时候并不会创建对象,只有在获取使用对象时才会创建(懒汉式)

  • ApplicationContext:BeanFactory 的子接口,提供更多定制功能,建议开发人员使用

ApplicationContext 在加载配置文件时就会创建对象(饿汉式)

ApplicationContext 实现类

ApplicationContext 有一些实现类:
在这里插入图片描述
其中有两个重要的实现类:

  • FileSystemXmlApplicationContext

使用该实现类加载 Xml 需要制定文件在系统盘中的路径

  • ClassPathXmlApplicationContext

使用该实现类主要是相对于当前项目代码文件的路径,即 src 下的路径

BeanFactory 也有这两个实现类

IOC 操作 Bean 管理

Bean 管理

Bean 管理主要包括两个操作:

  1. Spring 创建对象,如入门案例使用 ApplicationContext 读取配置文件然后创建对象
  2. Spring 注入属性,即根据类的 set 方法设置对象相关属性值

主要包括两种实现方式

  1. 继续 XML 配置文件
  2. 基于注解

基于 XML 配置文件

基于 XML 创建对象

  1. 准备配置文件

在配置文件中使用 bean 标签配置

<bean id="user" class="com.sict.spring5.User" name=""></bean>

bean 标签常用属性

  • id:给对象起一个标识符
  • class:类的全类名
  • name:和 id 功能类似,不过该属性中可以有特殊符号,不常用
  1. 创建对象

创建对象的时候默认使用对象的无参构造器

基于 XML 注入属性

依赖注入

IOC 中有一个概念为 DI,表示依赖注入,也就是注入属性

注入方式有两种:

  • 使用相应属性的 set 方法注入
  • 使用类的有参构造器注入
set 方法注入
  1. 在对象中设置属性的 set 方法
public class Book {

    private String name;
    private String author;

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

    public void setName(String name) {
        this.name = name;
    }
    
}
  1. 在 Spring 配置文件中配置对象创建,以及属性注入
<bean id="book" class="com.sict.spring5.Book">
<!--        使用 property 标签完成属性注入
            name:属性名
            value:属性要注入的值
-->
        <property name="name" value="猎魔人"></property>
        <property name="author" value="杰洛特"></property>
    </bean>
  1. 测试
public void testBook1() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean1.xml");

        Book book = context.getBean("book", Book.class);

        book.testDemo();
    }
有参构造器注入
  1. 设置好有参构造器
public class Order {

    private String name;
    private String address;

    public Order(String name, String address) {
        this.name = name;
        this.address = address;
    }

    public void testDemo() {
        System.out.println(name + ", " + address);
    }
}
  1. 在 Spring 配置文件中配置对象创建,以及属性注入
 <bean id="order" class="com.sict.spring5.Order">
<!--        使用 constructor-arg 标签完成属性注入
            name:属性名
            value:属性要注入的值
-->
        <constructor-arg name="name" value="羊肉汤"></constructor-arg>
        <constructor-arg name="address" value="洛阳"></constructor-arg>
    </bean>
  1. 测试
public void testOrder1() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean1.xml");

        Order order = context.getBean("order", Order.class);

        order.testDemo();
    }
set 注入简化 – p 名称空间注入

配置文件头部依赖加上

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

在这里插入图片描述
在配置文件中配置创建对象方式:

<bean id="book" class="com.sict.spring5.Book" p:author="单的列宁" p:name="66666"></bean>

这里使用标签 p:属性名=属性值 注入对应属性

xml 注入其他类型数据
null 值

在配置文件中配置属性时,可以通过以下方法将属性设置为空值

	<bean id="book" class="com.sict.spring5.Book">
		<property name="publish">
            <null></null>
        </property>
    </bean>
带特殊符号的内容

在配置文件中配置属性时,属性值中不可以包含特殊符号(如 “<” 、 “>”)可以通过以下方法使属性值包含特殊符号

  1. 使用转义字符代替,如 &lt; &gt;表示 “<” 、 “>”
  2. 把带特殊符号的内容写到 <![CDATA[特殊内容]]>
<bean id="book" class="com.sict.spring5.Book">
<!--        属性值包含特殊符号
            1. 在特殊符号前加上转义 &lt; &gt;
            2. 把带特殊符号的内容写到 <![CDATA[特殊内容]]>-->
        <property name="author">
            <value><![CDATA[<<南京>>]]></value>
        </property>
    </bean>
注入属性–外部 bean

假设现在有两个类:service 类和 dao 类
其中,service 类中调用 dao 类中的方法

dao 接口

public interface UserDao {
    void update();
}

dao 实现类

public class UserDaoImpl implements UserDao{

    @Override
    public void update() {
        System.out.println("dao update sth");
    }
}

service 类

public class UserService {

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

        // 创建 UserDao 对象
        // 常规方法
        UserDao userDao = new UserDaoImpl();
        userDao.update();
    }
}

也可以在 spring 配置文件中进行配置
首先,需要更改 service 类,加上属性 UserDao

public class UserService {

    private UserDao userDao;

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

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


        // 创建 UserDao 对象
        // 常规方法
        UserDao userDao = new UserDaoImpl();
        userDao.update();
        
        userDao.update();
    }
}

然后在配置文件中配置:

<!--    service 和 dao 对象创建-->
    <bean id="userService" class="com.sict.spring5.service.UserService">
<!--    注入 userDao 对象
        name 属性名
        ref 属性值对应的对象在配置文件中的 id
-->
        <property name="userDao" ref="userDao"></property>
    </bean>

编写测试:

public void testAdd() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean2.xml");

        UserService userService = context.getBean("userService", UserService.class);

        userService.add();

    }
注入属性–内部 bean

假设现在有两个类

部门类

public class Dept {

    private String name;

    public void setName(String name) {
        this.name = name;
    }
}

员工类

public class Empl {

    private String name;
    private String gender;
    // 员工所属部门
    private Dept dept;

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

    public void setName(String name) {
        this.name = name;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
    

    public void add() {
        System.out.println(name + ", " + gender + ", " + dept);
    }
}

其中,一个部门可以有多个员工,这两个类是一对多的关系

于是可以在 spring 配置文件中进行如下配置:

<bean id="emp" class="com.sict.spring5.bean.Empl">
<!--        设置普通属性(字面量属性) name 和 gender-->
        <property name="gender" value="男"/>
        <property name="name" value="jerry"/>
<!--        设置对象属性-->
        <property name="dept">
<!--            内部 bean-->
            <bean id="dept" class="com.sict.spring5.bean.Dept">
                <property name="name" value="系统集成"/>
            </bean>
        </property>
    </bean>

这里使用内部 bean 配置对象属性

编写测试代码

@Test
    public void testBean2() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean3.xml");

        Empl emp = context.getBean("emp", Empl.class);

        emp.add();
    }
注入属性–级联赋值

级联赋值就是给属性的属性赋值

首先,需要在有对应属性的属性的 get 方法

修改员工类如下,添加了 dpet 的 get 方法:

public class Empl {

    private String name;
    private String gender;
    // 员工所属部门
    private Dept dept;

    public Dept getDept() {
        return dept;
    }

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

    public void setName(String name) {
        this.name = name;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }

    public void add() {
        System.out.println(name + ", " + gender + ", " + dept);
    }
}

在配置文件中配置:

<bean id="emp" class="com.sict.spring5.bean.Empl">
        <!--        设置普通属性(字面量属性) name 和 gender-->
        <property name="gender" value="男"/>
        <property name="name" value="jerry"/>
        <!--        级联赋值 设置对象属性-->
        <property name="dept" ref="dept"/>
        <property name="dept.name" value="办公室"/>
    </bean>

    <bean id="dept" class="com.sict.spring5.bean.Dept">
        <property name="name" value="School"/>
    </bean>
注入属性–集合
  • 注入数组类型
  • 注入 List 集合
  • 注入 Set 集合

假设有一个类 Stu

public class Stu {
    private String[] courses;
    private Set<String> friends;
    private List<String> bills;
    private Map<String, Integer> score;

    public void testBean() {
        for (String cours : courses) {
            System.out.println(cours + " ");
        }
        System.out.println();
        for (String friend : friends) {
            System.out.println(friend + " ");
        }
        System.out.println();
        for (String bill : bills) {
            System.out.println(bill + " ");
        }
        System.out.println();
        score.forEach((s, integer) -> System.out.println(s + ": " + integer));
    }

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setFriends(Set<String> friends) {
        this.friends = friends;
    }

    public void setBills(List<String> bills) {
        this.bills = bills;
    }

    public void setScore(Map<String, Integer> score) {
        this.score = score;
    }
}

编写配置文件:

<!--    集合类型注入-->
    <bean id="stu" class="com.sict.spring5.collectionType.Stu">
<!--        数组类型注入-->
        <property name="courses">
            <array>
                <value>计算机组成原理</value>
                <value>计算机系统结构</value>
            </array>
        </property>
<!--        set 类型注入-->
        <property name="friends">
            <set>
                <value>张三</value>
                <value>李四</value>
            </set>
        </property>
<!--        list 类型注入-->
        <property name="bills">
            <list>
                <value>刚刚花了一块钱</value>
                <value>现在花了五块钱</value>
            </list>
        </property>
<!--        map 类型注入-->
        <property name="score">
            <map>
                <entry key="数据结构" value="66"/>
                <entry key="算法设计" value="76"/>
            </map>
        </property>
    </bean>

编写测试代码

public void testBead01() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean1.xml");

        Stu stu = context.getBean("stu", Stu.class);

        stu.testBean();
    }
集合中注入对象类型

在上面的例子中,集合中存储的都是字符串或者基本类型这些字面量,如果集合中存储的是对象的话,需要用如下方法进行配置

假设现在有一个课程类:

public class Course {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "Course{" +
                "name='" + name + '\'' +
                '}';
    }
}

修改类 Stu 为:

public class Stu {
    private String[] courses;
    private Set<String> friends;
    private List<String> bills;
    private Map<String, Integer> score;
    private List<Course> courseList;

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

    public void testBean() {
        for (Course cours : courseList) {
            System.out.println(cours + " ");
        }
        System.out.println();
        for (String friend : friends) {
            System.out.println(friend + " ");
        }
        System.out.println();
        for (String bill : bills) {
            System.out.println(bill + " ");
        }
        System.out.println();
        score.forEach((s, integer) -> System.out.println(s + ": " + integer));
    }

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setFriends(Set<String> friends) {
        this.friends = friends;
    }

    public void setBills(List<String> bills) {
        this.bills = bills;
    }

    public void setScore(Map<String, Integer> score) {
        this.score = score;
    }
}

于是配置 courseList 方法为:

<!--    集合类型注入-->
    <bean id="stu" class="com.sict.spring5.collectionType.Stu">
<!--        数组类型注入-->
        <property name="courses">
            <array>
                <value>计算机组成原理</value>
                <value>计算机系统结构</value>
            </array>
        </property>
<!--        set 类型注入-->
        <property name="friends">
            <set>
                <value>张三</value>
                <value>李四</value>
            </set>
        </property>
<!--        list 类型注入-->
        <property name="bills">
            <list>
                <value>刚刚花了一块钱</value>
                <value>现在花了五块钱</value>
            </list>
        </property>
<!--        map 类型注入-->
        <property name="score">
            <map>
                <entry key="数据结构" value="66"/>
                <entry key="算法设计" value="76"/>
            </map>
        </property>
<!--        list 类型注入对象-->
        <property name="courseList">
            <list>
                <ref bean="course01"/>
                <ref bean="course02"/>
                <ref bean="course03"/>
                <ref bean="course04"/>
            </list>
        </property>
    </bean>
    
    <bean id="course01" class="com.sict.spring5.collectionType.Course">
        <property name="name" value="数据结构"/>
    </bean>
    <bean id="course02" class="com.sict.spring5.collectionType.Course">
        <property name="name" value="算法设计"/>
    </bean>
    <bean id="course03" class="com.sict.spring5.collectionType.Course">
        <property name="name" value="组成原理"/>
    </bean>
    <bean id="course04" class="com.sict.spring5.collectionType.Course">
        <property name="name" value="操作系统"/>
    </bean>
提取集合注入部分

将配置文件中集合配置部分提取出来,作为一个公共部分

现在有一个类 Extraction

public class Extraction {
    private List<String> list;

    public void setList(List<String> list) {
        this.list = list;
    }
}
  1. 首先,需要在 spring 配置文件头部引入名称空间 util
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">

  1. 使用 util 标签完成 list 集合初始化
<!--提取 list 集合作为公共部分-->
    <util:list id="extractList">
<!--        如果元素是对象,需要使用标签 <ref> -->
        <value>杰瑞狗</value>
        <value>jerry dog</value>
        <value>Jerry</value>
    </util:list>
  1. 注入提取后的 list 集合作为属性
<!--    注入公共部分的 list 集合-->
    <bean id="extract" class="com.sict.spring5.collectionType.Extraction">
        <property name="list" ref="extractList"/>
    </bean>

这样就完成了 list 集合的提取和注入

FactoryBean

Spring 有两种类型的 bean,一种是普通 bean,一种是 FactoryBean

  • 普通 bean 就是之前提到的配置文件,在配置文件中 <bean> 标签的属性 class 对应的就是要返回类的全类名
  • FactoryBean 配置中的定义类型与返回类型可以不一致
使用方式
  1. 创建类,让该类作为 FactoryBean(工厂 bean),实现接口 FactoryBean
  2. 实现接口里的方法,在实现的方法中定义返回的 bean 的类型
public class MyBean implements FactoryBean<Course> {

    // 定义返回 bean 的类型
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setName("abc");
        return course;
    }

    @Override
    public Class<?> getObjectType() {
        return Course.class;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

然后在配置文件中配置工厂 bean

<bean id="myBean" class="com.sict.spring5.factoryBean.MyBean">
    </bean>

编写测试

public void testBead03() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean3.xml");

        Course myBean = context.getBean("myBean", Course.class);

        System.out.println(myBean);
    }

输出结果:

Course{name='abc'}

Bean 的作用域

在 Spring 里面,可以设置创建 bean 实例是单实例还是多实例
默认情况下,都是单实例

比如,之前提到的 Extraction 类的测试,修改为下:

public void testBead02() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean2.xml");

        Extraction extract1 = context.getBean("extract", Extraction.class);
        Extraction extract2 = context.getBean("extract", Extraction.class);

        System.out.println(extract1);
        System.out.println(extract2);
    }

输出结果:

com.sict.spring5.collectionType.Extraction@2a65fe7c
com.sict.spring5.collectionType.Extraction@2a65fe7c

可以看到两个对象地址一致,也就是说明返回的 bean 是单实例的

单实例、多实例设置方法

在配置文件中 bean 标签中有属性 scope 用于设置单实例还是多实例

scope 有两个值可以设置:

  • singleton 表示单实例,默认值
  • prototype 表示多实例

于是可以配置文件中写上:

<!--提取 list 集合作为公共部分-->
    <util:list id="extractList">
<!--        如果元素是对象,需要使用标签 <ref> -->
        <value>杰瑞狗</value>
        <value>jerry dog</value>
        <value>Jerry</value>
    </util:list>

<!--    注入公共部分的 list 集合-->
    <bean id="extract" class="com.sict.spring5.collectionType.Extraction" scope="prototype">
        <property name="list" ref="extractList"/>
    </bean>

重新运行测试代码,结果为:

com.sict.spring5.collectionType.Extraction@2a65fe7c
com.sict.spring5.collectionType.Extraction@4135c3b

可以看到两个对象地址不同,也就是返回两个不一样的对象

singleton 和 prototype 区别
  • singleton 单实例、prototype 多实例
  • scope 为 singleton,加载 spring 配置文件的时候就会创建单实例对象
  • scope 为 prototype,调用 getBean() 方法时才会创建对象
bean 生命周期

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

bean 的生命周期包含:

  1. 通过参数构造器(无参构造器)创建 bean 实例
  2. 为 bean 的属性设置值或对其它 bean 的引用(调用 set 方法)
  3. 调用 bean 的初始化方法(需要进行配置)
  4. 使用 bean
  5. 容器关闭时,调用销毁 bean 的销毁方法(需要进行配置)

代码演示:

  1. 先创建一个 Orders 类
public class Orders {
    private String name;

    public void setName(String name) {
        this.name = name;
        System.out.println("2. set 方法被调用,用来设置值");
    }

    public Orders() {
        System.out.println("1. 无参构造器被调用,用来创建 bean 实例");
    }

    // 创建 bean 执行的初始化的方法
    public void initMethod() {
        System.out.println("3. 执行初始化的方法");
    }

    // 销毁 bean 执行的销毁方法
    public void destoryMethod() {
        System.out.println("5. 执行销毁方法");
    }
}
  1. 配置 bean
<!--   init-method 即初始化方法 
        destroy-method 即销毁方法
        -->
    <bean id="orders" class="com.sict.spring5.bean.Orders" init-method="initMethod" destroy-method="destoryMethod">
        <property name="name" value="饺子"/>
    </bean>
  1. 编写测试代码
public void testBead04() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean4.xml");

        Orders orders = context.getBean("orders", Orders.class);
        System.out.println("4. 使用 bean");
        System.out.println(orders);

        // 手动销毁 bean 实例
        // close 方法是 ClassPathXmlApplicationContext 类的方法,需要强转
        ((ClassPathXmlApplicationContext) context).close();
    }

输出结果为:

1. 无参构造器被调用,用来创建 bean 实例
2. set 方法被调用,用来设置值
3. 执行初始化的方法
4. 使用 bean
com.sict.spring5.bean.Orders@515aebb0
5. 执行销毁方法
bean 的后置处理器

bean 的生命周期还有更完整的两个步骤(bean 的后置处理器),补充之前的步骤后如下:

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

添加的代码演示:

  1. 添加自定义的 bean 后置处理器类,实现 BeanPostProcessor 接口
public class MyBeanPostProcessor implements BeanPostProcessor {
    @Override
    // 初始化之前调用的方法
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之前执行的方法");
        return bean;
    }

    @Override
    // 初始化之后调用的方法
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后执行的方法");
        return bean;
    }
}
  1. 在配置文件中配置后置处理器,该后置处理器应用于整个配置文件
<!--    配置后置处理器-->
    <bean id="myBeanPostProcessor" class="com.sict.spring5.bean.MyBeanPostProcessor"></bean>

执行测试代码后的结果为:

1. 无参构造器被调用,用来创建 bean 实例
2. set 方法被调用,用来设置值
初始化之前执行的方法
3. 执行初始化的方法
初始化之后执行的方法
4. 使用 bean
com.sict.spring5.bean.Orders@6c64cb25
5. 执行销毁方法

XML 自动装配

之前提到的配置方法,通过指定属性名称和值配置初始化 bean 实例的方法就是手动配置

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

bean 标签有属性 autowire,配置自动装配

autowire 有两个常用属性值:

  • byName 根据属性名称注入,注入值 bean 的 id 值和类的属性名称要一致
  • byType 根据属性类型注入
根据属性名称自动装配

假设有两个类:

public class Dept {

    @Override
    public String toString() {
        return "Dept{}";
    }
}
public class Emp {
    private Dept dept;

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

    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                '}';
    }

    public void test() {
        System.out.println(dept);
    }
}

在配置文件中配置:

	<bean id="dept" class="com.sict.spring5.autowire.Dept">

    </bean>


    <!--        实现自动装配
                 bean 标签有属性 autowire,配置自动装配
                 autowire 有两个常用属性值:
                    byName 根据属性名称注入,注入值 bean 的 id 值和类的属性名称要一致
                    byType 根据属性类型注入
        -->
    <bean id="emp" class="com.sict.spring5.autowire.Emp" autowire="byName">
<!--        手动装配-->
<!--        <property name="dept" ref="dept"/>-->
    </bean>

编写测试:

public void testBead05() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean5.xml");

        Emp emp = context.getBean("emp", Emp.class);
        System.out.println(emp);

    }
根据属性类型自动装配

在配置文件中进行配置:

	<bean id="dept" class="com.sict.spring5.autowire.Dept">

    </bean>


    <!--        实现自动装配
                 bean 标签有属性 autowire,配置自动装配
                 autowire 有两个常用属性值:
                    byName 根据属性名称注入,注入值 bean 的 id 值和类的属性名称要一致
                    byType 根据属性类型注入
        -->
    <bean id="emp" class="com.sict.spring5.autowire.Emp" autowire="byType">
<!--        手动装配-->
<!--        <property name="dept" ref="dept"/>-->
    </bean>

注意,根据属性类型自动装配,在配置文件中只能由一个对应类型的 bean,如果有多个将会出错

引入外部属性文件

在配置文件中可以引入外部文件来配置属性

比如配置 druid 数据库连接池有两种方式

  • 直接配置数据库信息
<!--    直接配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.driver"/>
        <property name="url" value="jdbc:mysql://localhost/userDb"/>
        <property name="username" value="root"/>
        <property name="password" value="root"/>
    </bean>
  • 引入外部属性文件配置数据库连接池

先在配置文件头部引入 context 名称空间

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

准备一个 properties 文件在 src 目录下:

prop.driverClass=com.mysql.jdbc.Driver
prop.url=com.mysql.jdbc.driver
prop.username=root
prop.password=root

然后在配置文件中引入:

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

<!--    配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${prop.driverClass}"/>
        <property name="url" value="${prop.url}"/>
        <property name="username" value="${prop.username}"/>
        <property name="password" value="${prop.password}"/>
    </bean>

基于注解方式

什么是注解

  • 注解是代码特殊标记,格式@注解名称(属性名称=属性值...)
  • 注解可以作用在类、方法、属性上面
  • 注解的目的是为了简化 XML 配置

Spring 针对 Bean 管理提供了四种注解:

  • @component 普通组件
  • @Service 用在 service 层或者业务逻辑层
  • @Controller 用在 web 层
  • @Repository 用在 dao 层或者持久层

这四个注解都可以用来创建 bean 实例,不用注解一般用在不同层中

基于注解创建对象

  1. 引入依赖在这里插入图片描述

  2. 开启组件扫描,使 Spring 扫描加注解的类

引入 context 名称空间

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns: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:component-scan base-package="com.sict.spring5.dao, com.sict.spring5.service"/>-->
<!--    也可以直接写上层目录-->
    <context:component-scan base-package="com.sict.spring5"/>
  1. 创建类,在类名上加上注解
//  等价于 <bean id="userService" class="..."/>
//    value 属性值可以忽略,默认值为 首字母小写后的类名称
@Service(value = "userService")
public class UserService {

    public void add() {
        System.out.println("service add....");
    }
}
  1. 编写测试代码
public void testService() {
        ApplicationContext context =
                new ClassPathXmlApplicationContext("bean1.xml");

        UserService userService = context.getBean("userService", UserService.class);

        userService.add();
    }

输出结果:

service add....

组件扫描的细节配置

在上面的例子中,开启组件扫描时会扫描包下所有的类

实际上可以配置具体扫描的类

<!--    示例 1
    use-default-filters="false" 表示不使用默认扫描规则,即不使用全包扫描
    context:include-filter 表示要扫描的内容
-->
    <context:component-scan base-package="com.sict" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>


<!--    示例 2
    默认扫描全包
    context:exclude-filter 表示不进行扫描的内容
-->
    <context:component-scan base-package="com.sict">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

即默认规则即为全包扫描,可以通过use-default-filters="false" 关闭全包扫描,然后通过context:include-filter 表示要扫描的内容;

也可以在全包扫描时通过context:exclude-filter过滤不进行扫描的内容

通过注解实现属性注入

三种常用的属性注入的注解为:

  • @AutoWired 根据属性类型自动注入
  • @Qualifier 根据属性名称自动注入
  • @Resource 可以根据属性类型,也可根据属性名称
  • @Value 注入字面量
@AutoWired
  1. 创建 service 和 dao 类,在类中加入对象注解
@Service(value = "userService")
public class UserService {

    public void add() {
        System.out.println("service add....");
    }
}
@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("dao add...");
    }
}
  1. 在 service 添加 dao 属性,在属性上加上注解
@Service(value = "userService")
public class UserService {

	// 使用该注解不需要加上 set 方法
    @Autowired
    private UserDao userDao;

    public void add() {
        userDao.add();
        System.out.println("service add....");
    }
}
@Qualifier

该注解需要和 @Autowired 一起使用

在上面的例子中,如果属性对应接口有多个实现类,就可能会引发错误

这时候就可以使用 @Qualifier 注解指定具体实现类

首先给 UserDao 加上自定义名称

@Repository(value = "userDaoImpl1")
public class UserDaoImpl implements UserDao{
    @Override
    public void add() {
        System.out.println("dao add...");
    }
}

然后在 UserService 中加上 @Qualifier 注解

//  等价于 <bean id="userService" class="..."/>
//    value 属性值可以忽略,默认值为 首字母小写后的类名称
@Service(value = "userService")
public class UserService {

    @Autowired
    @Qualifier(value = "userDaoImpl1")
    private UserDao userDao;

    public void add() {
        userDao.add();
        System.out.println("service add....");
    }
}
@Resource

直接在属性上加上 @Resource 注解,默认即为根据类型注入

@Service(value = "userService")
public class UserService {

    // 根据类型注入
    @Resource
    private UserDao userDao;

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

如果在 @Resource 后面加上属性 name 那么即为根据名称注入

@Service(value = "userService")
public class UserService {
    // 根据名称注入
    @Resource(name = "userDaoImpl1")
    private UserDao userDao;

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

注意,@Resource 注解不是 spring 官方的包,而是 javax.annotation 包下

@Value

修改 UserService 类

@Service(value = "userService")
public class UserService {

    // 根据名称注入
    @Resource(name = "userDaoImpl1")
    private UserDao userDao;
	
	// 注入字符串 abc
    @Value(value = "abc")
    private String name;

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

全注解开发

即不使用配置文件,仅使用注解开发

步骤如下:

  1. 创建配置类,替代配置文件
@Configuration  // 加上该注解,该类即为配置类,可以替代 xml 配置文件
@ComponentScan(basePackages = {"com.sict"}) // 开启组件扫描
public class SpringConfig {

}
  1. 和之前步骤一致,创建 service 和 dao 类,加上相应注解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

三更鬼

谢谢老板!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值