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

 更新时间:2023年02月10日 11:27:05   作者:零维展开智子  
这篇文章主要介绍了SpringBoot Bean花式注解方法,很多时候我们需要根据不同的条件在容器中加载不同的Bean,或者根据不同的条件来选择是否在容器中加载某个Bean

1.容器初始化完成后注入bean

import lombok.Data;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
public class Cat {
}

被注入的JavaBean

import org.springframework.context.annotation.Configuration;
@Configuration
public class Config5 {
}

被加载的配置类

import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        context.registerBean(Cat.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

在加载配置类的时候,普通的ApplicationContext不具备该功能。

可以看到其还具有扫描JavaBean注解的功能,直接把名字装配了,没有自定义名字的话就是类名首字母小写。

那么同一个实体类被加载多次会怎么样呢?

import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
@NoArgsConstructor
public class Cat {
    String shout;
    public Cat(String shout) {
        this.shout = shout;
    }
}
import org.springframework.context.annotation.Configuration;
@Configuration
public class Config5 {
}
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        context.registerBean(Cat.class,"1");
        context.registerBean(Cat.class,"2");
        context.registerBean(Cat.class,"3");
        Cat miao = context.getBean("miao",Cat.class);
        System.out.println(miao.getShout());
    }
}

可以看到如果被加载多次的话,后面会覆盖前面的。

这个和我们在配置yml文件属性时有异曲同工之妙,配置了就是你的配置,没有配置就是默认的,你的配置会覆盖默认的配置,其中那些配置背后就是一个一个的bean对象罢了。

2.导入源的编程式处理

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    String shout;
}
import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        return new String[]{"yi.beans.Cat"};
    }
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import yi.beans.MyImportSelector;
@Configuration
@Import(MyImportSelector.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

可以看到注册了bean,并且还识别到了注解的value值。

不过这种方式还仅不于此,还可以做很多判定。

import org.springframework.context.annotation.ImportSelector;
import org.springframework.core.type.AnnotationMetadata;
public class MyImportSelector implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata annotationMetadata) {
        boolean b = annotationMetadata.hasAnnotation("org.springframework.context.annotation.Configuration");
        if (b){     //判断是否包含这个注解
            return new String[]{"yi.beans.Cat"};
        }else {
            return new String[]{"yi.beans.Dog"};
        }
    }
}
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import yi.beans.MyImportSelector;
//@Configuration
@Import(MyImportSelector.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.Cat;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

可以看到,我们通过API可以达到多种多样的效果,不仅有查看注解是否存在啊,还能获取注解的所有参数等等。

@Configuration注解如果不被@ComponentScan扫描的话,直接被容器加载。是可以省略的,所以后面我是用@Import也是可以的。

3.bean裁定

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.stereotype.Component;
@Component("miao")
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Cat {
    String shout;
}

实体类我通过注解给它的bean赋了名字。

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 MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(Cat.class).getBeanDefinition();
        registry.registerBeanDefinition("mao",beanDefinition);
    }
}

AnnotationMetadata这个属性我忽略了,因为这就是上一个定义bean的方式,可以通过元数据对其条件判断,你可以结合到一块。下面是定义了bean的名字,不过还有许多ApI你可以慢慢看有空的时候。

import org.springframework.context.annotation.Import;
import yi.beans.MyImportBeanDefinitionRegistrar;
@Import(MyImportBeanDefinitionRegistrar.class)
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
    }
}

可以看到这里注解的value值被覆盖了,在之前的方法中,一直都获取的是注解的value值为bean的名字,由此说明,这种方式的权限也开放了不少。

拓展

那么如果我使用这种方式加载同一个bean加载了多次,是哪个生效呢?我来用接口模拟。可以发现是最后一个被加载的在生效。可能有人会疑问,为什么bean名字一样,编译时不报异常呢?

因为一个项目是分布式的情况下,一个配置bean可能会被多个人修改,需要确保这些bean能够覆盖达到刷新的效果,我猜的,不一定对。

public interface BookService {
    void check();
}
import yi.beans.BookService;
public class BookServiceImpl1 implements BookService {
    @Override
    public void check() {
        System.out.println("书籍是人类进步的阶梯");
    }
}
import yi.beans.BookService;
public class BookServiceImpl2 implements BookService {
    @Override
    public void check() {
        System.out.println("书籍是人类进步的阶梯");
    }
}
import yi.beans.BookService;
public class BookServiceImpl3 implements BookService {
    @Override
    public void check() {
        System.out.println("书籍是人类进步的阶梯");
    }
}
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;
import yi.beans.impl.BookServiceImpl1;
public class MyImportBeanDefinitionRegistrar1 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl1.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}
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;
import yi.beans.impl.BookServiceImpl2;
public class MyImportBeanDefinitionRegistrar2 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}
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;
import yi.beans.impl.BookServiceImpl3;
public class MyImportBeanDefinitionRegistrar3 implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
        BeanDefinition beanDefinition= BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl3.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService",beanDefinition);
    }
}
import org.springframework.context.annotation.Import;
import yi.beans.*;
@Import({MyImportBeanDefinitionRegistrar1.class, MyImportBeanDefinitionRegistrar2.class, MyImportBeanDefinitionRegistrar3.class})
public class Config5 {
}
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.BookService;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        BookService bookService = context.getBean("bookService", BookService.class);
        System.out.println(bookService.getClass());
    }
}

4.最终裁定

基于第七种方式,我们要是就是想要加载某个bean,又不想被其他人的覆盖该怎么办呢?也就是说我们这个类无论加载到哪个位置,都不会被覆盖。请看第八种方式。

在第七种拓展的基础上,我们再加如下:

import yi.beans.BookService;
public class BookServiceImpl4 implements BookService {
    @Override
    public void check() {
        System.out.println("书籍是人类进步的阶梯");
    }
}

再加一个实现类。

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.BeanDefinitionRegistryPostProcessor;
import yi.beans.impl.BookServiceImpl4;
public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry beanDefinitionRegistry) throws BeansException {
        AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl4.class).getBeanDefinition();
        beanDefinitionRegistry.registerBeanDefinition("bookService",beanDefinition);
    }
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory configurableListableBeanFactory) throws BeansException {
    }
}

通过BeanDefinition的注册器实名bean,实现对bean的最终裁定。

import org.springframework.context.annotation.Import;
import yi.beans.*;
@Import({MyImportBeanDefinitionRegistrar1.class, MyImportBeanDefinitionRegistrar2.class, MyPostProcessor.class, MyImportBeanDefinitionRegistrar3.class,})
public class Config5 {
}

可以看到,我将该类没有放到最后。

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import yi.beans.BookService;
import yi.config.Config5;
public class App2 {
    public static void main(String[] args) {
        ApplicationContext context=new AnnotationConfigApplicationContext(Config5.class);
        String[] names = context.getBeanDefinitionNames();
        for (String name : names) {
            System.out.println(name);
        }
        BookService bookService = context.getBean("bookService", BookService.class);
        System.out.println(bookService.getClass());
    }
}

该类注册的bean没有被覆盖耶。权限是不是更开放了。bean的加载就到此为止。了解这些,springboot的源码你读起来就不会那么费劲了。

到此这篇关于SpringBoot Bean花式注解方法示例下篇的文章就介绍到这了,更多相关SpringBoot Bean注解方法内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • IDEA maven项目中刷新依赖的两种方法小结

    IDEA maven项目中刷新依赖的两种方法小结

    这篇文章主要介绍了IDEA maven项目中刷新依赖的两种方法小结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03
  • Spring Boot项目部署命令java -jar的各种参数及作用详解

    Spring Boot项目部署命令java -jar的各种参数及作用详解

    这篇文章主要介绍了Spring Boot项目部署命令java -jar的各种参数及作用的相关资料,包括设置内存大小、垃圾回收器、线程栈大小、系统属性等,还介绍了SpringBoot专用参数,如修改端口、指定配置文件等,需要的朋友可以参考下
    2025-04-04
  • Java实现布隆过滤器的方法步骤

    Java实现布隆过滤器的方法步骤

    布隆过滤器是可以用于判断一个元素是不是在一个集合里,并且相比于其它的数据结构,布隆过滤器在空间和时间方面都有巨大的优势。下面这篇文章主要给大家介绍了关于Java实现布隆过滤器的相关资料,需要的朋友可以参考下
    2018-11-11
  • 浅析Java中ConcurrentHashMap的存储流程

    浅析Java中ConcurrentHashMap的存储流程

    ConcurrentHashMap技术在互联网技术使用如此广泛,几乎所有的后端技术面试官都要在ConcurrentHashMap技术的使用和原理方面对小伙伴们进行360°的刁难,本文详细给大家介绍一下ConcurrentHashMap的存储流程,需要的朋友可以参考下
    2023-05-05
  • Java重点梳理类与对象核心原理

    Java重点梳理类与对象核心原理

    类(class)和对象(object)是两种以计算机为载体的计算机语言的合称。对象是对客观事物的抽象,类是对对象的抽象。类是一种抽象的数据类型
    2022-07-07
  • Java判断数字位数的方法总结

    Java判断数字位数的方法总结

    本文给大家整理了Java判断数字位数的两种常用方法,对此有兴趣的可以跟着小编一起学习下。
    2018-02-02
  • Java Swing JLabel标签的使用方法

    Java Swing JLabel标签的使用方法

    这篇文章主要介绍了Java Swing JLabel标签的使用方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-12-12
  • 详解Java面向对象中的继承

    详解Java面向对象中的继承

    这篇文章主要介绍了详解Java面向对象中的继承,继承提高代码的复用性:通过继承,子类可以直接使用父类的属性和方法,不需要重复定义,需要的朋友可以参考下
    2023-05-05
  • 关于@RequestBody和@RequestParam注解的使用详解

    关于@RequestBody和@RequestParam注解的使用详解

    这篇文章主要介绍了关于@RequestBody和@RequestParam注解的使用详解,本文十分具有参考意义,希望可以帮助到你,如果有错误的地方还望不吝赐教
    2023-03-03
  • Eclipse IDE可支持Java 14編程

    Eclipse IDE可支持Java 14編程

    这篇文章主要介绍了Eclipse IDE可支持Java 14編程,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-04-04

最新评论