iis服务器助手广告广告
返回顶部
首页 > 资讯 > 后端开发 > Python >Spring创建bean的几种方式及使用场景
  • 619
分享到

Spring创建bean的几种方式及使用场景

Spring创建beanSpringbean 2023-05-18 11:05:38 619人浏览 安东尼

Python 官方文档:入门教程 => 点击学习

摘要

目录1、@Configuration注解2、@Bean注解3、@Import注解3.1、导入标记有@Configuration的配置类3.2、导入ImportSelector的实现类

本篇我们讲解下使用spring创建bean的几种方式,创建bean,也可以叫组件注册,就是把单例bean放到spring容器中。我们定义如下工程结构:

sping
--src
----main
      java
        com.xk.spring (包路径)
        --bean (普通类所在的包名)
        --config   (用来写各种配置类)
        --service   (用来编写服务层)
      resources
        --(本目录下用于存放各类资源配置文件,后面测试会用到)
----test
--pom.xml

在bean包下面定义Person类,用于演示

package com.xk.spring.bean;

public class Person {
    private Integer id;
    private String name;
    private Integer age;
    public Person(){}
    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public Integer getAge() {
        return age;
    }
    public void setAge(Integer age) {
        this.age = age;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    @Override
    public String toString() {
        return "name:"+this.name+" age:"+this.age+" id:"+this.id;
    }
}

另外再定义一个打印spring容器中bean名称的方法,在单元测试中会使用。

 void printBeanNames(ApplicationContext applicationContext){
        String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
        for (String definitionName : beanDefinitionNames) {
            System.out.println("----"+definitionName);
        }
    }

1、@Configuration注解

首先我们先说下@Configuration这个注解,在SpringBoot应用中,经常可以看到引用的各类jar包中定义的类中用到了这个注解。该注解只能作用于类上,在一个类上面加@Configuration注解,就说明该类是一个配置类,该配置类也会作为一个bean被存放到spring容器中,bean的名称就是类的名称(首字母小写)。如下所示,MyConfig是个配置类,spring容器中就拥有了一个bean名称为myConfig的bean。

package com.xk.spring.config;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
}

我们编写一个单元测试,来打印下spring容器中bean的名称。

    @Test
    public void testMyConfig(){
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig.class);
        printBeanNames(applicationContext);
    }

执行testMyConfig单元测试,得到结果如下:

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig

前面几个bean,是spring内置的bean,最后一个bean就是我们定义的这个配置类,bean名称为myConfig.

2、@Bean注解

@Bean作用于配置类的方法上,要求该方法有返回值,返回的值就是spring容器中的bean,bean名称默认就是取方法的名称。比如下面的代码说明创建一个名称为onePerson的bean。

package com.xk.spring.config;
import com.xk.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class MyConfig {
    @Bean
    public Person onePerson(){
        return new Person("xx",12);
    }
}

我们再次执行上面的testMyConfig单元测试,会得到如下结果:

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig ----onePerson

可以看到,相比于第1步中的结果,spring容器中多了一个叫onePerson的bean,而onePerson也就是方法onePerson的方法名称。

3、@Import注解

@Import注解只能作用于类上面,可以导入标记有@Configuration的配置类、ImportSelector和ImportBeanDefinitionRegistrar的实现类,还能导入普通的类(不含spring注解),所谓导入,就是将类的实例注册到spring容器中。该注解必须和@Configuration注解结合使用,而且正常情况下,只有当某个组件不会被spring自动注册时(比如当我们使用ComponentScan指定了某个包扫描路径),才会使用该注解。spring-boot-autoconfigure.jar包大量使用了该注解,感兴趣的可以去参考下。

3.1、导入标记有@Configuration的配置类

通过@Import注解导入配置类,会把该配置类中定义的bean都注册到spring容器中,同时spring也会该该配置类创建一个bean,bean的名称就是该类的全路径名。

我们定义一个ImportConfig配置类,内容如下:

package com.xk.spring.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({MyConfig.class})
@Configuration
public class ImportConfig {
}

我们在配置类上通过@Import注解导入另外的配置类MyConfig,会把MyConfig配置类以及在MyConfig类中定义(注册)的bean都导入到spring容器中。

我们编写一个单元测试,来打印下spring容器中bean的名称。

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.config.MyConfig ----onePerson

注意,此时容器中不仅有importConfig这个bean,也有MyConfig配置类中定义的onePerson这个bean。而导入的MyConfig配置类在spring容器中对应的bean名称是MyConfig类的全路径名com.xk.spring.config.MyConfig。特别提醒,由于MyConfig本身是个配置类,如果spring本身能自动扫描注册该类(比如配置了@ComponentScan包含config包路径),那么我们再通过@Import这种方式导入MyConfig,MyConfig在spring容器中对应的名称就变成了myConfig,也就是bean的名称是类名(首字母小写)。当然,正如前面所说,如果我们的配置类能被spring自动扫描注册,我们就不会使用@Import这种方式导入配置类。

另外,需要格外注意的是,我们通过@Import导入的类本身会被当做配置类,所以即使此处MyConfig类没有加@Configuration注解,通过配置@Import({Myconfig.class}),也会把MyConfig类里面定义的bean注册到spring容器,此时MyConfig类对应的bean名称就是类的全路径名。但我们一般不这么做,如果一个类中定义了bean,我们很自然会为该类加上@Configuration注解。

3.2、导入ImportSelector的实现类

ImportSelector是个接口,它的定义如下:

public interface ImportSelector {
	
	String[] selectImports(AnnotationMetadata importinGClaSSMetadata);
	
	@Nullable
	default Predicate<String> getExclusionFilter() {
		return null;
	}
}

我们定义一个MyImportSelector类,实现该接口,内容如下:

package com.xk.spring.importselector;
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;

public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        return new String[]{"com.xk.spring.bean.Person"};
    }
}

然后我们修改下我们的ImportConfig类,通过@Import导入MyImportSelector类,内容如下:

package com.xk.spring.config;
import com.xk.spring.importselector.MyImportSelector;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({MyImportSelector.class})
@Configuration
public class ImportConfig {
}

最后我们执行上面的testImportConfig单元测试,可以得到下面的结果:

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.bean.Person

可以看到,通过导入MyImportSelector类,spring自动帮我们生成了Person的bean实例,而Person对应的bean的名称就是Person类的全路径名。

3.3、导入ImportBeanDefinitionRegistrar的实现类

ImportBeanDefinitionRegistrar也是个接口,它的定义如下:

public interface ImportBeanDefinitionRegistrar {
	
	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry,
			BeanNameGenerator importBeanNameGenerator) {
		registerBeanDefinitions(importingClassMetadata, registry);
	}
	
	default void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
	}
}

我们定义一个MyImportBeanDefinitionRegistrar类,实现ImportBeanDefinitionRegistrar接口,定义如下:

package com.xk.spring.importbeandefinitionregistrar;
import com.xk.spring.bean.Person;
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 importingClassMetadata, BeanDefinitionRegistry registry) {
        boolean flag = registry.containsBeanDefinition("com.xk.spring.bean.Person");
        if(!flag){
            RootBeanDefinition rootBeanDefinition = new RootBeanDefinition(Person.class);
            //注册person,并且自定义bean的名称为myPerson
            registry.registerBeanDefinition("myPerson",rootBeanDefinition);
        }
    }
}

然后我们修改下我们的ImportConfig配置类,使用@Import导入MyImportBeanDefinitionRegistrar类,内容如下:

package com.xk.spring.config;
import com.xk.spring.importbeandefinitionregistrar.MyImportBeanDefinitionRegistrar;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({MyImportBeanDefinitionRegistrar.class})
@Configuration
public class ImportConfig {
}

最后我们执行testImportConfig单元测试,会得到如下的结果:

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----myPerson

可以看到,我们通过这种方式成功的导入Person类对应的bean,而且bean的名称就是我们自定义的myPerson。

3.4、导入普通的类

我们还可以通过@Import导入普通类到spring容器,导入之后的bean的名称就是类名的全路径。这些普通类可以什么注解都不加,比如没有@Component注解,也没有@Configuration注解。就拿我们的Person类来说,我们可以通过@Import({Person.class})的方式直接将其导入spring容器,。

修改ImportConfig配置类,内容如下:

package com.xk.spring.config;
import com.xk.spring.bean.Person;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Import({Person.class})
@Configuration
public class ImportConfig {
}

最后执行testImportConfig单元测试,会得出如下结果:

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----com.xk.spring.bean.Person

可以看到,Person类被导入到spring容器,并且对应的bean名称是Person类的全路径名。

4、@ImportResource注解

传统的spring项目通过使用xml配置文件来定义bean信息,然后在WEB.xml中声明我们的spring的xml配置文件。现在我们换种方式,我们可以通过使用@ImportResource注解,将整个的xml配置文件导入到配置类,进而由spring替我们生成对应的bean。

我们在工程的resources资源目录下创建application-beans.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
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--定义person-->
    <bean id="person" class="com.xk.spring.bean.Person">
        <!-- collaborators and configuration for this bean Go here -->
    </bean>
</beans>

然后我们修改ImportConfig配置类,内容如下:

package com.xk.spring.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

@ImportResource({"classpath:/application-beans.xml"})
@Configuration
public class ImportConfig {
}

最后执行testImportResource单元测试,得出结果如下:

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----importConfig ----person

可以看到,通过@ImportResource的方式,我们把在xml配置文件中定义的person这个bean注册到了spring容器中。

5、@ComponentScan注解

@ComponentScan注解可以让spring方便地识别标记了@Component注解的组件,需要和@Configuration注解一起使用。我们在web开发时,经常会使用@Service、@Repository、@Controller、@Configuration、@Component等注解,用来表示mvc不同层次的组件bean。其实前面四种注解的元注解上面都标记了@Component,说明被这四种注解标记的类通过配置@ComponentScan指令,就可以被注册到spring容器中,而它们对应的bean的名称就是类名(首字母小写)。

我们拿@Service为例,在service包下面创建PersonService类,内容如下:

package com.xk.spring.service;
import org.springframework.stereotype.Service;

@Service
public class PersonService {
}

内容很简单,就简单的通过@Service将该类标记为一个组件。接下来我们修改MyConfig类,在它上面加上@ComponentScan注解,内容如下:

package com.xk.spring.config;
import com.xk.spring.bean.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@ComponentScan("com.xk.spring.service")
@Configuration
public class MyConfig {
    @Bean
    public Person onePerson(){
        return new Person("xx",18);
    }
}

最后我们执行下先前定义的testMyConfig单元测试,得到结果如下:

----org.springframework.context.annotation.internalConfigurationAnnotationProcessor ----org.springframework.context.annotation.internalAutowiredAnnotationProcessor ----org.springframework.context.annotation.internalCommonAnnotationProcessor ----org.springframework.context.event.internalEventListenerProcessor ----org.springframework.context.event.internalEventListenerFactory ----myConfig ----personService ----onePerson

可以看到,容器中多了一个personService的bean,而该bean就是对应被我们标记了@Service注解的PersonService。虽然我们config包下面的ImportConfig类也加了@Configuration注解,但由于它不在包扫描的范围,所以spring无法将其自动注册到容器中。

6、使用总结

(1)如果一个类不是ImportSelector或ImportBeanDefinitionRegistrar的子类,当它被@Import导入的时候,它就会被当成一个配置类存在,可以简单理解为它被加了@Configuration注解,那么原本在这个类上面的注解(比如@ComponentScan、@Import、@ImportResource等等)就也会生效。

(2)我们通过springboot开发客户端jar包,提供给其他团队使用时,如果里面涉及到多个配置类,并且需要实现自动配置的功能,那么可以在配置类A上面通过@Import({B.class})将配置类B导入,然后再根据springboot自动配置类编写规范,将配置类A写到类路径下面的META-INF/spring.factories文件中。

(3)@ComponentScan注解可以让我们指定扫描的包路径,假如我们公司里面用的项目都以com.xk开头,我们的项目的包名以com.xk.spring开始,其他的团队的项目包名以com.xk.mybatis开始。如果com.xk.mybatis中也配置了一些组件,但是我们并不想将它们注册到spring容器中,就可以通过配置@ComponentScan({"com.xk.spring"})的方式只扫描我们项目下的包,也相当于排除掉其他路径的包。

结束语

到此这篇关于Spring创建bean的几种方式及使用场景的文章就介绍到这了,更多相关Spring创建bean内容请搜索编程网以前的文章或继续浏览下面的相关文章希望大家以后多多支持编程网!

--结束END--

本文标题: Spring创建bean的几种方式及使用场景

本文链接: https://www.lsjlt.com/news/211996.html(转载时请注明来源链接)

有问题或投稿请发送至: 邮箱/279061341@qq.com    QQ/279061341

本篇文章演示代码以及资料文档资料下载

下载Word文档到电脑,方便收藏和打印~

下载Word文档
猜你喜欢
  • Spring创建bean的几种方式及使用场景
    目录1、@Configuration注解2、@Bean注解3、@Import注解3.1、导入标记有@Configuration的配置类3.2、导入ImportSelector的实现类...
    99+
    2023-05-18
    Spring创建bean Spring bean
  • Spring创建bean实例的几种方式分享
    目录前言环境通过bean的class属性创建实例(带参构造器)工厂方法(静态工厂方法)工厂方法(实例工厂方法)工厂bean总结前言 Spring常见的创建bean实例的方式有: 1....
    99+
    2024-04-02
  • git版本库介绍及本地创建的三种场景方式
    目录1、Git版本库介绍2、创建本地版本库场景一:创建一个空的本地版本库。场景二:项目中已存在文件时,创建该项目的本地版本库。场景三:在GitHub网站上创建仓库,克隆到本地。1、G...
    99+
    2024-04-02
  • Spring创建bean的方式有哪些
    这篇文章主要讲解了“Spring创建bean的方式有哪些”,文中的讲解内容简单清晰,易于学习与理解,下面请大家跟着小编的思路慢慢深入,一起来研究和学习“Spring创建bean的方式有哪些”吧!环境Ubuntu 22.04IntelliJ ...
    99+
    2023-07-02
  • Spring @Bean注解的使用场景是什么
    本篇内容介绍了“Spring @Bean注解的使用场景是什么”的有关知识,在实际案例的操作过程中,不少人都会遇到这样的困境,接下来就让小编带领大家学习一下如何处理这些情况吧!希望大家仔细阅读,能够学有所成!一、简单介绍翻看Spri...
    99+
    2023-07-05
  • MySQL几种创建索引的方式
    一、创建表时创建索引 key 索引名 (column); 二、表创建好后创建索引 通过Alter创建索引 ①PRIMARY  KEY(主键索引)         mysql > ALTER  TABLE  `table_name`  A...
    99+
    2023-09-01
    mysql
  • Spring@Bean注解的使用场景与案例实现
    目录一、简单介绍二、注解说明1. 注解源码2. 注解使用场景三、使用案例1. 案例描述2. 案例实现新建注入到IOC容器中的User类创建Spring的配置类BeanConfig创建...
    99+
    2023-03-10
    Spring @Bean使用案例 Spring @Bean注解
  • 创建 KVM 虚机的几种方式
    1 使用 virt-install 命令2 使用 virt-manager 工具3 使用 qemu-img 和 qemu-kvm ...
    99+
    2023-06-06
  • socket.io断线重连的几种场景及处理方法
    最近有做一个项目,类型聊天室的需求,自然也就选用了socket.io。搭建起来的确快,不管是km上还是外面,大把聊天室的demo,当然,只是demo,简易聊天室,而我们的需求当然不会...
    99+
    2023-03-19
    socketio断开重连 socket断开连接 socket 重连
  • Vue实现组件间通信的几种方式(多种场景)
    目录1、Props 父 >>> 子  (Props)子 >>> 父 ($emit)2、Bus事件总线3、V...
    99+
    2024-04-02
  • 浅谈spring使用策略模式实现多种场景登录方式
     @Autowired注解可以帮我们自动注入我们想要的 Bean。 如果只是简单使用@Autowired会遇到spring IOC容器中一个接口有多个实现的情况,spring无法识别...
    99+
    2024-04-02
  • spring使用策略模式如何实现多种场景登录方式
    这篇文章给大家介绍spring使用策略模式如何实现多种场景登录方式,内容非常详细,感兴趣的小伙伴们可以参考借鉴,希望对大家能有所帮助。 @Autowired注解可以帮我们自动注入我们想要的 Bean。如果只是简单使用@Autowi...
    99+
    2023-06-22
  • Java 中创建线程的几种方式
    Java 是一种面向对象的编程语言,它支持多线程编程。多线程编程是指在一个程序中同时运行多个线程,这些线程可以并行执行,以提高程序的效率和性能。Java 提供了多种创建线程的方法,本文将介绍这些方法以...
    99+
    2023-09-13
    java jvm servlet
  • 理解k8s控制器DaemonSet创建及使用场景
    目录DaemonSet 简介DaemonSet 使用场景DaemonSet 创建查看 DaemonSet更新 DaemonSet删除 DaemonSet其它使用场景容忍性 Toler...
    99+
    2024-04-02
  • Spring IOC创建对象的两种方式
    IOC创建对象的方式 一、 使用无参构造创建对象(默认方式) 创建实体类 注意:属性必须要有set方法,来完成注入 public class User { private S...
    99+
    2024-04-02
  • uniapp中的picker选择器的几种使用场景
    目录一、普通选择器二、多列选择器三、时间选择器四、日期选择器一、普通选择器 <template> <view> <picker @change=...
    99+
    2024-04-02
  • sql创建索引的方式有哪几种
    在SQL中,可以通过以下几种方式来创建索引: 在创建表的时候指定索引:在创建表的SQL语句中,可以通过在字段声明后面添加"...
    99+
    2024-04-09
    sql
  • c#创建数组的方式有哪几种
    在C#中,创建数组的方式有以下几种: 使用数组初始化器: int[] numbers = {1, 2, 3, 4, 5}; ...
    99+
    2024-03-05
    c#
  • CSS的多种背景及使用场景和技巧
    这篇文章主要介绍CSS的多种背景及使用场景和技巧,文中介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们一定要看完!CSS background是最常用的CSS属性之一。然而,并不是所有开发人员都知道使用多种背景。这段时间都在关注使用多种...
    99+
    2023-06-08
  • java创建对象的方式有哪几种
    在Java中,可以通过以下几种方式创建对象:1. 使用new关键字:通过使用new关键字,可以调用类的构造方法实例化一个对象。例如:...
    99+
    2023-10-10
    java
软考高级职称资格查询
编程网,编程工程师的家园,是目前国内优秀的开源技术社区之一,形成了由开源软件库、代码分享、资讯、协作翻译、讨论区和博客等几大频道内容,为IT开发者提供了一个发现、使用、并交流开源技术的平台。
  • 官方手机版

  • 微信公众号

  • 商务合作