SpringBoot中注册Bean的方式汇总

@ComponentScan + @Componet相关注解

@Componet相关注解有@Configuration、@Controller、@Service、@Repository,配合@ComponentScan就能被扫描注册到Spring容器中。

定义我们需要注册的类

@Configuration
public class ForlanConfig {

	@Bean
	public ForlanBean forlanBean1(){
		return new ForlanBean();
	}
}

@Component
// @Controller
// @Service
// @Repository
public class ForlanComponent {

	@Bean
	public ForlanBean forlanBean2(){
		return new ForlanBean();
	}
}

public class ForlanBean {
}

验证如下:

public static void main(String[] args) {
	ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
	System.out.println(applicationContext.getBean("forlanConfig"));
	System.out.println(applicationContext.getBean("forlanComponent"));
}

// 输出如下:
cn.forlan.ForlanConfig$$EnhancerBySpringCGLIB$$e43dabb2@1305c126
cn.forlan.ForlanComponent@43af351a

@Bean

前面已经定义好需要注册的类,直接验证即可

验证如下:

public static void main(String[] args) {
	ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
	System.out.println(applicationContext.getBean("forlanBean1"));
	System.out.println(applicationContext.getBean("forlanBean2"));
}

// 输出如下:
cn.forlan.ForlanBean@64279ab
cn.forlan.ForlanBean@6650a6c

@Import

它可以导入的类有:Component, Configuration, ImportSelector, ImportBeanDefinitionRegistrar, ImportResource

定义我们需要注册的类

public class CaffeineForlanCache {
}

public class RedisForlanCache {
}

public class ForlanCustomize {
	private String name;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}
}

实现ImportSelector

public class ForlanImportSelector implements ImportSelector {
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		Map<String, Object> annotationAttributes = importingClassMetadata.getAnnotationAttributes(EnableForlanCache.class.getName());
		//通过 不同type注入不同的缓存到容器中
		CacheType cacheType = (CacheType) annotationAttributes.get("cacheType");
		if(cacheType.equals(CacheType.CAFFEINE)){
			return new String[]{CaffeineForlanCache.class.getName()};
		}else{
			return new String[]{RedisForlanCache.class.getName()};
		}
	}
} 

实现ImportBeanDefinitionRegistrar

public class ForlanBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(ForlanCustomize.class)
				.addPropertyValue("name", "forlan").getBeanDefinition();
		registry.registerBeanDefinition("forlanCustomize", beanDefinition);
	}
} 

定义注解导入

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Import({ForlanImportSelector.class, ForlanBeanDefinitionRegistrar.class})
public @interface EnableForlanCache {
	CacheType cacheType() default CacheType.REDIS;
}

验证如下:

@EnableForlanCache(cacheType = CacheType.CAFFEINE)
public class Application {

	public static void main(String[] args) {
		ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
		System.out.println(applicationContext.getBean("forlanBean1"));
		System.out.println(applicationContext.getBean("forlanBean2"));
	}
}

// 输出如下:
cn.forlan.ForlanCustomize@245cb8df
cn.forlan.CaffeineForlanCache@578c3fd9
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'cn.forlan.RedisForlanCache' available

spring.factories

定义我们需要注册的类

public class ForlanAutoConfiguration {
}

在resources\META-INF下新建spring.factories,填写内容,SpringBoot在启动时,就会自动注入

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
cn.forlan.ForlanAutoConfiguration

验证如下:

public static void main(String[] args) {
	ConfigurableApplicationContext applicationContext = SpringApplication.run(Application.class, args);
	System.out.println(applicationContext.getBean(ForlanAutoConfiguration.class));
	System.out.println(applicationContext.getBean("cn.forlan.ForlanAutoConfiguration"));
}

// 输出如下:
cn.forlan.ForlanAutoConfiguration@19d53ab4
cn.forlan.ForlanAutoConfiguration@19d53ab4

注:这种方式的注入的BeanName为路径+类名

总结

总的来说,一共有如下几种方式可以注册bean:

  • @ComponentScan + @Componet相关注解
  • 使用@Bean注解
  • 使用@Import注解
  • spring.factories

@Configuration和@Component的主要区别?

使用场景:@Configuration主要用于定义配置类,其中包含了Bean的定义和配置;而@Component适用于任何需要被Spring管理的类。
功能:@Configuration主要用于配置类的定义和初始化Bean;而@Component主要用于组件的自动扫描和注册。

@Bean是不是必须和@Configuration一起使用?

不是的,尽管@Bean注解常常出现在带有@Configuration注解的配置类中,用于定义和初始化Spring容器中的Bean,但它也可以单独使用。@Bean注解的主要作用是告诉Spring框架,被该注解标注的方法将返回一个对象,这个对象需要被注册到Spring容器中。在非配置类中使用@Bean注解,只需要确保该方法能够被Spring扫描到即可。

@Import导入配置类有意义?

总结来说,@Import导入的类本身不是Bean,而是用于扩展Spring容器配置的工具。它可以定义或注册其他的Bean,但你不能直接通过applicationContext.getBean()获取这些导入类的实例。相反,你应该获取它们定义或注册的Bean的实例。它的主要价值在于动态注入Bean。

出现异常:java.lang.NoClassDefFoundError: Could not initialize class org.springframework.beans.factory.BeanDefinitionStoreException

原因是这个类写的有问题,ForlanImportSelector根本就没有初始化,不是是当前类
在这里插入图片描述

相关推荐

  1. SpringBootWebSokcet无法注入Bean对象解决方案

    2024-04-10 12:44:01       53 阅读
  2. springboot 重新注册 bean

    2024-04-10 12:44:01       24 阅读
  3. Spring Bean获取方法 (手动注入bean)超级实用

    2024-04-10 12:44:01       63 阅读
  4. SpringBoot】如何在 Utils 工具类注入 Bean

    2024-04-10 12:44:01       50 阅读

最近更新

  1. docker php8.1+nginx base 镜像 dockerfile 配置

    2024-04-10 12:44:01       94 阅读
  2. Could not load dynamic library ‘cudart64_100.dll‘

    2024-04-10 12:44:01       100 阅读
  3. 在Django里面运行非项目文件

    2024-04-10 12:44:01       82 阅读
  4. Python语言-面向对象

    2024-04-10 12:44:01       91 阅读

热门阅读

  1. 为什么K8s需要服务网格Istio?

    2024-04-10 12:44:01       29 阅读
  2. 【御控物联】 2、物联网构成

    2024-04-10 12:44:01       30 阅读
  3. systemctl stop与信号

    2024-04-10 12:44:01       32 阅读
  4. 一篇文章说清楚 golang之interface

    2024-04-10 12:44:01       34 阅读
  5. 汽车变速器原理?

    2024-04-10 12:44:01       33 阅读
  6. 2023第十四届蓝桥杯省赛C/C++大学A组题解

    2024-04-10 12:44:01       34 阅读