【Spring】Bean注册和注入

简介: 1. 逻辑上的 Bean 注册2. XML 注册 Bean 到自建的库中2.1 工厂方法2.2 使用工厂方法和实例化工厂注册 Bean3. XML 配合注解进行 Bean 注册4. 使用注解注册 Bean4.1 注解方式注册的必要条件4.2 用到的注解4.3 @Component注解注入4.4 使用 @Bean 注解注册5. 通过注解注入 Bean6. 注入时的一个坑点7. 获取 库中的对象

1. 逻辑上的 Bean 注册


76.png


2. XML 注册 Bean 到自建的库中

上篇文章介绍了使用 XML 三种注册的三种方式 (直接注入、构造方法注入、set 方法注入),在这里继续介绍一下使用工厂方法实例化工厂注册 Bean


2.1 工厂方法

工厂方法分为静态工厂方法实例工厂方法

使用工厂方法注册就是调用静态工厂方法注册 Bean

实例化工厂注册就是调用实例工厂方法注册 Bean


2.2 使用工厂方法和实例化工厂注册 Bean

首先还是使用 XML 自建库,在 Main 方法中对库进行操作(这里对库的操作主要是打印 Bean)


import org.springframework.context.support.FileSystemXmlApplicationContext;
public class Main {
    public static void main(String[] args) {
        FileSystemXmlApplicationContext context = new FileSystemXmlApplicationContext("spring-config.xml");
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            Object bean = context.getBean(name);
            String canonicalName = bean.getClass().getCanonicalName();
            System.out.println(name + "     " + canonicalName);
        }
        int count = context.getBeanDefinitionCount();
        System.out.println("一共有 " + count + "个");
    }
}
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--    通过工厂注册,bean 的实例化由工厂方法完成-->
    <bean id="工厂注册" class="com.hsq.ioc3.SomeClass" factory-method="createPerson"/>
<!--    通过已经注册的 bean 的实例方法注册,bean 的实例化由我们自己完成-->
    <bean id="工具bean" class="com.hsq.ioc3.SomeClass"/>
    <bean id="通过实例化工厂注册" factory-bean="工具bean" factory-method="instantCreatePerson"/>
</beans>
public class SomeClass {
    // 静态方法(可以直接通过类名调用)
    // 作用:返回一个对象
    // 这类方法被称为工厂方法
    public static Person createPerson() {
        System.out.println("createPerson 被调用");
        return new Person();
    }
    public Person instantCreatePerson() {
        System.out.println("instantCreatePerson 被调用");
        return new Person();
    }
}
public class Person {
    public Person() {
        System.out.println("Person 被调用");
    }
}

通过打印可以清楚的看到两种方法都成功注册 Person 对象

77.png


3. XML 配合注解进行 Bean 注册

自建 XML 库中的配置文件有所改变

用到的注解 @Component,此注解后边会讲到


<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        https://www.springframework.org/schema/context/spring-context.xsd">
<!--    扫描这个包下的所有类,如果没在这个包下,即使加了注解接不会被注入-->
    <context:component-scan base-package="com.hsq.ioc3"/>
</beans>
import org.springframework.stereotype.Component;
@Component
public class World {
    public World() {
        System.out.println("World 被调用");
    }
}

通过打印可以清楚看到,World 对象被成功注册

78.png


4. 使用注解注册 Bean

使用注解注册简而言之就是使用某个注解修饰类或方法,对其进行注册

使用注解注册 Bean 是注册进 Spring 提供的库,就不需要自建库了


4.1 注解方式注册的必要条件

  1. 要被注解修饰类
  2. 被注册的 Bean 要在 XXXApplication 所在包下,否则注册不会成功



4.2 用到的注解

这几个注解在 IOC 场景下,没有区别,都是将类注册进 Spring 库,但在其他场景一般这样用


@Component:没有特殊作用时,都可以用


@Controller:SpringMVC中把此注解特殊化了,要求控制器类必须用此注解修饰


@Service:修饰中间数据整合的类


@Repository:修饰数据获取类


@Configuration:修饰配置类


4.3 @Component注解注入

import org.springframework.stereotype.Component;
@Component
public class World {
    public World() {
        System.out.println("World() 被调用");
    }
}
@SpringBootApplication
public class IocAApplication {
   public static void main(String[] args) {
      ConfigurableApplicationContext context = SpringApplication.run(IocAApplication.class, args);
      String[] names = context.getBeanDefinitionNames();
      System.out.println("bean 陈列如下:");
      for (String name : names) {
         Object bean = context.getBean(name);
         String canonicalName = bean.getClass().getCanonicalName();
         System.out.println(name + "   " + canonicalName);
      }
      int count = context.getBeanDefinitionCount();
      System.out.println("一共 " + count + "个");
   }
}

通过打印清楚看到,对象被注册

78.png


4.4 使用 @Bean 注解注册

使用 @Bean 修饰方法,@Configuration 修饰类

此方法注册就相当于 XML 中的工厂方法注册


@Configuration
public class AppConfig {
    // <bean id="hsq" factory-bean="appConfig" factory-method="hsq" />
    // 以工厂方法注册
    @Bean
    public String hsq() {
        return "hsq";
    }
    @Bean       // 这里的 World 由 Spring 注入
    // 因为 createHello 被 Spring 调用
    public Hello createHello(@Autowired World world) {
        System.out.println("createHello(), world = " + world);
        return new Hello(world);
    }
}

79.png


5. 通过注解注入 Bean

需要用到 World 类时


先让 Hello 类被注册到 Spring 容器,并且实例化过程交给 Spring。———— @Component 修饰 Hello 类

要求 World 类被注册到 Spring 中(类注册或者方法注册都可以)

使用构造方法、set 方法、属性直接注入三种方法注入bean——使用 @Autowired 修饰


import org.springframework.stereotype.Component;
@Component
public class World {
    public World() {
        System.out.println("World() 被调用");
    }
}

构造方法注入

@Component
public class Hello {
    @Autowired      // 这个注解其实可以不写,但是建议写上,主要是让看代码的人知道我们的 World 对象是被注入的
                    // 如果有多个构造方法,告诉 Spring,实例化对象是,应该调用哪个
    public Hello(World world) {
        System.out.println("Hello(), world = " + world);
    }
}

set 方法注入

@Component
public class Hello2 {
    @Autowired          // 这里的此注解必须写上
    public void setWorld(World world) {
        System.out.println("setWorld(), World = " + world);
    }
}

属性直接注入

@Component
public class Hello3 {
    @Autowired
    public World world;     // world 属性的值会被 Spring 容器对象注入
    public void printWorld() {
        System.out.println("printWorld(), world = " + this.world);
    }
}

6. 注入时的一个坑点

当使用以下方法注入时,会注入进 NULL 值,而非对象,原因已在下面代码的注释中写出

// 发生在 set 注入 / 属性直接注入上
@Component
public class 注入时的一个坑点 {
    @Autowired
    public World world;
    public 注入时的一个坑点() {
        // 构造方法先执行,然后再进行注入(属性注入 / set 注入)
        // 所以,构造方法执行的时候,注入还没有发生,所以还是 null
        // 所以一般建议使用构造方法注入
        System.out.println("注入时的一个坑点(), world = " + this.world);
    }
}

7. 获取 库中的对象

ConfigurableApplicationContext context = SpringApplication.run(IocAApplication.class, args);
Object world1 = context.getBean("world");         // 根据 id 获取 bean
World world2 = context.getBean(World.class);         // 根据类型获取 bean
World world = context.getBean("world", World.class);      // 根据 id + 类型获取 bean
目录
相关文章
|
12天前
|
Java 测试技术 程序员
为什么Spring不推荐@Autowired用于字段注入?
作为Java程序员,Spring框架在日常开发中使用频繁,其依赖注入机制带来了极大的便利。然而,尽管@Autowired注解简化了依赖注入,Spring官方却不推荐在字段上使用它。本文将探讨字段注入的现状及其存在的问题,如难以进行单元测试、违反单一职责原则及易引发NPE等,并介绍为何Spring推荐构造器注入,包括增强代码可读性和维护性、方便单元测试以及避免NPE等问题。通过示例代码展示如何将字段注入重构为构造器注入,提高代码质量。
|
13天前
|
XML Java 数据格式
Spring从入门到入土(bean的一些子标签及注解的使用)
本文详细介绍了Spring框架中Bean的创建和使用,包括使用XML配置文件中的标签和注解来创建和管理Bean,以及如何通过构造器、Setter方法和属性注入来配置Bean。
53 9
Spring从入门到入土(bean的一些子标签及注解的使用)
|
3天前
|
Java 测试技术 Windows
咦!Spring容器里为什么没有我需要的Bean?
【10月更文挑战第11天】项目经理给小菜分配了一个紧急需求,小菜迅速搭建了一个SpringBoot项目并完成了开发。然而,启动测试时发现接口404,原因是控制器包不在默认扫描路径下。通过配置`@ComponentScan`的`basePackages`字段,解决了问题。总结:`@SpringBootApplication`默认只扫描当前包下的组件,需要扫描其他包时需配置`@ComponentScan`。
|
13天前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细解析Spring Bean的生命周期及其核心概念,并深入源码分析。Spring Bean是Spring框架的核心,由容器管理其生命周期。从实例化到销毁,共经历十个阶段,包括属性赋值、接口回调、初始化及销毁等。通过剖析`BeanFactory`、`ApplicationContext`等关键接口与类,帮助你深入了解Spring Bean的管理机制。希望本文能助你更好地掌握Spring Bean生命周期。
42 1
|
15天前
|
Java Spring
获取spring工厂中bean对象的两种方式
获取spring工厂中bean对象的两种方式
16 1
|
16天前
|
缓存 Java Spring
源码解读:Spring如何解决构造器注入的循环依赖?
本文详细探讨了Spring框架中的循环依赖问题,包括构造器注入和字段注入两种情况,并重点分析了构造器注入循环依赖的解决方案。文章通过具体示例展示了循环依赖的错误信息及常见场景,提出了三种解决方法:重构代码、使用字段依赖注入以及使用`@Lazy`注解。其中,`@Lazy`注解通过延迟初始化和动态代理机制有效解决了循环依赖问题。作者建议优先使用`@Lazy`注解,并提供了详细的源码解析和调试截图,帮助读者深入理解其实现机制。
17 1
|
16天前
|
Java 开发者 Spring
Spring bean的生命周期详解!
本文详细介绍了Spring框架中的核心概念——Spring Bean的生命周期,包括实例化、属性赋值、接口回调、初始化、使用及销毁等10个阶段,并深入剖析了相关源码,如`BeanFactory`、`DefaultListableBeanFactory`和`BeanPostProcessor`等关键类与接口。通过理解这些核心组件,读者可以更好地掌握Spring Bean的管理和控制机制。
50 1
|
1月前
|
XML Java 数据格式
spring复习03,注解配置管理bean
Spring框架中使用注解配置管理bean的方法,包括常用注解的标识组件、扫描组件、基于注解的自动装配以及使用注解后的注意事项,并提供了一个基于注解自动装配的完整示例。
spring复习03,注解配置管理bean
|
XML Java 数据格式
Spring【依赖注入】就是这么简单(二)
在Spring的第二篇中主要讲解了Spring Core模块的使用IOC容器创建对象的问题,Spring Core模块主要是解决对象的创建和对象之间的依赖关系,因此本博文主要讲解如何使用IOC容器来解决对象之间的依赖关系!
133 0
Spring【依赖注入】就是这么简单(二)
|
1月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。