Spring容器注入bean的五种方法逐个解析

 更新时间:2023年02月20日 09:02:35   作者:尚少  
依赖注入(Dependency Injection)和控制反转(Inversion of Control)是同一个概念。具体含义是:当某个角色(可能是一个Java实例,调用者)需要另一个角色(另一个Java实例,被调用者)的协助时,在传统的程序设计过程中,通常由调用者来创建被调用者的实例

前言

  我们在项目开发中都用到Spring,知道对象是交由Spring去管理。那么将一个对象加入到Spring容器中,有几种方法呢,我们来总结一下。

@ComponentScan+@Component

  @ComponentScan可以放在启动类上,指定要扫描的包路径;该包路径下被@Component修饰的类,都会被注入到Spring容器中。

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.ComponentScan;
@ComponentScan(basePackages = "com.gs.beanRegister")
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext(BootStrap.class);
        A bean = context.getBean(A.class);
        bean.say();
    }
}

  com.gs.beanRegister包下:

import org.springframework.stereotype.Component;
@Component
public class A {
    public void say() {
        System.out.println("这是a");
    }
}

  注:在SpringBoot中,由于其自动装配的特性,所以@ComponentScan可以不加,只要@Component修饰的类和启动类在同一包下或者在启动类所在包的子包下。

@Configuration+@Bean

  @Configuration用来声明一个配置类,如果它的方法被@Bean修饰,那么该方法返回的对象也会被注入到Spring容器中。

  代码方面,BootStrap 类不动,A类的@Component去掉,com.gs.beanRegister包下建个配置类:

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;
@Configuration
public class MyConfiguration {
    @Bean
    public A a() {
        return new A();
    }
}

通过@Import注解

  这个注解可能平时大家接触得不多,它有好几种使用方式。

1.直接导入类的class

import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
@Import(A.class)
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext(BootStrap.class);
        A bean = context.getBean(A.class);
        //B bean = context.getBean(B.class);
        bean.say();
    }
}

  A类不用添加任何注解:

public class A {
    public void say() {
        System.out.println("这是a");
    }
}

2.导入配置类

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(MyConfiguration.class)
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext(BootStrap.class);
        A bean = context.getBean(A.class);
        bean.say();
    }
}
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
// 使用@Import导入配置类时,@Configuration可以不加
//@Configuration
public class MyConfiguration {
    @Bean
    public A a() {
        return new A();
    }
}

3.导入ImportSelector的实现类

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(MyImportSelector.class)
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext(BootStrap.class);
        A bean = context.getBean(A.class);
        bean.say();
    }
}
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata metadata) {
        // 返回要注入的bean的全路径,A类不用任何注解修饰
        // SpringBoot的自动装配,就用到了这种方式:
        // 返回配置类的全路径,配置类的@Bean方法返回的对象也能注入到容器中
        return new String[] { A.class.getName() };
    }
}

4.导入ImportBeanDefinitionRegistrar的实现类

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(MyImportBeanDefinitionRegistrar.class)
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext(BootStrap.class);
        A bean = context.getBean(A.class);
        bean.say();
    }
}
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportBeanDefinitionRegistrar implements 
             ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata metadata, 
                BeanDefinitionRegistry registry) {
        // 构建bean的元数据,A类不用任何注解修饰
        // spring-mybatis扫描mapper接口,生成代理类,就是用的这种方式
        BeanDefinition definition = new RootBeanDefinition(A.class);
        registry.registerBeanDefinition("a", definition);
    }
}

借助FactoryBean接口

  实现FactoryBean接口的类,除了本身会被注入外,getObject方法返回的对象也会被注入到Spring容器中。

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Import;
@Import(MyFactoryBean.class)
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext(BootStrap.class);
        A bean = context.getBean(A.class);
        bean.say();
    }
}
import org.springframework.beans.factory.FactoryBean;
public class MyFactoryBean implements FactoryBean {
    @Override
    public Object getObject() throws Exception {
        return new A();
    }
    @Override
    public Class<?> getObjectType() {
        return A.class;
    }
}

借助BeanDefinitionRegistryPostProcessor接口

  在Spring容器启动时,会调用该接口的postProcessBeanDefinitionRegistry方法,大概意思是等BeanDefinition(上面提到的bean的元数据)加载完成后,再对它进行后置处理。所以可以在此调整BeanDefinition,从而把对应的bean注入。

import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class BootStrap {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context = 
        new AnnotationConfigApplicationContext();
        BeanDefinitionRegistryPostProcessor postProcessor = 
        new MyBeanDefinitionRegistryPostProcessor();
        context.addBeanFactoryPostProcessor(postProcessor);
        context.refresh();
        A a = context.getBean(A.class);
        a.say();
    }
}
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import org.springframework.beans.factory.support.RootBeanDefinition;
public class MyBeanDefinitionRegistryPostProcessor implements 
             BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry 
                registry) throws BeansException {
        BeanDefinition definition = new RootBeanDefinition(A.class);
        registry.registerBeanDefinition("a", definition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory 
                beanFactory) throws BeansException {
    }
}

到此这篇关于Spring容器注入bean的五种方法逐个解析的文章就介绍到这了,更多相关Spring注入bean内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Java实现图片与二进制的互相转换

    Java实现图片与二进制的互相转换

    这篇文章主要为大家详细介绍了Java实现图片与二进制的互相转换,将图片转二进制再将二进制转成图片,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2018-03-03
  • java去除中文括号小括号,或者英文括号的实例代码

    java去除中文括号小括号,或者英文括号的实例代码

    这篇文章主要介绍了java去除中文括号小括号,或者英文括号的实例代码,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2020-09-09
  • 从Java的jar文件中读取数据的方法

    从Java的jar文件中读取数据的方法

    这篇文章主要介绍了从Java的jar文件中读取数据的方法,实例分析了java档案文件的相关操作技巧,需要的朋友可以参考下
    2015-06-06
  • IDEA个性化设置注释模板详细讲解版

    IDEA个性化设置注释模板详细讲解版

    IDEA自带的注释模板不是太好用,我本人到网上搜集了很多资料系统的整理了一下制作了一份比较完整的模板来分享给大家,下面这篇文章主要给大家介绍了IDEA个性化设置注释模板的相关资料,需要的朋友可以参考下
    2024-01-01
  • 学习C语言对后期java有帮助吗

    学习C语言对后期java有帮助吗

    在本篇文章里小编给大家整理的是一篇关于学习C语言对后期java有帮助吗的基础文章,有兴趣的朋友们可以参考下。
    2020-11-11
  • SpringBoot读取properties或者application.yml配置文件中的数据

    SpringBoot读取properties或者application.yml配置文件中的数据

    这篇文章主要介绍了SpringBoot读取properties或者application.yml配置文件中的数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • Java中的关键字volatile详解

    Java中的关键字volatile详解

    这篇文章主要介绍了Java中的关键字volatile,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • java编写简单的ATM存取系统

    java编写简单的ATM存取系统

    这篇文章主要介绍了java编写简单的ATM存取系统,附上思路和具体实现代码,适合新人练手用,推荐给小伙伴们。
    2015-02-02
  • 基于JavaMail的常用类详细介绍

    基于JavaMail的常用类详细介绍

    以下是对JavaMail的常用类进行了详细分析的介绍,需要的朋友可以过来参考下
    2013-09-09
  • 解析SpringBoot中@Autowire注解的实现原理

    解析SpringBoot中@Autowire注解的实现原理

    在开发Java项目时,依赖注入是一种常见的实现方式,SpringBoot框架通过@Autowired注解来实现依赖注入的功能,本文将介绍SpringBoot中 Autowired注解实现的原理
    2023-06-06

最新评论