SpringBoot组件添加详细解析

2.1、组件添加

1、@Configuration(不懂看下面文字描述)

  • 基本使用
  • Full模式与Lite模式
    • 示例
    • 最佳实战
      • 配置 类组件无依赖关系用Lite模式(@Configuration(proxyBeanMethods = false))加速容器启动过程,减少判断
      • 配置类组件之间有依赖关系,方法会被调用得到之前单实例组件,用Full模式(@Configuration(proxyBeanMethods = true))

怎么给容器里添加组件

准备了俩个类:

User.java

package com.chentianyu.boot.bean;

/**
 * 用户类
 */
public class User {
    private Integer age;
    private String name;

    public User(){}
    public User(Integer age , String name){
        this.age = age;
        this.name = name;
    }

    public Integer getAge(){return age;}
    public void setAge(Integer age){this.age = age;}

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

    public String toString(){
        return "User{" +
                "name = " + name +
                ", age = " + age +
                "}";
    }
}

Pet.java

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){this.name = name;}
    
    public String toString(){
        return "Pet{" + 
                "name = " + name + '\'' + 
                "}";
    }
}

如果用以前原生的Spring得:

resources -> new -> XML Configuration File -> Spring Config -> beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="user01" class="com.chentianyu.boot.bean.User">
        <!--俩个属性赋个默认值-->
        <property name="name" value="user01"></property>
        <property name="age" value="18"></property>
    </bean>
    <!--我们给容器中注册了一个组件-->

    <bean id="cat" class="com.chentianyu.boot.bean.Pet">
        <property name="name" value="tomcat"></property>
    </bean>
</beans>

这是以前用springxml形式

springboot不是这种xml形式,springboot怎么给容器中添加组件

第一种:

springboot不写配置文件了在springboot底层可以使用@Configuration注解

package com.chentianyu.boot.config;

import org.springframework.context.annotation.Configuration;

@Configuration//告诉SpringBoot这是一个配置类(把这个类说明@Configuration类似于告诉spring这个文件是配置文件)
public class MyConfig {//这就等于创建了一个文件(beans.xml)
}

我们虽然不能写标签了,但是能写方法:

@Bean //给容器中添加组件。以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例(我们不用<Bean>标签,我们用@Bean注解)
public User user01(){
	return new User(18, "lisi");
}

不想方法名作为组件名:

@Bean("名字")

验证:在主程序中:

MainAppliction.java

//从容器中获取组件
run.getBean(组件名,组件的类型);
例如:
Pet tom01 = run.getBean("tom",Pet.class);

是不是单实例(验证):

System.out.println("组件:" + (tom01 == tom02));
组件:true

注册的组件就是单实例的

/**
 * @Configuration 标注在一个类上告诉它(Spring)这是一个配置类
 * 配置类里面我们可以使用@Bean标注在方法上给容器注册组件,默认也是单实例的
 * 需要注意的是@Configuration标注的这个类,它本身也是一个组件
 */

验证MyConfig.java是否是一个组件:

MyConfig bean = run.getBean(MyConfig.class);
System.out.println(bean);

结果:

com.chentianyu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$1edd5731@286b39c2

最大的特性:在SpringBoot2.0以后的版本里多了一个boolean proxyBeanMethods() default true;是基于Spring5.2以后多的属性:

Configuration.java
//
// Source code recreated from a .class file by IntelliJ IDEA
// (powered by FernFlower decompiler)
//

package org.springframework.context.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.springframework.core.annotation.AliasFor;
import org.springframework.stereotype.Component;

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Configuration {
    @AliasFor(
        annotation = Component.class
    )
    String value() default "";

    boolean proxyBeanMethods() default true;//默认是true
}
@Configuration(proxyBeanMethods = true)

proxyBeanMethods:代理Bean的方法

我们这个bean配置类里面申明过UserPet俩个方法,能不能调用配置类的俩个方法:

bean.user01();

我们把配置类的user01()方法多调用几遍,会不会得到不一样的对象?

配置类它的作用就是这个user01()方法是给容器中添加组件的(我们使用@Bean标注了)但是我们在外部把这个user01()方法多调了俩遍,那我们这个方法返回的这个对象是从容器中拿呢?还是就是普通的调用方法?

答案是true

也就是说我们配置类里面一旦组件注册的这个方法,你在外面调用多少遍,它都是拿到容器中的那个实例

/**
     * 外部无论对配置类中的这个组件注册方法调用多少次,获取的都是之前注册容器中的单实例对象
     * @return
     */
    @Bean //我们不用<Bean>标签,我们用@Bean注解
    public User user01(){
        return new User(18, "lisi");
    }

相等的原因就是我们proxyBeanMethods属性。

我们这个proxyBeanMethods属性说这个方法会不会被代理,默认会(true),会的情况下我们就看到我们容器(MyConfig)获取到我们组件的这个对象。MyConfig本身就不是一个普通的对象(com.chentianyu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$7ab85b6@4905c46b)它是我们这个EnhancerBySpringCGLIB相当于被SpringCGLIB增强了的代理对象。

//这里获取到的本身就是代理对象
MyConfig bean = run.getBean(MyConfig.class);

代理对象调用user01()我们springboot里面的默认逻辑就是:如果@Configuration(proxyBeanMethods = true)是true , 我们这个类获取到的就是代理对象。调用方法。我们springboot就会默认检查容器中有没有这个方法以及返回的组件如果有就拿,如果没有就调用新创

//@Configuration(proxyBeanMethods = true)代理对象调用方法。springboot总会检查这个组件是否存在于容器中
//保持组件单实例
User user01 = bean.user01();

如果@Configuration(proxyBeanMethods = false)呢?

我们从容器中拿到(getBean())的这个对象类型是什么类型?

我们发现拿到的类型不再是代理对象(com.chentianyu.boot.config.MyConfig$$EnhancerBySpringCGLIB$$7ab85b6@4905c46b)而是com.chentianyu.boot.config.MyConfig@2adddc06User user01 = bean.user01();多次调用方法就不是true相等的值。

这个就衍生出了:SpringBoot在底层@Configuration的俩个配置:一个是Full(全配置@Configuration(proxyBeanMethods = true))和Lite(轻量级配置@Configuration(proxyBeanMethods = false))。也就是说以后我们想要给容器中添加组件的时候,我们编写一个配置类,然后如果我们proxyBeanMethodstrue的情况下,我们配置类每一个给容器中每一个给组件注册的方法,在外边随便调用,它都会从容器中找组件;但是如果proxyBeanMethodsfalse的情况下,我们MyConfig配置类再也不会保存代理对象,你在外边无限次调用这个方法,每一次调用都会产生一个新的方法(new User(18,"lisi"))。

这个来解决什么场景呢?

组件依赖

举个例子:

有一个User.java

package com.chentianyu.boot.bean;

/**
 * 用户类
 */
public class User {
    private Integer age;
    private String name;
    
    private Pet pet;//假设用户要养一个宠物

    public User(){}
    public User(Integer age , String name){
        this.age = age;
        this.name = name;
    }

    public Integer getAge(){return age;}
    public void setAge(Integer age){this.age = age;}

    public String getName(){return name;}
    public void setName(String name){this.name = name;}
    
    public Pet getPet(){return pet;}
    public void setPet(Pet pet){this.pet = pet;}

    public String toString(){
        return "User{" +
                "name = " + name +
                ", age = " + age +
            	", pet = " + pet +
                "}";
    }
}

MyConfig.java中我们的用户想要用我们容器中之前注册的这个tomcatPet()方法(宠物),那如果我调成@Configuration(proxyBeanMethods = false)模式,因为:

@Bean //我们不用<Bean>标签,我们用@Bean注解
public User user01(){
	User lisi = new User(18, "lisi");
    lisi.setPet(tomcatPet());
    retrun lisi;
}

但是如果是@Configuration(proxyBeanMethods = true)模式的话,这个依赖就是成立的,我们用户(lisi)用的这个宠物(setPet())跟容器中用的宠物一模一样说明我们User组件依赖了tomcatPet组件。

测试:

User user01 = run.getBean("user01",User.class);
Pet tom = run.getBean("tom",Pet.class);

System.out.println("用户的宠物:" + (user01.getPet() == tom);

@Configuration(proxyBeanMethods = true)情况下为true:用户的宠物就是容器里的宠物。

但如果是@Configuration(proxyBeanMethods = false)现象是:我这个用户想要用的宠物,我们把人家的方法调一遍,但这个方法又不是经过代理的,相当于这个方法直接调,它又帮我们new了一个宠物,虽然宠物的名字都是tomcat , 但是不是容器中的宠物。

springboot最大的更新

我们Lite模式(轻量级配置@Configuration(proxyBeanMethods = false))就是说调成false的优点是说我们SpringBoot不会来检查我们这个方法返回的值在容器(@Bean)中有没有,跳过检查,springboot直接启动,运行起来就非常快;调成true你每一次外界对它的调用它都会检查容器中是否有。

*Full和Lite最佳实战:

如果我们对容器中单单注册组件,别人也不依赖这些组件我们一般都调成false这样我们springboot启动起来会非常快加载起来也特别快;如果我们的这个组件明显下面还要用、还要依赖我们就把proxyBeanMethods调成true保证它依赖的组件就是容器中的组件


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

结城明日奈是我老婆

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值