【springboot原理篇】Bean的加载方式,面试必看

简介: 【springboot原理篇】Bean的加载方式,面试必看

🌈键盘敲烂,年薪30万🌈



一、上古时代原始方式:

📕XML文件
~~bean定义
  • 配置自己的或者第三方的bean:
  • id:指定bean的名称 class指定bean的位置
<!--声明自定义bean-->
    <bean id="dog" class="com.itpan.domain.Dog"/>
    <bean class="com.itpan.domain.Cat"/>
    <!--声明第三方bean-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"/>

 

👀演示获取bean:
    void te1(){
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationcontext1.xml");
        System.out.println(ctx.getBean("dog")); // 获取自定义baen
        System.out.println(ctx.getBean(Cat.class));
        System.out.println(ctx.getBean("dataSource")); // 获取第三方bean
        //获取所有的bean
        System.out.println("================");
        for (String name : ctx.getBeanDefinitionNames()) {
            System.out.println(name);
        }
 
    }
❌缺点:

太麻烦,且可读性太差,bean一旦多了就不知道哪些被加载了,哪些没被加载。

📕注解方式:
~~@component
  • 只要在你的类上加上@component注解,就代表这个类要交给IOC容器管理
  • 但这还不够,java文件这么多,IOC不能所有文件都扫描一遍吧,所以还要在XML配置文件里面指定扫描路径。
  • component(value = "可指定bean的名称") 等同于z在XML里面的id
~~指定扫描路径:

开启命名空间需要动5个地方:

👀演示获取bean
    @Test
    void te2(){
        // 通过注解加载的bean
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("applicationcontext2.xml");
        System.out.println(ctx.getBean("dog")); // 获取自己的bean
        System.out.println(ctx.getBean("dataSource")); // 获取第三方的bean
        System.out.println("===============");
        // 获取容器中的所哟bean
        for (String name : ctx.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }
📕XML太繁琐:

XML文件里面的内容都是固定的,只有bean的定义不同,那么能不能省区XML文件呢???

 

二、现代科技配置类

🐟配置类作用:

配置类说白了就是加载bean的,当然配置类本身也会变为bean(重要),只要在配置类上加相应的注解,spring会自动扫描相应的包来加载bean。

🐟@componentScan

@componentScan就替代了XML里面那一大坨代码,但是扫描哪些包spring还不知道,所以要指定包扫描路径:@component({"指定扫描哪些包下的bean","xxx"})。

小细节:如果不加扫描路径,默认扫描本包及其子包下的类。

🐟@configuration

同上面的注解一样,它亦可以代替XML文件,表示该类是一个配置类,但是它们两个真的相同吗?

👀演示获取bean
    @Test
    void te3(){
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig1.class);
        for (String name : ctx.getBeanDefinitionNames()) {
            System.out.println(name);
        }
    }

注意:

获取配置类的bean是通过annotationconfigapplicationcontext这个对象的相关方法,那么@cofiguration与@componentScan有什么不同吗,如果相同用为什么会出现两个注解。

 

⭐本文重点,没有之一⭐
  • 相同点:加上这两个注解都会将该类变为配置类,成为IOC容器的bean,假如你获取bean的方式为annotationconfigapplicationcontext,那么这两个注解的作用一样。
  • 但是,如果你加载bean的方式是通过别的包扫描这个包,那么你不加@configuration这个注解就扫描不上,扫描不上就成为不了bean对象,到时候就干瞪眼了。

@configuration这个注解有个属性是proxybeanmethods,它的作用是使用哪种代理模式。

看完下面这个例子你就懂了

运行结果:

把proxybeanmethod改为false:

总结:

       当proxybeanmethods为true是,调用里面的方法创建的bean是代理对象调用的,也就是每一次调用方法如果IOC容器俩面有这个bean对象,就会使用这个对象,如果没有,new一个,以后用到了就会返回这个对象,所有三个bean对象一致。

       当proxybeanmethods为false是,代理对象每一次调用创建bean的方法都不会从IOC容器里面找,而是直接跑一遍代码,从而导致创建的三个bean对象不一致。

三、工厂模式FactoryBean

📕认识它

FactoryBean是我们创建了一个类,这个类专门用来造bean的,你可能会有疑惑,它和上面直接返回这个对象的那种方法有什么区别啊?就像下面这样

📕factorybean的优势:

来自gpt的肯定:

FactoryBean 提供了更高级别的配置和创建过程的控制,允许你以更灵活的方式管理和定制 Bean 的创建。它适用于那些需要特殊处理的 Bean 创建场景,而不仅仅是简单地实例化和配置对象。

📕小总结

并不是你返回值是什么就创建什么bean,例如factorybean就是创建的它的泛型的bean

四、超级无敌@import

📕应用场景:

假如一个很老的项目已经打包上线了,加载bean的方式XML,现在要新增功能,如何添加新的将那些bean导入呢??你不能修改原码依次加上各种注解吧,这不现实。。

就像下面这样:

运行后只有spring自带的bean:

📕@importResource

你只需加上这么一个注解,指定文件路径就欧啦!!

再次运行,熟悉的bean就回来了

❓思考问题:

假如你的spring中也定义了Dog这个bean,引入的XML文件也定义了Dog,那么会发生什么

结论:

XML文件的bean会覆盖spring中的bean

📕@import({类的字节码文件,……})
  • 使用improt注解导入的bean无需在该bean上加@component注解,并且使用import导入的bean的名称为类全类名,不再是什么方法的返回值了,这点要注意
  • 如果导入的是配置类,不光配置类被加载为bean,配置类里面的bean也被加载为bean。
@Configuration(proxyBeanMethods = false)
@Import({Cat.class})
public class SpringConfig3 {
    @Bean
    public Dog dog(){
        return new Dog();
    }
}

注意:import只能使用一次,如果想导入多个bean,用,分割

📕@import导入ImprotSelector接口

可以做到bean的加载控制

public class MyImportSelect implements ImportSelector {
    @Override
    public String[] selectImports(AnnotationMetadata importingClassMetadata) {
        // import导谁,形参就是谁
        System.out.println("提示" + importingClassMetadata);
        // 优势就是可以在这里面做判断,做到bean的加载控制
        boolean flag = importingClassMetadata.hasAnnotation("import org.springframework.context.annotation.Configuration");
        if (flag){
            return new String[]{"com.itpan.domain.Cat"};
        }
        return new String[]{"com.itpan.domain.Fish"};
    }
}
📕@import导入ImportBeanDefinitionRegistrar接口

可以自定义bean的名称

public class MyRegister implements ImportBeanDefinitionRegistrar {
    @Override
    public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry, BeanNameGenerator importBeanNameGenerator) {
        // 构造一个beandefinition对象
        BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(Fish.class).getBeanDefinition();
        registry.registerBeanDefinition("Jinyu", beanDefinition);
    }
}
📕@import导入BeanDefinitionRefistryPostProcessor接口

当IOC容器初始化所有的bean后,在加载这个类中的bean,也叫bean的后处理。

public class MyPostProcessor implements BeanDefinitionRegistryPostProcessor {
    // bean的后处理
    @Override
    public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
        BeanDefinition beanDefinition = BeanDefinitionBuilder.rootBeanDefinition(BookServiceImpl2.class).getBeanDefinition();
        registry.registerBeanDefinition("bookService", beanDefinition);
    }
}

五、register注册bean

📕register

容器初始化完成之后,可以手动注册bean

    @Test
    void te7(){
        AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig3.class);
        SpringConfig3 springConfig3 = ctx.getBean("springConfig3", SpringConfig3.class);
        System.out.println(springConfig3.dog());
        
        ctx.registerBean("cat", Cat.class);
        System.out.println(ctx.getBean("cat"));
    }

六、总结

相关文章
|
3月前
|
Java Spring
SpringBoot自动配置原理
本文深入解析了SpringBoot的核心功能——自动配置,重点探讨了`org.springframework.boot.autoconfigure`及相关注解的工作机制。通过分析`@SpringBootApplication`、`@EnableAutoConfiguration`等注解,揭示了SpringBoot如何基于类路径和条件自动装配Bean
128 7
|
3月前
|
Java
SpringBoot自动装配的原理
在SpringBoot项目的启动引导类上都有一个注解@SpringBootApplication 这个注解是一个复合注解, 其中有三个注解构成 , 分别是 ● @SpringBootConfiguration : 是@Configuration的派生注解 , 标注当前类是一个SpringBoot的配置类 ● @ComponentScan : 开启组件扫描, 默认扫描的是当前启动引导了所在包以及子包 ● @EnableAutoConfiguration : 开启自动配置(自动配置核心注解) 2.在@EnableAutoConfiguration注解的内容使用@Import注解导入了一个AutoC
|
2月前
|
安全 前端开发 Java
Spring Boot 项目中触发 Circular View Path 错误的原理与解决方案
在Spring Boot开发中,**Circular View Path**错误常因视图解析与Controller路径重名引发。当视图名称(如`login`)与请求路径相同,Spring MVC无法区分,导致无限循环调用。解决方法包括:1) 明确指定视图路径,避免重名;2) 将视图文件移至子目录;3) 确保Spring Security配置与Controller路径一致。通过合理设定视图和路径,可有效避免该问题,确保系统稳定运行。
124 0
|
3月前
|
JavaScript 前端开发 Java
Idea启动SpringBoot程序报错:Veb server failed to start. Port 8082 was already in use;端口冲突的原理与解决方案
本文解决了Idea启动SpringBoot程序报错:Veb server failed to start. Port 8082 was already in use的问题,并通过介绍端口的使用原理和操作系统的端口管理机制,可以更有效地解决端口冲突问题,并确保Web服务器能够顺利启动和运行。 只有锻炼思维才能可持续地解决问题,只有思维才是真正值得学习和分享的核心要素。如果这篇博客能给您带来一点帮助,麻烦您点个赞支持一下,还可以收藏起来以备不时之需,有疑问和错误欢迎在评论区指出~
|
4月前
|
Java 数据库 开发者
详细介绍SpringBoot启动流程及配置类解析原理
通过对 Spring Boot 启动流程及配置类解析原理的深入分析,我们可以看到 Spring Boot 在启动时的灵活性和可扩展性。理解这些机制不仅有助于开发者更好地使用 Spring Boot 进行应用开发,还能够在面对问题时,迅速定位和解决问题。希望本文能为您在 Spring Boot 开发过程中提供有效的指导和帮助。
177 12
|
5月前
|
Dart 前端开发 JavaScript
springboot自动配置原理
Spring Boot 自动配置原理:通过 `@EnableAutoConfiguration` 开启自动配置,扫描 `META-INF/spring.factories` 下的配置类,省去手动编写配置文件。使用 `@ConditionalXXX` 注解判断配置类是否生效,导入对应的 starter 后自动配置生效。通过 `@EnableConfigurationProperties` 加载配置属性,默认值与配置文件中的值结合使用。总结来说,Spring Boot 通过这些机制简化了开发配置流程,提升了开发效率。
127 17
springboot自动配置原理
|
4月前
|
存储 NoSQL 前端开发
美团面试:手机扫描PC二维码登录,底层原理和完整流程是什么?
45岁老架构师尼恩详细梳理了手机扫码登录的完整流程,帮助大家在面试中脱颖而出。该过程分为三个阶段:待扫描阶段、已扫描待确认阶段和已确认阶段。更多技术圣经系列PDF及详细内容,请关注【技术自由圈】获取。
|
6月前
|
Java 数据库连接 Maven
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
自动装配是现在面试中常考的一道面试题。本文基于最新的 SpringBoot 3.3.3 版本的源码来分析自动装配的原理,并在文未说明了SpringBoot2和SpringBoot3的自动装配源码中区别,以及面试回答的拿分核心话术。
最新版 | 深入剖析SpringBoot3源码——分析自动装配原理(面试常考)
|
6月前
|
Java 数据库连接 Maven
最新版 | SpringBoot3如何自定义starter(面试常考)
在Spring Boot中,starter是一种特殊的依赖,帮助开发人员快速引入和配置特定功能模块。自定义starter可以封装一组特定功能的依赖和配置,简化项目中的功能引入。其主要优点包括模块化、简化配置、提高代码复用性和实现特定功能。常见的应用场景有短信发送模块、AOP日志切面、分布式ID生成等。通过创建autoconfigure和starter两个Maven工程,并编写自动配置类及必要的配置文件,可以实现一个自定义starter。最后在测试项目中验证其有效性。这种方式使开发者能够更便捷地管理和维护代码,提升开发效率。
最新版 | SpringBoot3如何自定义starter(面试常考)
|
5月前
|
Java Linux 调度
硬核揭秘:线程与进程的底层原理,面试高分必备!
嘿,大家好!我是小米,29岁的技术爱好者。今天来聊聊线程和进程的区别。进程是操作系统中运行的程序实例,有独立内存空间;线程是进程内的最小执行单元,共享内存。创建进程开销大但更安全,线程轻量高效但易引发数据竞争。面试时可强调:进程是资源分配单位,线程是CPU调度单位。根据不同场景选择合适的并发模型,如高并发用线程池。希望这篇文章能帮你更好地理解并回答面试中的相关问题,祝你早日拿下心仪的offer!
95 6

热门文章

最新文章