SpringBoot向容器注册bean的方法详解
作者:IT利刃出鞘 发布时间:2023-09-02 10:58:22
简介
本文用示例介绍SpringBoot如何向容器注册bean(即:将对象加入容器)。
法1:@Component
(@Controller/@Service/@Repository也可以,因为它里边包含@Component)
默认是加载和Application类所在同一个目录下的所有类,包括所有子目录下的类。
当启动类和@Component分开时,如果启动类在某个包下,需要在启动类中增加注解@ComponentScan,配置需要扫描的包名。例如:
@SpringBootApplication(scanBasePackages="com.test.chapter4")
此注解其实是@ComponentScan的basePackages,通过查看scanBasePackages即可得知。
@SpringBootApplication只会扫描@SpringBootApplication注解标记类包下及其子包的类,将这些类纳入到spring容器,只要类有@Component注解即可。
有的注解的定义中已加入@Component,所以这些注解也会被扫描到:@Controller,@Service,@Configuration,@Bean
@ComponentScan+@Configuration+@Component
DemoConfig在扫描路径之内
@Configuration
@ComponentScan(basePackages = { "com.example.demo.mybeans" })
public class DemoConfig {
}
MyBean1在com.example.demo.mybeans下
@Component
public class MyBean1{
}
法2:@Configuration+@Bean
使用场景:将没有Component等注解的类导入。例如:第三方包里面的组件、将其他jar包中的类。
public class User {
//@Value("Tom")
public String username;
public User(String s) {
this.username = s;
}
}
@Configuration
public class ImportConfig {
@Bean
public User user(){
return new User("Lily");
}
}
@RestController
public class ImportDemoController {
@Autowired
private User user;
@RequestMapping("/importDemo")
public String demo() throws Exception {
String s = user.username;
return "ImportDemo@SpringBoot " + s;
}
}
法3:@Import等
简介
@Import(要导入到容器中的组件);容器会自动注册这个组件,id默认是全类名。(@Import是Spring的注解。)
ImportSelector:返回需要导入的组件的全类名数组;
ImportBeanDefinitionRegistrar:手动注册bean到容器中
@Import方式
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Import({ImportDemoConfig.class})
public @interface EnableImportDemo {
}
public class ImportDemoConfig{
@Bean
public User user(){
return new User("Lily");
}
}
@EnableImportDemo
@SpringBootApplication
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
@RestController
public class ImportDemoController {
@Autowired
private User user;
@RequestMapping("/importDemo")
public String demo() {
String s = user.getName();
return "user.getName():" + s;
}
}
ImportSelector方式
//自定义逻辑返回需要导入的组件
public class MyImportSelector implements ImportSelector {
//返回值,就是到导入到容器中的组件全类名
//AnnotationMetadata:当前标注@Import注解的类的所有注解信息
@Override
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//当前类的所有注解
Set<String> annotationTypes = importingClassMetadata.getAnnotationTypes();
System.out.println("当前配置类的注解信息:"+annotationTypes);
//注意不能返回null,不然会报NullPointException
return new String[]{"com.paopaoedu.springboot.bean.user01","com.paopaoedu.springboot.bean.user02"};
}
}
public class User01 {
public String username;
public User01() {
System.out.println("user01...constructor");
}
}
public class User02 {
public String username;
public User02() {
System.out.println("user02...constructor");
}
}
@Configuration
@Import({ImportDemo.class, MyImportSelector.class})
public class ImportConfig {
@Bean
public User user(){
return new User("Lily");
}
}
@RestController
public class ImportDemoController {
@Autowired
private User user;
@Autowired
private ImportDemo importDemo;
@Autowired
private User01 user01;
@RequestMapping("/importDemo")
public String demo() throws Exception {
importDemo.doSomething();
user01.username = "user01";
String s = user.username;
String s1 = user01.username;
return "ImportDemo@SpringBoot " + s + " " + s1;
}
}
ImportBeanDefinitionRegistrar方式
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:当前类的注解信息
* BeanDefinitionRegistry:BeanDefinition注册类;
* 把所有需要添加到容器中的bean;调用
* BeanDefinitionRegistry.registerBeanDefinition手工注册进来
*/
@Override
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
BeanDefinitionRegistry registry) {
boolean definition = registry.containsBeanDefinition("com.paopaoedu.springboot.bean.User01");
boolean definition2 = registry.containsBeanDefinition("com.paopaoedu.springboot.bean.User02");
if(definition && definition2){
//指定Bean定义信息作用域都可以在这里定义;(Bean的类型,Bean。。。)
RootBeanDefinition beanDefinition = new RootBeanDefinition(User03.class);
//注册一个Bean,指定bean名
registry.registerBeanDefinition("User03", beanDefinition);
}
}
}
public class User03 {
public String username;
public User03() {
System.out.println("user03...constructor");
}
}
使用上和前面的类似就不举例了。
法4:FactoryBean
默认获取到的是工厂bean调用getObject创建的对象。
要获取工厂Bean本身,我们需要给id前面加一个&。例如:&xxxFactoryBean 注意类名是X,这里就是小写的x
public class UserFactoryBean implements FactoryBean<User04> {
@Override
public User04 getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("UserFactoryBean...getObject...");
return new User04("User04");
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return User04.class;
}
//是否单例?
//true:这个bean是单实例,在容器中保存一份
//false:多实例,每次获取都会创建一个新的bean;
@Override
public boolean isSingleton() {
return true;
}
}
public class User04 {
public String username;
public User04(String s) {
String nowtime= DateUtil.now();
username=s+" "+nowtime;
}
}
@Configuration
@Import({ImportDemo.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class})
public class ImportConfig {
// 要获取工厂Bean本身,需要给id前面加一个&,&userFactoryBean
@Bean
public UserFactoryBean userFactoryBean(){
return new UserFactoryBean();
}
@Bean
public User user(){
return new User("Lily");
}
}
@RestController
public class ImportDemoController {
@Autowired
private User user;
@Autowired
private ImportDemo importDemo;
@Autowired
private User01 user01;
@Autowired
private UserFactoryBean userFactoryBean;
@RequestMapping("/importDemo")
public String demo() throws Exception {
importDemo.doSomething();
user01.username = "user01";
String s = user.username;
String s1 = user01.username;
String s4 = userFactoryBean.getObject().username;
return "ImportDemo@SpringBoot " + s + " " + s1 + " " + s4;
}
}
@SpringBootApplication
public class SpringBootLearningApplication {
public static void main(String[] args) {
SpringApplication.run(SpringBootLearningApplication.class, args);
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext("com.paopaoedu.springboot.config");
ImportDemo importDemo = context.getBean(ImportDemo.class);
importDemo.doSomething();
printClassName(context);
Object bean1 = context.getBean("userFactoryBean");
Object bean2 = context.getBean("userFactoryBean");
System.out.println(bean1 == bean2);
}
private static void printClassName(AnnotationConfigApplicationContext annotationConfigApplicationContext){
String[] beanDefinitionNames = annotationConfigApplicationContext.getBeanDefinitionNames();
for (int i = 0; i < beanDefinitionNames.length; i++) {
System.out.println("匹配的类"+beanDefinitionNames[i]);
}
}
}
测试结果
来源:https://blog.csdn.net/feiying0canglang/article/details/124761970


猜你喜欢
- 在这篇文章中,我精选了几个比较适合 Java 编码的 IDEA 主题供小伙伴们选择。另外,我自己用的是 One Dark theme 这款。
- 定义枚举类型时本质上就是在定义一个类,只不过很多细节由编译器帮您补齐了,所以某些程度上,enum关键字的 作用就像是class或interf
- 这篇文章主要介绍了spring boot如何指定启动端口,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的
- 前言EasyCache升级兼容 Springboot2,有个业务系统启动总是会卡住,最后抛出超时异常,如下:java.util.concur
- 目录aop配合反射统一签名验证接口统一签名校验第一种aop 方式实现第二种 * aop配合反射统一签名验证直接上代码,作为记录。CheckS
- private static char[] constant = &
- 提出问题我做的是一个通讯录,用到了选项菜单,每一个菜单项左边我都添加了一个小图标,运行后发现没有显示出来。解决方案利用反射机制,根据对象来寻
- 使用 AppbarLayout 和 MotionLayout 实现常用的布局效果前文我们讲了协调滚动的一些定义方式,我们在开发中常用的几种效
- 由于项目需求,需要为Java提供一套支持事件驱动机制的类库,可以实现类似于C#中的event和delegate机制。众所周知,Java语言本
- 我们经常用简单数据类型,比如int作为泛型Dictionary<TKey,TValue>的key,但有时候我们希望自定义数据类型
- 工作以来,代码越写越多,程序也越来越臃肿,效率越来越低,对于我这样一个追求完美的程序员来说,这是绝对不被允许的,于是除了不断优化程序结构外,
- 看过阿里巴巴开发手册的同学应该都会对Integer临界值127有点印象。原文中写的是:【强制】所有整型包装类对象之间值的比较,全部使用 eq
- 本文实例讲述了Java采用循环链表结构求解约瑟夫问题的方法。分享给大家供大家参考。具体分析如下:这是第一次java考试的试题,对于没看过链表
- 一. break1. 作用break关键字可以用于for、while、do-while及switch语句中,用来跳出整个语句块,结束当前循环
- 正文前: 1. IDEA内存优化(秒开的快感!!)因机器本身的配置而配置:\IntelliJ IDEA8\bin\idea.exe.vmop
- namespace ConsoleApplication2 { class Program { static v
- Android 应用冷启动时,需要从Application开始启动,加载时间就会比较长,容易出现白色或黑色闪屏,观察一下手机上一些 其他AP
- 比较简单的一个控件,就是加些逻辑处理而已,以前貌似是直接监听的,封装起来方便点public class AccountTxtView ext
- 介绍在进行项目开发的时候,刚好需要用到对字符串表达式进行求值的处理场景,因此寻找了几个符合要求的第三方组件LambdaParser、Dyna
- 使用PHP开发的同学都知道array_chunk函数,其作用是将数据进行切割分段,但是在 java中却找不到合适的给List和Map分段的函