SpringBoot加载bean的八种方式总结

目录
  • 第一种bean的加载方式-配置文件
  • 第二种加载bean方式-注解和扫描
  • 第三种加载bean方式-不使用配置文件
    • 扩展-bean的加载方式扩展FactoryBean<>
    • 扩展-@ImportResource导入配置文件
    • 扩展-proxyBeanMethods属性-产生代理对象
  • 第四种加载bean方式-使用@Import
  • 第五种加载bean方式-registerBean
  • 第六种加载bean方式-实现ImportSelector接口
  • 第七种加载bean方式-实现ImportBeanDefinitionRegistrar
  • 第八种bean的加载方式-实现BeanDefinitionRegistryPostProcessor
  • 实现bean的方式总结

第一种bean的加载方式-配置文件

先创建一个使用maven的spring工程

导入spring核心配置

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.9</version>
        </dependency>

创建一个类

public  class Cat {

}
public class Dog {
}

创建一个名为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">

    <bean id="cat" class="com.service.Cat"/>
<bean id="dog" class="com.service.Dog"/>

</beans>

创建一个启动类

package com.app;

import com.service.Dog;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App1 {
    public static void main(String[] args) {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");
        Object cat = app.getBean("cat");//根据id获取
        System.out.println(cat);
        Object dog = app.getBean(Dog.class);//根据类获取,当不唯一时会报错
        System.out.println(dog);

    }
}

运行结果,这样就可以得到bean的对象了

或者使用可以使用一次性获取所有bean

public class App1 {
    public static void main(String[] args) {
        ApplicationContext app=new ClassPathXmlApplicationContext("applicationContext.xml");

        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

运行结果

第二种加载bean方式-注解和扫描

使用注解,注解的作用就是替代配置文件的配置,注解有@Component @Service @Repository等

替换配置文件中的<bean id= class=..>

@Component("cat") //起的名
public class Cat {

}
@Component
public class Dog {
}

使用完注解还得让spring去扫描到这个注解,在配置文件中的写

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
          http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
">

<!--告诉spring扫描哪个包component导入context命名空间-->
    <context:component-scan base-package="com"/>

</beans>

运行结果

创建第三方的bean对象

先导入对应的坐标

               <dependency>
                    <groupId>com.alibaba</groupId>
                    <artifactId>druid</artifactId>
                    <version>1.1.24</version>
                </dependency>

创建一个类,返回你需要导入的对象即可,加入注解

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class DBconfig {
    @Bean
    public DruidDataSource dataSource(){
        DruidDataSource ds =new DruidDataSource();
        return ds;
    }
}

运行结果

第三种加载bean方式-不使用配置文件

创建一个类代替配置文件

package com.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration//定义为配置类
@ComponentScan({"com.config","com.service"}) //注解扫描包
public class springConfig {
}

运行类也得修改

package com.app;

import com.config.springConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
ApplicationContext app=new AnnotationConfigApplicationContext(springConfig.class);

        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

运行结果

扩展-bean的加载方式扩展FactoryBean<>

初始化实现FactoryBean<>接口的类,实现对bean加载到容器之前的批处理操作。

实现了FactoryBean接口创建出来的对象不是本身而是里面的泛型。

创建一个类实现接口

package com.config;

import com.service.Dog;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.context.annotation.Bean;

public class DogFactoryBean implements FactoryBean<Dog> {
    public Dog getObject() throws Exception {
        return new Dog();
    }
//返回对象的类型
    public Class<?> getObjectType() {

        //这里可以做一系列的初始化工作
        return Dog.class;
    }

    //是否是单例,单例则多次获取都是一个对象
    public boolean isSingleton() {
        return false;
    }
}
@Component
public class Dog {
}

启动的主类

import com.config.springConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App2 {
    public static void main(String[] args) {
ApplicationContext app=new AnnotationConfigApplicationContext(springConfig.class);

        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        System.out.println(app.getBean("dog1"));
        System.out.println(app.getBean("dog1"));
    }
}

运行结果

产生的是泛型的对象

扩展-@ImportResource导入配置文件

看源码可知道,可以写入多个string类型的数组,使用{}

@ImportResource({"applicationContext2.xml","applicationContext.xml"})

@Configuration
@ComponentScan("com")
@ImportResource({"applicationContext2.xml","applicationContext.xml"})
public class SpringConfig2 {
    @Bean
    public Cat cat(){
        return new Cat();
    }
}

两个配置文件中的bean,排在前面的首先加载,后面的之后加载,同的内容以之后的为主,不同的内容都加载。

扩展-proxyBeanMethods属性-产生代理对象

@Configuration注解中有一属性proxyBeanMethod属性,默认值是true

 值为false时

@Configuration(proxyBeanMethods = false)
@ComponentScan("com")
@ImportResource({"applicationContext2.xml","applicationContext.xml"})
public class SpringConfig2 {
    @Bean
    public Cat cat(){
        return new Cat();
    }
}

主方法中

public class app3 {
    public static void main(String[] args) {
        ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfig2.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        System.out.println("--------");
        System.out.println(app.getBean("springConfig2"));

        SpringConfig2 springConfig2 = app.getBean("springConfig2", SpringConfig2.class);
        System.out.println(springConfig2.cat());
        System.out.println(springConfig2.cat());
        System.out.println(springConfig2.cat());

    }
}

运行结果

产生的是普通对象,每一次调用方法都会new一个新的对象前提是这个方法是被bean管理的对象。

  值为true时

不写或写true时

@Configuration(proxyBeanMethods = true)
@ComponentScan("com")
@ImportResource({"applicationContext2.xml","applicationContext.xml"})
public class SpringConfig2 {
    @Bean
    public Cat cat(){
        return new Cat();
    }
}

运行结果

会产生一个代理对象,这个代理对象让我们每次调用方法是都是同一个,前提也是需要被bean容器管理

注:产生的bean对象没指定名称时,默认是方法名或类名首字母小写,如类名是SpringTest则产生的bean是springTest

第四种加载bean方式-使用@Import

翻看@Import源码可知,需要一个类class字节码对象

在类中

import com.service.TestBean1;
import com.service.TestBean2;
import org.springframework.context.annotation.Import;

@Import({TestBean1.class, TestBean2.class})
public class springConfig4 {
}

创建测试的类

public class TestBean1 {
}
public class testBean2 {
}

主类上

public class app4 {
    public static void main(String[] args) {
        ApplicationContext app=new AnnotationConfigApplicationContext(springConfig4.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}

运行结果

全路径名,加入的类即使没有被spring管理也可以产生bean。

第五种加载bean方式-registerBean

使用上下文对象在容器初始化后注入bean

在创建完上下文对象的时候可以加载bean

只能使用 AnnotationConfigApplicationContext获取上下文对象

public class app5 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext app=new AnnotationConfigApplicationContext(springConfig5.class);
    //加载完成后
        app.registerBean("CaiDog", Dog.class,1 );
        app.registerBean("CaiDog", Dog.class,2);
        app.registerBean("CaiDog", Dog.class,3 );
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

        System.out.println("------");
        System.out.println(app.getBean(Dog.class));
    }
}

Dog类下

@Component
public class Dog {

    int age;
    public Dog(){}

    public Dog(int age){
        this.age=age;
    }

    @Override
    public String toString() {
        return "Dog{" +
                "age=" + age +
                '}';
    }
}

运行结果 ,当有多个的时候,且bean的名字一致时,以最后的为准。

或者直接使用

app.register(Cat.class);

也可以快速的加载一个bean

第六种加载bean方式-实现ImportSelector接口

这个接口有许多方法用来判定

导入实现了ImportSelector接口的类,实现对导入源的编程式处理

public class MyImportSelector implements ImportSelector {
    public String[] selectImports(AnnotationMetadata annotationMetadata) {//AnnotationMetadata 注解的源数据
     //  做判定条件,是否有这个注解
        boolean flag = annotationMetadata.hasAnnotation("org.springframework.context.annotation.Configuration");
        if (flag){
            return new String[]{"com.service.Dog"};
        }

        return new String[]{"com.service.Cat"};
    }
}
@Import({MyImportSelector.class})
public class SpringConfig6 {
}
public class app6 {
    public static void main(String[] args) {
        ApplicationContext app=new AnnotationConfigApplicationContext(SpringConfig6.class);
        String[] names = app.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }

    }
}

运行结果

第七种加载bean方式-实现ImportBeanDefinitionRegistrar

导入实现ImportBeanDefinitionRegistrar接口的类,通过BeanDefinition的注册器注册实名bean,实现对容器中bean的决定,例如对现有的bean的覆盖,进而达到

import com.service.Dog;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.ImportBeanDefinitionRegistrar;
import org.springframework.core.type.AnnotationMetadata;
public class MyRegistrar implements ImportBeanDefinitionRegistrar {
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(Dog.class).getBeanDefinition();
        registry.registerBeanDefinition("woDog", beanDefinition);
    }
}
@Import({MyRegistrar.class})
public class SpringConfig7 {
}

运行结果

第八种bean的加载方式-实现BeanDefinitionRegistryPostProcessor

导入实现了BeanDefinitionRegistryPostProcessor接口的类,通过BeanDefintion的注册器注册实名bean,实现对容器中bean的最终裁定.(以这个接口加载的bean为主)

@Component
public class DBconfig {
    @Bean
    public DruidDataSource dataSource(){
        DruidDataSource ds =new DruidDataSource();
        return ds;
    }
}
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
 BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(DBconfig.class).getBeanDefinition();

    registry.registerBeanDefinition("dataSource",beanDefinition);
    }

    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {

    }
}
@Import({MyPostProcessor.class})
public class SpringConfig8 {
}

运行结果

实现bean的方式总结

1.xml+<bean/>

2.xml:context+注解(@Component+4个@Bean

3.配置类+扫描+注解(@Component+4个@Bean)

@Bean定义FactoryBean接口@ImportResource@Configuration注解的proxyBeanMethods属性

4.@Import导入bean的类

@Import导入配置类

5.AnnotationConfigApplicationContext调用register方法

6.@Import导入ImportSelector接口

7.@Import导入ImportBeanDefinitionRegistrar接口

8.@Import导入BeanDefinitionRegistryPostProcessor接口

到此这篇关于SpringBoot加载bean的八种方式的文章就介绍到这了,更多相关SpringBoot加载bean内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • SpringBoot对不同Bean注解的区别和使用场景说明

    目录 对不同Bean注解的区别和使用场景 什么是Bean? 注解@Bean @Component …等都有什么区别? SpringBoot注入对象冲突如何解决? SpringBoot的各种注解 @Configuration 总结 对不同Bean注解的区别和使用场景 什么是Bean? 谈Bean的潜台词是在说Spring中的Bean,我们都知道Spring中的BeanFactory,而Bean这个概念也是由此而来.在Spring中,只要一个类能被实例化,并被Spring容器管理,这个类就称为一个B

  • 解决springboot启动报错bean找不到的问题

    目录 springboot启动报错bean找不到的原因解决 一.普通的dao,service对应的实例bean不存在 报错示例: 解决方案: 二.由于bean的加载顺序和配置文件的关系 补充:Springboot启动报错之类文件具有错误的版本 61.0, 应为 52.0 启动Springboot项目时候报错 原因 总结: springboot启动报错bean找不到的原因解决 一.普通的dao,service对应的实例bean不存在 报错示例: 1.Failed to configure a Da

  • SpringBoot Bean花式注解方法示例下篇

    目录 1.容器初始化完成后注入bean 2.导入源的编程式处理 3.bean裁定 拓展 4.最终裁定 1.容器初始化完成后注入bean import lombok.Data; import org.springframework.stereotype.Component; @Component("miao") @Data public class Cat { } 被注入的JavaBean import org.springframework.context.annotation.Con

  • Springboot项目中单元测试时注入bean失败的解决方案

    目录 Springboot项目中单元测试时注入bean失败 问题背景 问题描述 问题解决 Springboot单元测试,注入失败,报空指针错误 下面是测试类 Springboot项目中单元测试时注入bean失败 问题背景 最近公司项目搭了一个springboot项目进行开发,在单元测试时,由于生成项目后可能哪个同事把项目生产的test文件目录删了,也不知道是项目生成时test目录没有生成,需要自己建立一个test目录进行测试. 就是下图中的红框部分... 问题描述 在上图中的test目录建好之后

  • SpringBoot启动失败的解决方法:A component required a bean of type ‘xxxxxxx‘ that could not be found.

    目录 问题描述 分析问题 解决问题 不注入bean的方式 使用@Component 扩展:@Component解释说明 问题描述 今天写了一个MD5加密加盐工具类,运用到实际业务代码中缺报错了,内容如下: ***************************APPLICATION FAILED TO START*************************** Description: A component required a bean of type 'com.wyh.util.Sa

  • 详解使用Vue.Js结合Jquery Ajax加载数据的两种方式

    整理文档,搜刮出一个使用Vue.Js结合Jquery Ajax加载数据的两种方式的代码,稍微整理精简一下做下分享. 废话不多说,直接上代码 html代码 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>demo</title> <script src="js/jquery.js"

  • Vue加载组件、动态加载组件的几种方式

    什么是组件: 组件是Vue.js最强大的功能之一.组件可以扩展HTML元素,封装可重用的代码.在较高层面上,组件是自定义的元素,Vue.js的编译器为它添加特殊功能.在有些情况下,组件也可以是原生HTML元素的形式,以is特性扩展. 下面一段简单的代码给大家介绍Vue加载组件的几种方式,具体代码如下所示: //正常加载 import index from '../pages/index.vue' import view from '../pages/view.vue' //懒加载 const i

  • 详解SpringBoot静态方法获取bean的三种方式

    目录 方式一  注解@PostConstruct 方式二  启动类ApplicationContext 方式三 手动注入ApplicationContext 方式一  注解@PostConstruct import com.example.javautilsproject.service.AutoMethodDemoService; import org.springframework.beans.factory.annotation.Autowired; import org.springfr

  • Tensorflow 2.4加载处理图片的三种方式详解

    目录 前言 数据准备 使用内置函数读取并处理磁盘数据 自定义方式读取和处理磁盘数据 从网络上下载数据 前言 本文通过使用 cpu 版本的 tensorflow 2.4 ,介绍三种方式进行加载和预处理图片数据. 这里我们要确保 tensorflow 在 2.4 版本以上 ,python 在 3.8 版本以上,因为版本太低有些内置函数无法使用,然后要提前安装好 pillow 和 tensorflow_datasets ,方便进行后续的数据加载和处理工作. 由于本文不对模型进行质量保证,只介绍数据的加

  • Spring 加载 Application Context五种方式小结

    目录 Spring创建出现的错误,ApplicationContext错误 解决方案 容器是Spring框架的核心.Spring 容器使用DI管理构成应用的组件.Spring容器使用DI管理构成应用的组件.这些对象更简单.易于理解,更易于重用并且更易于进行单元测试. Spring 容器 Spring 容器并不是只有一个.Spring 自带了多个容器实现,可以归为两种不同的类型. Bean工厂(由org.springframework,beansfactory.BeanFactory 接口定义)是

  • js前端实现图片懒加载(lazyload)的两种方式

    在实际的项目开发中,我们通常会遇见这样的场景:一个页面有很多图片,而首屏出现的图片大概就一两张,那么我们还要一次性把所有图片都加载出来吗?显然这是愚蠢的,不仅影响页面渲染速度,还浪费带宽.这也就是们通常所说的首屏加载,技术上现实其中要用的技术就是图片懒加载--到可视区域再加载. 思路: 将页面里所有img属性src属性用data-xx代替,当页面滚动直至此图片出现在可视区域时,用js取到该图片的data-xx的值赋给src. 关于各种宽高: 页可见区域宽: document.body.clien

  • SpringBoot加载配置文件的实现方式总结

    目录 一.简介 二.代码实践 2.1.通过@value注解实现参数加载 2.2.通过@ConfigurationProperties注解实现参数加载 2.3.通过@PropertySource注解实现配置文件加载 2.4.通过自定义环境处理类,实现配置文件的加载 2.5.最后,我们来介绍一下yml文件读取 三.小结 一.简介 在实际的项目开发过程中,我们经常需要将某些变量从代码里面抽离出来,放在配置文件里面,以便更加统一.灵活的管理服务配置信息.比如,数据库.eureka.zookeeper.r

  • Spring多种加载Bean方式解析

    1 定义bean的方式 常见的定义Bean的方式有: 通过xml的方式,例如: <bean id="dictionaryRelMap" class="java.util.HashMap"/> 通过注解的方式,在Class上使用@Component等注解,例如 @Component public class xxxServicer{ .... } 通过在@Configuration类下的@Bean的方式,例如 @Configuration public c

  • SpringBoot通过注解注入Bean的几种方式解析

    目录 1.背景 xml扫描包的方式 2.通过注解注入的一般形式 2.1.Bean类 2.2.Configuration类 2.3.Test类 3.通过构造方法注入Bean 3.1.Bean类 3.2.AnotherBean类 3.3.Configuration类 4.通过set方法注入Bean 4.1.MyBean类 4.2.Configuration类和Test类 5.通过属性去注入Bean 6.通过List注入Bean 6.1.MyBeanList类 6.2.MyConfiguration类

  • Python加载数据的5种不同方式(收藏)

    数据是数据科学家的基础,因此了解许多加载数据进行分析的方法至关重要.在这里,我们将介绍五种Python数据输入技术,并提供代码示例供您参考. 作为初学者,您可能只知道一种使用p andas.read_csv函数读取数据的方式(通常以CSV格式).它是最成熟,功能最强大的功能之一,但其他方法很有帮助,有时肯定会派上用场. 我要讨论的方法是: Manual 函数 loadtxt 函数 genfromtxtf 函数 read_csv 函数 Pickle 我们将用于加载数据的数据集可以在此处找到 .它被

随机推荐