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
这是以前用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注解) 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注册的组件就是单实例的
验证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配置类里面申明过User和Pet俩个方法,能不能调用配置类的俩个方法:
bean.user01();我们把配置类的user01()方法多调用几遍,会不会得到不一样的对象?
配置类它的作用就是这个user01()方法是给容器中添加组件的(我们使用@Bean标注了)但是我们在外部把这个user01()方法多调了俩遍,那我们这个方法返回的这个对象是从容器中拿呢?还是就是普通的调用方法?
答案是true
也就是说我们配置类里面一旦组件注册的这个方法,你在外面调用多少遍,它都是拿到容器中的那个实例
@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@2adddc06。User user01 = bean.user01();多次调用方法就不是true相等的值。
这个就衍生出了:SpringBoot在底层@Configuration的俩个配置:一个是Full(全配置@Configuration(proxyBeanMethods = true))和Lite(轻量级配置@Configuration(proxyBeanMethods = false))。也就是说以后我们想要给容器中添加组件的时候,我们编写一个配置类,然后如果我们proxyBeanMethods为true的情况下,我们配置类每一个给容器中每一个给组件注册的方法,在外边随便调用,它都会从容器中找组件;但是如果proxyBeanMethods为false的情况下,我们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注解 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保证它依赖的组件就是容器中的组件



