文章详情

短信预约-IT技能 免费直播动态提醒

请输入下面的图形验证码

提交验证

短信预约提醒成功

Spring Boot底层原理实例分析

2023-06-29 20:33

关注

这篇“Spring Boot底层原理实例分析”文章的知识点大部分人都不太理解,所以小编给大家总结了以下内容,内容详细,步骤清晰,具有一定的借鉴价值,希望大家阅读完这篇文章能有所收获,下面我们一起来看看这篇“Spring Boot底层原理实例分析”文章吧。

1. 底层注解@Configuration

@Configuration 注解主要用于给容器添加组件(Bean),下面实践其用法:

项目基本结构:

Spring Boot底层原理实例分析

 两个Bean组件:

User.java

package com.menergy.boot.bean; public class User {    private String name;    private Integer age;    public User() {    }    public User(String name, Integer age) {        this.name = name;        this.age = age;    public String getName() {        return name;    public void setName(String name) {    public Integer getAge() {        return age;    public void setAge(Integer age) {    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", age=" + age +                '}';}

Pet.java

package com.menergy.boot.bean; public class Pet {    private String name;    public Pet() {    }    public Pet(String name) {        this.name = name;    public String getName() {        return name;    public void setName(String name) {    @Override    public String toString() {        return "Pet{" +                "name='" + name + '\'' +                '}';}

以前Spring 配置文件方式是这样给容器添加组件的:

<beans>     <bean id="user01" class="com.menergy.boot.bean.User">        <property name="name" value="dragon"></property>        <property name="age" value="18"></property>    </bean>    <bean id="pet01" class="com.menergy.boot.bean.Pet">        <property name="name" value="dragonPet"></property></beans>

现在Spring Boot 已经不写上面的xml配置了,在Spring Boot 底层可以用@Configuration 注解给容器中添加组件。如下:

注解类MyConfig.java

package com.menergy.boot.config; import com.menergy.boot.bean.Pet;import com.menergy.boot.bean.User;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration(proxyBeanMethods = true)  //告诉SpringBoot 这是一个配置类 == 以前的配置文件public class MyConfig {        @Bean   //给容器中添加组件,以方法名作为主键id,返回类型就是组件类型,返回值就是组件在容器中的实例    public User user01(){        return new User("dragon",18);    }    @Bean("tomcatPet")    public Pet pet01(){        return new Pet("dragonPet");}

主类MainApplication.java 中测试调用:

package com.menergy.boot; import com.menergy.boot.bean.Pet;import com.menergy.boot.bean.User;import com.menergy.boot.config.MyConfig;import org.springframework.boot.SpringApplication;import org.springframework.boot.SpringBootConfiguration;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.context.annotation.ComponentScan;import sun.awt.geom.AreaOp;//@SpringBootApplication@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan("com.menergy.boot")public class MainApplication {    public static void main(String[] args) {//        SpringApplication.run(MainApplication.class, args);        // 1.返回IOC容器        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);        // 2.查看容器里面的容器        String[] names = run.getBeanDefinitionNames();        for (String name : names) {            System.out.println(name);        }        // 3. 从容器中获取组件        Pet pet1 = run.getBean("tomcatPet", Pet.class);        Pet pet2 = run.getBean("tomcatPet", Pet.class);        System.out.println("组件: " + (pet1 == pet2));        // 4. com.menergy.boot.config.MyConfig$$EnhancerBySpringCGLIB$$3779496a@67a056f1        MyConfig myConfig = run.getBean(MyConfig.class);        System.out.println(myConfig);        //如果@Configuration(proxyBeanMethods = true)代理对象调用方法, Spring Boot 总会检查这个组件是否在容器中有,如果有则不会新建,保持组件单实例。        User user01 = myConfig.user01();        User user02 = myConfig.user01();        System.out.println(user01 == user02);    }}

输出的部分结果:

Spring Boot底层原理实例分析

上面的例子,重点落在@Configuration(proxyBeanMethods = true) 注解。 该注解告诉SpringBoot ,被注解的类是一个配置类, 相当于以前的配置文件xml中的“bean配置”。该注解有如下特性:

该注解的配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的。

被这个注解的配置类本身也是组件。

该注解的属性proxyBeanMethods 可以通过“true” 和 “false” 配置值,来控制使用的模式:

        (1)Full模式(proxyBeanMethods = true): 为true时,外部无论对配置类中的组件注册方法调用多少次,获取的都是之前注册容器中的单实例对象。

        (2)Lite模式(proxyBeanMethods = false): 为false时,在容器中不会保留代理对象,外部多次调用这些组件时,每次调用都会产生一个新的对象。

        这两种模式的存在主要用于解决组件依赖场景。

1和2 两点特性上面的例子中都有体现, 接下来重点实践第三点特性:

实践proxyBeanMethods:

基于上面的例子,首先修改User.java类,加上宠物Pet的依赖:

package com.menergy.boot.bean; public class User {    private String name;    private Integer age;    private Pet pet;    public User() {    }    public User(String name, Integer age) {        this.name = name;        this.age = age;    public User(String name, Integer age, Pet pet) {        this.pet = pet;    public String getName() {        return name;    public void setName(String name) {    public Integer getAge() {        return age;    public void setAge(Integer age) {    public Pet getPet() {        return pet;    public void setPet(Pet pet) {    @Override    public String toString() {        return "User{" +                "name='" + name + '\'' +                ", age=" + age +                ", pet=" + pet +                '}';}

 在配置类MyConfig.java 中加入user01对象对用pet对象,同时使用Full模式(proxyBeanMethods = true):

package com.menergy.boot.config; import com.menergy.boot.bean.Pet;import com.menergy.boot.bean.User;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration(proxyBeanMethods = true)  //告诉SpringBoot 这是一个配置类 == 以前的配置文件public class MyConfig {        @Bean   //给容器中添加组件,以方法名作为主键id,返回类型就是组件类型,返回值就是组件在容器中的实例    public User user01(){        User dragonUser = new User("dragon",18);        // User 组件依赖了Pet 组件,当proxyBeanMethods 为 true 时,这种依赖关系成立        dragonUser.setPet(pet01());        return dragonUser;    }    @Bean("tomcatPet")    public Pet pet01(){        return new Pet("dragonPet");}

主类MainApplication.java:

package com.menergy.boot; import com.menergy.boot.bean.Pet;import com.menergy.boot.bean.User;import com.menergy.boot.config.MyConfig;import org.springframework.boot.SpringApplication;import org.springframework.boot.SpringBootConfiguration;import org.springframework.boot.autoconfigure.EnableAutoConfiguration;import org.springframework.boot.autoconfigure.SpringBootApplication;import org.springframework.context.ConfigurableApplicationContext;import org.springframework.context.annotation.ComponentScan;import sun.awt.geom.AreaOp;//@SpringBootApplication@SpringBootConfiguration@EnableAutoConfiguration@ComponentScan("com.menergy.boot")public class MainApplication {    public static void main(String[] args) {//        SpringApplication.run(MainApplication.class, args);        // 1.返回IOC容器        ConfigurableApplicationContext run = SpringApplication.run(MainApplication.class, args);        // 2.查看容器里面的容器        String[] names = run.getBeanDefinitionNames();        for (String name : names) {            System.out.println(name);        }        // 3. 从容器中获取组件        Pet pet1 = run.getBean("tomcatPet", Pet.class);        Pet pet2 = run.getBean("tomcatPet", Pet.class);        System.out.println("组件: " + (pet1 == pet2));        // 4. com.menergy.boot.config.MyConfig$$EnhancerBySpringCGLIB$$3779496a@67a056f1        MyConfig myConfig = run.getBean(MyConfig.class);        System.out.println(myConfig);        //如果@Configuration(proxyBeanMethods = true)代理对象调用方法, Spring Boot 总会检查这个组件是否在容器中有,如果有则不会新建,保持组件单实例。        User user01 = myConfig.user01();        User user02 = myConfig.user01();        System.out.println(user01 == user02);        //测试 @Configuration(proxyBeanMethods = true/false)        User user011 = run.getBean("user01", User.class);        Pet tomcatPet = run.getBean("tomcatPet", Pet.class);        System.out.println("用户的宠物:" + (user011.getPet() == tomcatPet));    }}

运行结果:

Spring Boot底层原理实例分析

可以看出,Full模式(proxyBeanMethods = true)时,输出true,说明是从容器中获取的同一个组件(用户的宠物就是容器中的宠物)。

接下来,改用Lite模式(proxyBeanMethods = false):即基于上面实例,将配置类MyConfig.java 中的注解的属性proxyBeanMethods 改成false值,如下:

MyConfig.java:

package com.menergy.boot.config; import com.menergy.boot.bean.Pet;import com.menergy.boot.bean.User;import org.springframework.context.annotation.Bean;import org.springframework.context.annotation.Configuration;@Configuration(proxyBeanMethods = false)  //告诉SpringBoot 这是一个配置类 == 以前的配置文件public class MyConfig {        @Bean   //给容器中添加组件,以方法名作为主键id,返回类型就是组件类型,返回值就是组件在容器中的实例    public User user01(){        User dragonUser = new User("dragon",18);        // User 组件依赖了Pet 组件,当proxyBeanMethods 为 true 时,这种依赖关系成立        dragonUser.setPet(pet01());        return dragonUser;    }    @Bean("tomcatPet")    public Pet pet01(){        return new Pet("dragonPet");}

运行结果:

Spring Boot底层原理实例分析

 可以看出,Lite模式(proxyBeanMethods = false)时,输出false,说明是从容器中获取的不是同一个组件(用户的宠物不是容器中的宠物, 相当于new 了另一个对象)。

总结:配置类包括了全模式(Full)和轻量级模式(Lite)两种。当proxyBeanMethods 是true时,Spring Boot 每次都会检查容器中是否有相应的组件,如果proxyBeanMethods 是false, 则不检查容器中是否有没有相应的组件,而是直接new一个。这也是Spring Boot 新增的一个很重要的特性。

最佳实战:如果只是向容器中增加组件,别的地方也不会调用这个组件,我们可以将其调为false 模式,这样Spring Boot 启动起来非常快,加载起来也非常快。 如果别的地方明显要用,要依赖,我们就把其调成true,保证依赖的组件就是容器中的组件。

注: 前面的例子中,在配置类中用到@Been 注解来指定组件, 其实Spring Boot 底层还用到了其他一些以前常用的注解来指定组件,包括@Component、@Controller、@Service、@Repository。这些类似于@Been 原理,也是用于向容器中注册组件。

除此之外,底层还用到@ComponentScan 注解来说明容器的包扫描,还有@Import 和@Conditional 来向容器添加组件。很多注解是以前常用的,接下来主要说明@Import 和@Conditional 注解。

2. 底层注解@Import

首先,从@Import 注解类中可以看到该注解的定义,以及知道其属性是一个Class类型的数组,说明这个注解的作用是向容器中导入一批组件

Spring Boot底层原理实例分析

接下来,实践一下:

 首先在配置类上加入@Import 注解,并向容器中导入两个组件,一个是自己定义的类,一个是从第三方Jar 包中任意的一个类:

Spring Boot底层原理实例分析

主类加入如下测试:

Spring Boot底层原理实例分析

 运行结果:

Spring Boot底层原理实例分析

 结果说明:

“com.menergy.boot.bean.User” 是通过@Import 导入的组件。(默认的组件名称是全类名

“user01” 是之前用@Bean 方法添加进去的

“org.apache.logging.log4j.util.StringBuilders@4482469c” 也是通过@Import 导入的组件。

3. 底层注解@Conditional

@Conditional 是条件装配:当满足@Conditional指定的条件时, 才向容器中注入组件。

在全局Jar包中搜索@Conditional 类:双击Shift键,选择Classes,输入@Conditional搜索。

Spring Boot底层原理实例分析

打开Conditional 类后,“Ctrl + H” 键调出这个类的继承树:

Spring Boot底层原理实例分析

 注:如果快捷键失效,请确定如下快捷键设置:

Spring Boot底层原理实例分析

从前面的@Conditional 的继承树可以看出,@Conditional 有非常多的派生注解,每个注解都代表不同的功能,从派生注解的注解名称可以大概知道其功能用意,例如@ConditionalOnBean 注解代表当容器中存在某个Bean时才干某些事情, @ConditionalOnMissingBean 注解代表当容器中不存在某个Bean时才干某些事情。

以上就是关于“Spring Boot底层原理实例分析”这篇文章的内容,相信大家都有了一定的了解,希望小编分享的内容对大家有帮助,若想了解更多相关的知识内容,请关注编程网行业资讯频道。

阅读原文内容投诉

免责声明:

① 本站未注明“稿件来源”的信息均来自网络整理。其文字、图片和音视频稿件的所属权归原作者所有。本站收集整理出于非商业性的教育和科研之目的,并不意味着本站赞同其观点或证实其内容的真实性。仅作为临时的测试数据,供内部测试之用。本站并未授权任何人以任何方式主动获取本站任何信息。

② 本站未注明“稿件来源”的临时测试数据将在测试完成后最终做删除处理。有问题或投稿请发送至: 邮箱/279061341@qq.com QQ/279061341

软考中级精品资料免费领

  • 历年真题答案解析
  • 备考技巧名师总结
  • 高频考点精准押题
  • 2024年上半年信息系统项目管理师第二批次真题及答案解析(完整版)

    难度     813人已做
    查看
  • 【考后总结】2024年5月26日信息系统项目管理师第2批次考情分析

    难度     354人已做
    查看
  • 【考后总结】2024年5月25日信息系统项目管理师第1批次考情分析

    难度     318人已做
    查看
  • 2024年上半年软考高项第一、二批次真题考点汇总(完整版)

    难度     435人已做
    查看
  • 2024年上半年系统架构设计师考试综合知识真题

    难度     224人已做
    查看

相关文章

发现更多好内容

猜你喜欢

AI推送时光机
位置:首页-资讯-后端开发
咦!没有更多了?去看看其它编程学习网 内容吧
首页课程
资料下载
问答资讯