Spring - IoC篇

21 篇文章 0 订阅

Spring IoC



1. Spring核心之IoC控制反转

1.1 IoC的概念

  • IoCInversion of Control,即“控制反转”,不是什么技术,而是一种设计思想。
  • IoC是指在程序开发中,实例的创建不再由调用者管理,而是由Spring容器创建。Spring容器会负责控制程序之间的关系,而不是由程序代码直接控制,因此,控制权由程序代码转移到了Spring容器中,控制权发生了反转,这就是Spring的IoC思想。
  • Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从IoC容器中取出需要的对象。
  • 创建实例/对象:构造方法new、反射、克隆、序列化、动态代理

1.2 Spring入门案例

1.2.1 创建maven项目
  • 创建完整的目录结构 - 此处只需要创建一个Maven项目即可.

在这里插入图片描述

1.2.2 pom.xml文件添加依赖和插件
<dependencies>
    <!--单元测试-->
    <dependency>
        <groupId>junit</groupId>
        <artifactId>junit</artifactId>
        <version>4.12</version>
        <scope>test</scope>
    </dependency>
    <!--spring依赖-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.2.13.RELEASE</version>
    </dependency>
</dependencies>
<build>
    <plugins>
        <!--编译插件-->
        <plugin>
            <groupId>org.apache.maven.plugins</groupId>
            <artifactId>maven-compiler-plugin</artifactId>
            <version>3.8.0</version>
            <configuration>
                <source>1.8</source>
                <target>1.8</target>
            </configuration>
        </plugin>
    </plugins>
</build>
1.2.3 创建一个实体类
/**
 * 球队实体类
 *
 * @author murphy
 * @since 2021/6/19 4:25 下午
 */
public class Team {
    private Integer id;
    private String name;
    private String location;

    public Team() {
        System.out.println("Team - 默认构造方法:id=" + id + ",name=" + name + ",location=" + location);
    }
}
1.2.4 创建Spring的配置文件applicationContext.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">
    <!--
        Spring 配置文件:
        beans:根标签 - Spring中Java的对象称为Java Bean
        spring-beans.xsd:约束文件 - 约束XML文件中能编写哪些标签
     -->

    <!--
        创建对象:声明bean,告知Spring容器创建哪些对象 - 一个bean标签表示一个对象
        id = "对象名" - 要求唯一值
        class = "完全限定名" - Spring底层通过反射方式创建对象,不能写接口
        相当于 com.murphy.pojo.Team team1 = new com.murphy.pojo.Team();
        然后将创建的对象放入Spring容器的一个集合Map中
        springMap.put(id,对象) - 例如:springMap.put("team1", new Team());
    -->
    <bean id="team1" class="com.murphy.pojo.Team" />
    <bean id="team2" class="com.murphy.pojo.Team" />

    <!-- 非自定义对象的创建 -->
    <bean id="date1" class="java.util.Date"/>
</beans>
1.2.5 使用Spring容器创建对象

配置文件中创建对象,代码如上

<bean id="team1" class="com.murphy.pojo.Team" />
<bean id="team2" class="com.murphy.pojo.Team" />
1.2.6 获取Spring容器

Spring 提供了两种 IoC 容器,分别为BeanFactoryApplicationContext.

1.2.6.1 BeanFactory
  • BeanFactory是基础类型的 IoC 容器,是一个管理Bean的工厂,它主要负责初始化各种Bean,并调用它们的生命周期方法。
  • BeanFactory接口有多个实现类,最常见的是org.Springframework.beans.factory.xml.XmlBeanFactory,它是根据XML配置文件中的定义装配Bean的。
BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource(Spring配置文件的名称 - 全路径));
1.2.6.2 ApplicationContext
  • ApplicationContext是BeanFactory的子接口,也被称为应用上下文。它不仅提供了BeanFactory的所有功能,还添加了对i18n(国际化)、资源访问、事件传播等方面的良好支持。
  • ApplicationContext接口有两个常用的实现类

1.2.6.2.1 ClassPathXmlApplicationContext —— 常用

  • 该类从类路径ClassPath中寻找指定的XML配置文件,找到并装载完成ApplicationContext的实例化工作
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(Spring配置文件的名称);

1.2.6.2.2 FileSystemXmlApplicationContext

  • 它与ClassPathXmlApplicationContext的区别是:在读取Spring的配置文件时,FileSystemXmlApplicationContext不再从类路径中读取配置文件,而是通过参数指定配置文件的位置,它可以获取类路径之外的资源,如“D:\application.xml”。
ApplicationContext applicationContext = new FileSystemXmlApplicationContext(String configLocation);
1.2.7 通过上下文对象获取容器中的对象
import com.murphy.pojo.Team;
import org.junit.Test;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.xml.XmlBeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.springframework.core.io.FileSystemResource;

/**
 * 测试类
 *
 * @author murphy
 * @since 2021/6/19 4:27 下午
 */
public class Test01 {
    @Test
    public void test01(){
        System.out.println("原有写法:");
        // 原有写法:自己创建对象
        Team team = new Team();
        // Spring容器创建对象的方式
        String springConfig = "applicationContext.xml";
        // 1. 获取容器
        // 1.1 方式一 - 推荐使用
        System.out.println("ApplicationContext:");
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);
        // 从容器中根据ID获取对象 - 默认Object类型
        Team team1 = (Team) applicationContext.getBean("team1");
        // 1.2 方式二 - 已过时,不推荐
        System.out.println("BeanFactory:");
        BeanFactory beanFactory = new XmlBeanFactory(new FileSystemResource("配置文件全路径"));
        // 根据ID从IoC容器中获取对象 - Object类型
        beanFactory.getBean("team1");
        // 1.3 方式三 - ApplicationContext
        ApplicationContext applicationContext1 = new FileSystemXmlApplicationContext("配置文件全路径");
      
				// 2. 容器中的其他API
        // 获取bean定义的数量
        int beanDefinitionCount = applicationContext.getBeanDefinitionCount();
        System.out.println("容器中的对象的个数:" + beanDefinitionCount);

        System.out.println("容器中所有对象的名称:");
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName + "\t");
        }

        // 3. 获取非自定义的对象
        Date date1 = (Date) applicationContext.getBean("date1");
        System.out.println("获取非自定义的对象date = " + date1);
    }
}
1.2.8 创建非自定义对象
<!--创建非自定义的对象-->
<bean id="date1" class="java.util.Date"></bean>

// 获取非自定义的对象 - 测试方法
Date date1 = (Date) applicationContext.getBean("date1");
System.out.println("获取非自定义的对象date = " + date1);
1.2.9 Bean标签的属性

在这里插入图片描述

示例演示:

Team 实体类补充如下方法:

public void init(){
    System.out.println("Team - init() ---");
}

public void destroy(){
    System.out.println("Team - destroy() ---");
}

applicationContext.xml补充的Bean属性及运用:

		<!--
        scope = "singleton / prototype"
        singleton: 单例,默认值,容器启动完成之后单例对象就被创建了,而且容器中只有唯一的一个对象,每次获取都是单一对象
        prototype: 多例,多例的对象在每次获取的时候都创建新对象

        lazy-init = "true / false" - 是否懒加载,默认值false,针对单例对象
            true: 懒加载,获取对象的时候才创建对象
            false: 不懒加载,立即创建对象,不管是否使用

        生命周期相关:
        init-method = "对象创建完毕之后立即调用的初始化方法"
        destroy-method = "spring容器调用销毁方法时执行的方法"
    -->
    <bean id="team1" name="team1" class="com.murphy.pojo.Team" scope="singleton" />
    <bean id="team2" name="team2" class="com.murphy.pojo.Team" scope="prototype" />
    <bean id="team3" name="team3" class="com.murphy.pojo.Team" scope="singleton" lazy-init="true" init-method="init" destroy-method="destroy"/>

测试类:

@Test
public void test02(){
    String springConfig = "applicationContext.xml";
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext(springConfig);
    Team team1 = (Team) applicationContext.getBean("team1");
    Team team11 = (Team) applicationContext.getBean("team1");
    System.out.println(team1);
    System.out.println(team11);
    Team team2 = (Team) applicationContext.getBean("team2");
    Team team22 = (Team) applicationContext.getBean("team2");
    System.out.println(team2);
    System.out.println(team22);

    Team team3 = (Team) applicationContext.getBean("team3");
    System.out.println(team3);
    applicationContext.close();
}

图解说明:

  1. scope="singleton/prototype" - 单例模式多次取值对象单一,只创建一次对象 / 多例模式每次取值都要创建新对象

在这里插入图片描述

  1. lazy-init = "true/false" - 针对单例模式,是否懒加载
  • 懒加载true - 获取对象的时候才创建对象

在这里插入图片描述

  • 非懒加载false - 立即创建对象,不管是否使用,默认值

在这里插入图片描述

  1. init-method - 对象创建完毕之后立即调用的初始化方法 / destroy-method - spring容器调用销毁方法时执行的方法

在这里插入图片描述

1.2.10 Bean的作用域

在这里插入图片描述

1.3 Spring容器创建对象的方式

1.3.1 使用默认的构造方法
<!-- 1. 通过默认构造方法 -->
<bean id="team1" class="com.murphy.pojo.Team"/>
1.3.2 使用带参数的构造方法
<!-- 2. 通过带参数的构造方法 -->
<!-- 方式1:根据参数的属性名称 -->
<bean id="team2" class="com.murphy.pojo.Team">
    <constructor-arg name="id" value="1001"/>
    <constructor-arg name="name" value="Warriors"/>
    <constructor-arg name="location" value="Oakland"/>
</bean>
<!-- 方式2:根据参数的下标索引 -->
<bean id="team3" class="com.murphy.pojo.Team">
    <constructor-arg index="0" value="1002"/>
    <constructor-arg index="1" value="Heat"/>
    <constructor-arg index="2" value="Miami"/>
</bean>
1.3.3 使用工厂类
<!-- 3. 通过工厂方法:实例方法 / 静态方法 -->
<!-- 3.1 实例方法 -->
<bean id="factory" class="com.murphy.pojo.MyFactory"/>
<bean id="instanceTeam" factory-bean="factory" factory-method="instanceFun"/>
<!-- 3.2 静态方法 -->
<bean id="staticTeam" class="com.murphy.pojo.MyFactory" factory-method="staticFun"/>

三种方式的案例如下:

Team.java类中添加带参数构造方法:

public Team(Integer id, String name, String location) {
    this.id = id;
    this.name = name;
    this.location = location;
    System.out.println("Team - 带参数的构造方法:id=" + id + ",name=" + name + ",location=" + location);
}

创建工厂类MyFactory.java

/**
 * 工厂方法
 *
 * @author murphy
 */
public class MyFactory {
    /**
     * 实例方法
     * @return
     */
    public Team instanceFun() {
        System.out.println("MyFactory - instanceFun()");
        return new Team(1003,"Net","Brooklyn");
    }

    /**
     * 静态方法
     * @return
     */
    public static Team staticFun() {
        System.out.println("MyFactory - staticFun()");
        return new Team(1004,"Lakers","Los Angels");
    }

    public static void main(String[] args) {
        MyFactory factory = new MyFactory();
        Team team = factory.instanceFun();
        MyFactory.staticFun();
    }
}

创建新的配置文件createType.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">

    <!--
        Spring容器创建对象的方式
        1. 通过默认构造方法
        2. 通过带参数的构造方法
        3. 通过工厂方法:实例方法 / 静态方法
     -->

    <!-- 1. 通过默认构造方法 -->
    <bean id="team1" class="com.murphy.pojo.Team"/>
    <!-- 2. 通过带参数的构造方法 -->
    <!-- 方式1:根据参数的属性名称 -->
    <bean id="team2" class="com.murphy.pojo.Team">
        <constructor-arg name="id" value="1001"/>
        <constructor-arg name="name" value="Warriors"/>
        <constructor-arg name="location" value="Oakland"/>
    </bean>
    <!-- 方式2:根据参数的下标索引 -->
    <bean id="team3" class="com.murphy.pojo.Team">
        <constructor-arg index="0" value="1002"/>
        <constructor-arg index="1" value="Heat"/>
        <constructor-arg index="2" value="Miami"/>
    </bean>
    <!-- 3. 通过工厂方法:实例方法 / 静态方法 -->
    <!-- 3.1 实例方法 -->
    <bean id="factory" class="com.murphy.pojo.MyFactory"/>
    <bean id="instanceTeam" factory-bean="factory" factory-method="instanceFun"/>
    <!-- 3.2 静态方法 -->
    <bean id="staticTeam" class="com.murphy.pojo.MyFactory" factory-method="staticFun"/>
</beans>

测试类CreateTypeTest.java

/**
 * 创建对象 测试类
 *
 * @author murphy
 */
public class CreateTypeTest {
    @Test
    public void test1(){
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("createType.xml");
    }
}

测试结果:

在这里插入图片描述

1.4 基于XML的DI

  • DI — Dependency Injection,即依赖注入:是组件之间依赖关系由容器在运行期决定,形象的说,即由容器动态的将某个依赖关系注入到组件之中。依赖注入的目的并非为软件系统带来更多功能,而是为了提升组件重用的频率,并为系统搭建一个灵活、可扩展的平台。通过依赖注入机制,我们只需要通过简单的配置,而无需任何代码就可指定目标需要的资源,完成自身的业务逻辑,而不需要关心具体的资源来自何处,由谁实现
  • IoC是一个概念,是一种思想,其实现方式多种多样。依赖注入就是其中用的比较多的一种方式。
  • Ioc和DI是同一个概念的不同角度描述 。IoC是一种思想、概念,DI是实现它的手段。Spring框架使用依赖注入实现IoC。
  • Spring容器是一个超级大工厂,负责创建、管理所有的Java对象,这些Java对象被称为Bean。Spring容器管理着容器中Bean之间的依赖关系,Spring 使用依赖注入的方式来管理 Bean 之间的依赖关系。使用IoC实现对象之间的解耦和
1.4.1 注入分类
  • bean实例在调用无参构造器创建对象后,就要对bean对象的属性进行初始化。初始化是由容器自动完成的,称为注入
1.4.1.1 通过set方法
  • set注入也叫设值注入是指,通过setter方法传入被调用者的实例。这种注入方式简单、直观,因而在Spring的依赖注入中大量使用。
1.4.1.2 通过构造方法
  • 构造注入是指在构造调用者实例的同时,完成被调用者的实例化,使用构造器设置依赖关系。
1.4.1.3. 自动注入
  • 对于引用类型属性的注入,也可不在配置文件中显示的注入。可以通过为标签设置autowire属性值,为引用类型属性进行隐式自动注入(默认是不自动注入引用类型属性)。根据自动注入判断标准的不同,可以分为两种:
    • byName:根据名称自动注入
    • byType: 根据类型自动注入
  1. byName
  • 当配置文件中被调用者 bean 的 id 值与代码中调用者 bean 类的属性名相同时,可使用byName 方式,让容器自动将被调用者 bean 注入给调用者 bean。容器是通过调用者的 bean类的属性名与配置文件的被调用者 bean 的 id 进行比较而实现自动注入的。
  1. byType
  • 使用byType方式自动注入,要求:配置文件中被调用者bean的class属性指定的类,要与代码中调用者bean类的某引用类型属性类型同源。即要么相同,要么有is-a关系(子类,或是实现类)。但这样的同源的被调用bean只能有一个,多于一个,容器就不知该匹配哪一个了。

示例:

创建TeamDao.java

/**
 * Dao
 *
 * @author murphy
 */
public class TeamDao {
    public void add() {
        System.out.println("TeamDao - add---");
    }
}

创建TeamService.java

/**
 * Service
 *
 * @author murphy
 */
public class TeamService {

    private TeamDao teamDao;

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

    public TeamService(TeamDao teamDao) {
        this.teamDao = teamDao;
    }

    public TeamService() {
    }

    public TeamDao getTeamDao() {
        return teamDao;
    }

    public void setTeamDao(TeamDao teamDao) {
        this.teamDao = teamDao;
    }
}

创建配置文件DI.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="teamDao" class="com.murphy.dao.TeamDao"/>

    <bean id="teamService" class="com.murphy.service.TeamService">
        <!-- 使用setter方法注入属性值 -->
        <property name="teamDao" ref="teamDao"></property>
    </bean>

    <bean id="teamService2" class="com.murphy.service.TeamService">
        <!-- 使用构造方法注入 -->
        <constructor-arg name="teamDao" ref="teamDao"></constructor-arg>
    </bean>

    <bean id="teamService3" class="com.murphy.service.TeamService" autowire="byName">
        <!-- 查询与属性名相同的容器中的对象 -->
    </bean>

    <bean id="teamService4" class="com.murphy.service.TeamService" autowire="byType">
        <!-- 查询与属性值相同类型的容器中的对象,但是要求类型相同的对象唯一,否则抛出异常:无法精确匹配 -->
    </bean>
</beans>

创建测试类:

import com.murphy.dao.TeamDao;
import com.murphy.service.TeamService;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * DITest
 *
 * @author murphy
 */
public class DITest {
    @Test
    public void test1() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("DI.xml");
        TeamService teamService = (TeamService) applicationContext.getBean("teamService");
        teamService.add();
        System.out.println("--------------------");
        TeamService teamService2 = (TeamService) applicationContext.getBean("teamService2");
        teamService2.add();
        System.out.println("--------------------");
        TeamService teamService3 = (TeamService) applicationContext.getBean("teamService3");
        teamService3.add();
        System.out.println("--------------------");
        TeamService teamService4 = (TeamService) applicationContext.getBean("teamService4");
        teamService4.add();
    }
}

1.5 基于注解实现IoC

  • 对于DI使用注解,将不再需要在Spring配置文件中声明bean实例。Spring中使用注解,需要在原有Spring运行环境基础上再做一些改变。
1.5.1 声明Bean的注解 @Component
  • 在类上添加注解@Component表示该类创建对象的权限交给Spring容器。注解的value属性用于指定beanid值,value可以省略。
  • @Component不指定value属性,bean的id是类名的首字母小写
/**
 * 球队实体类
 *
 * @author murphy
 */
@Component
public class Team {
    private Integer id;
    private String name;
    private String location;

    public Team() {
        System.out.println("Team - 默认构造方法:id=" + id + ",name=" + name + ",location=" + location);
    }
}

除此之外,Spring中还提供了其他 3 个用于创建对象的注解

  • @Repository:用于dao实现类的的注解
/**
 * Dao
 * @Repository
 * @Component(value = "teamDao")
 * @Component 注解标识在类上,表示对象由Spring容器创建 - value属性表示创建的ID值 / value可以省略,值可以省略,默认类名的首字母小写
 * @author murphy
 */
@Repository
public class TeamDao {
    public TeamDao() {
        System.out.println("TeamDao - 默认的构造方法");
    }
}
  • @Service:用户service实现类的注解
/**
 * Service
 * @Service
 * @author murphy
 */
@Service
public class TeamService {
		public TeamService() {
        System.out.println("TeamService - 默认的构造方法");
    }
}
  • @Controller:用于controller实现类的注解
/**
 * Controller
 * @Controller
 * @author murphy
 */
@Controller
public class TeamController {
    public TeamController() {
        System.out.println("TeamController - 默认的构造方法");
    }
}

这三个注解与@Component都可以创建对象,但这三个注解还有其他的含义,@Service创建业务层对象,业务层对象可以加入事务功能,@Controller注解创建的对象可以作为处理器接收用户的请求@Repository@Service@Controller是对@Component注解的细化,标注不同层的对象。即持久层对象业务层对象控制层对象

测试类:

/**
 * 注解 测试类
 *
 * @author murphy
 */
public class AnnotationTest {
    @Test
    public void test() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation.xml");
    }
}
// ---------------------------------------------------------------------------------------------------------
运行结果:
TeamDao - 默认的构造方法
TeamService - 默认的构造方法
TeamController - 默认的构造方法
Team - 默认构造方法:id=null,name=null,location=null
1.5.2 包扫描
  • 需要在Spring配置文件中配置组件扫描器,用于在指定的基本包中扫描注解。 如果没有报扫描,添加的创建对象的注解不生效
  • 如果要扫描的包有多个,可以有以下方式扫描:
    1. 使用多个context:component-scan指定不同的包路径
    2. 指定base-package的值使用分隔符
      • 分隔符可以使用逗号(,)、分号(;),还可以使用空格,不建议使用空格。
    3. base-package指定到父包名
      • base-package的值表是基本包,容器启动会扫描包及其子包中的注解,当然也会扫描到子包下级的子包。所以base-package可以指定一个父包就可以。
      • 但不建议使用顶级的父包,扫描的路径比较多,导致容器启动时间变慢。指定到目标包和合适的,也就是注解所在包全路径。
<!-- annotation.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
       https://www.springframework.org/schema/context/spring-context.xsd">

    <!--
        表示告知Spring要扫描的包
        这些包以及子包当中的类上如果添加了 @Component 注解,这些添加了注解的类就交给Spring容器创建对象
        注意:在beans标签中添加
        xmlns:context="http://www.springframework.org/schema/context"
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd
    -->

    <!-- 多个包的扫描:方式1 - 使用多个 <context:component-scan> 表明 -->
    <context:component-scan base-package="com.murphy.dao"/>
    <context:component-scan base-package="com.murphy.service"/>
    <context:component-scan base-package="com.murphy.controller"/>

    <!-- 多个包的扫描:方式2 - base-package 中直接声明要扫描的多个包,多个包使用逗号/分号/空格分隔,空格不推荐 -->
    <context:component-scan base-package="com.murphy.dao,com.murphy.service,com.murphy.controller"/>

    <!-- 多个包的扫描:方式3 - base-package 中直接声明被扫描的多个包的父包 -->
    <context:component-scan base-package="com.murphy"/>
</beans>
1.5.3 属性注入 @Vaule
  • 需要在属性上使用注解@Value,该注解的value属性用于指定要注入的值。使用该注解完成属性注入时,类中无需setter。当然,若属性有setter,则也可将其加到setter上。
  • 相当于 <property name="name" value="murphy"/>

字段属性注入:

/**
 * 球队实体类
 *
 * @author murphy
 */
@Component
public class Team {
    @Value("1001")
    private Integer id;
    @Value("Warriors")
    private String name;
    @Value("Oakland")
    private String location;

    public Team() {
        System.out.println("Team - 默认构造方法:id=" + id + ",name=" + name + ",location=" + location);
    }
  
		@Override
    public String toString() {
        return "Team{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", location='" + location + '\'' +
                '}';
    }
}

// --------------------------------------------------------------------------------------------------------

// 测试类
@Test
public void test() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation.xml");
    Team team = (Team) applicationContext.getBean("team");
    System.out.println(team);
}

// 运行结果:
TeamDao - 默认的构造方法
TeamService - 默认的构造方法
TeamController - 默认的构造方法
Team - 默认构造方法:id=null,name=null,location=null
Team{id=1001, name='Warriors', location='Oakland'}

setter属性注入:

/**
 * 球队实体类
 *
 * @author murphy
 */
@Component
public class Team {

    private Integer id;
    private String name;
    private String location;

    @Value("1001")
    public void setId(Integer id) {
        this.id = id;
    }

    @Value("Warriors")
    public void setName(String name) {
        this.name = name;
    }
    
    @Value("Oakland")
    public void setLocation(String location) {
        this.location = location;
    }

    public Team() {
        System.out.println("Team - 默认构造方法:id=" + id + ",name=" + name + ",location=" + location);
    }
    
    @Override
    public String toString() {
        return "Team{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", location='" + location + '\'' +
                '}';
    }
}

// --------------------------------------------------------------------------------------------------------

// 测试类
@Test
public void test() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation.xml");
    Team team = (Team) applicationContext.getBean("team");
    System.out.println(team);
}

// 运行结果:
TeamDao - 默认的构造方法
TeamService - 默认的构造方法
TeamController - 默认的构造方法
Team - 默认构造方法:id=null,name=null,location=null
Team{id=1001, name='Warriors', location='Oakland'}
1.5.4 byType自动注入 @Autowired
  • 需要在引用属性上使用注解@Autowired,该注解默认使用按类型自动装配Bean的方式。使用该注解完成属性注入时,类中无需 setter。当然,若属性有setter,则也可将其加到setter上。
/**
 * Service
 * @Service
 * @author murphy
 * @since 2021/6/19 6:39 下午
 */
@Service
public class TeamService {
    /**
     * @Autowired 自动装配,自动按照类型装配
     * required true - 不存在则装配失败 / false - 不存在则置为空指针
     * @Qualifier 按照名称自动装配 - 需注解搭配使用
     */
    @Autowired(required = true)
    @Qualifier("teamDao")
    private TeamDao teamDao;

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

    public TeamService() {
        System.out.println("TeamService - 默认的构造方法");
    }

    public TeamService(TeamDao teamDao) {
        this.teamDao = teamDao;
    }
  
    public void setTeamDao(TeamDao teamDao) {
        this.teamDao = teamDao;
    }
}

// 测试类
@Test
public void test() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation.xml");
    TeamService teamService = (TeamService) applicationContext.getBean("teamService");
    teamService.add();
}

// 运行结果
TeamDao - add---
TeamService - add---
1.5.5 byName自动注入 @Autowired和@Qualifier
  • 需要在引用属性上联合使用注解@Autowired@Qualifier@Qualifiervalue属性用于指定要匹配的Bean的id值。类中无需set方法,也可加到set方法上。
  • @Autowired还有一个属性required,默认值为true,表示当匹配失败后,会终止程序运行。若将其值设置为false,则匹配失败,将被忽略,未匹配的属性值为null
1.5.6 自动注入 @Resource
  • Spring提供了对JDK中@Resource注解的支持。@Resource注解既可以按名称匹配Bean,也可以按类型匹配Bean。
  • 默认是按名称注入。使用该注解,要求JDK必须是6及以上版本。@Resource可在属性上,也可在set方法上。
/**
 * Controller
 * @Controller
 * @author murphy
 * @since 2021/6/19 10:05 下午
 */
@Controller
public class TeamController {
    /**
     * @Resource JDK > 1.6
     * 默认按照名称,若名称不相符,则按照类型自动装配
     * @Resource(name = "teamService", type = TeamService.class)
     */
    @Resource
    private TeamService teamService;

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

    public TeamController() {
        System.out.println("TeamController - 默认的构造方法");
    }
}

// 测试类
@Test
public void test() {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("annotation.xml");
    TeamController teamController = (TeamController) applicationContext.getBean("teamController");
    teamController.add();
}

// 运行结果
TeamDao - add---
TeamService - add---
TeamController - add---
  1. byType注入引用类型属性

@Resource注解若不带任何参数,采用默认按名称的方式注入,按名称不能注入bean,则会按照类型进行Bean的匹配注入。

  1. byName注入引用类型属性

@Resource注解指定其name属性,则name的值即为按照名称进行匹配的Bean的id。

  1. @Resource@Autowired的区别:
  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired通过byType的方式实现,而且必须要求这个对象存在!
  • @Resource通过byName的方式实现,如果找不到名字,则通过byType实现!两者都失败的情况下则报错。
  • 执行顺序不同:@Autowired通过byType的方式实现,@Resource通过byName的方式实现。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

xmurphymurphy

你的鼓励将是我创作的最大动力

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

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

打赏作者

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

抵扣说明:

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

余额充值