Springboot @Configuration 配置类的proxyBeanMethods() 属性的详解 Lite模式与Full模式

1、编写springboot的配置类(基于java类 @Configuration)

  • 首先编写用户类宠物类(pojo.User pojo.Pet)

导入lombok 依赖

<dependency>
    <groupId>org.projectlombokgroupId>
    <artifactId>lombokartifactId>
dependency>
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Pet {
    private String name;
}

  • 之前学的用beans.xml 中 注入组件

<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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

	
    <bean id="user01" class="com.tesla.pojo.User">
        <property name="name" value="Jack"/>
        <property name="age" value="20"/>
    bean>
    
    
    <bean id="cat01" class="com.tesla.pojo.Pet">
        <property name="name" value="tomcat"/>
    bean>
        
beans>

然后在主函数中使用注入的组件
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Pet cat = context.getBean("cat01", Pet.class);
System.out.println(cat.getName());



  • 另外一种方式,直接在java类中使用**@Configuration** (即创建一个配置类将组件注入容器config.MyConfiguration
/**
 * 告诉SpringBoot这是一个配置类 == 配置文件
 */
@Configuration
public class MyConfiguration {
    /**
    *给容器中添加组件。以方法名作为组件的id。返回类型就是组件类型。返回的值,就是组件在容器中的实例
     */
    @Bean
    public User myUser(){
        return new User("zhangsan",20);
    }

    @Bean
    public Pet myCat(){
        return new Pet("miaomiao");
    }
}

获取容器中组件方法同上(主程序获取)
@SpringBootApplication(scanBasePackages = "com.tesla")
public class ApplicationMain {
    public static void main(String[] args) {
        //1、返回我们IOC容器
        ConfigurableApplicationContext run = SpringApplication.run(ApplicationMain.class, args);
        //2、查看容器里面的组件
        String[] beanDefinitionNames = run.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }
        //3、从容器中获取组件,这里直接用 run 对象获取就可以了
        User myUser1 = run.getBean("myUser", User.class);
        User myUser2 = run.getBean("myUser", User.class);

        //返回值是 true
        System.out.println("两个用户是否相等:"+(myUser1==myUser2));
    }
}

配置类里面使用@Bean标注在方法上给容器注册组件,默认也是单实例的(也就是不管在主程序中创建多少个对象,它们都是从容器中拿出来的,这些对象的地址都相等)

注意: 查看容器中的组件,可以发现 配置类@Configuration),控制类@Controller) 其实都是注入到容器中的组件




2、Full模式与Lite模式



proxyBeanMethods() 属性的详解

  • @Configuration 有一个方法 proxyBeanMethods() 默认为 true (即开启代理Bean 方法
//手动开启 代理Bean 方法
@Configuration(proxyBeanMethods=true)

现在在User 中添加一个属性Pet,增加了对Pet类的依赖
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
    private String name;
    private int age;
    //现在User类 依赖 Pet类了
    private Pet pet;
}

修改 配置类中 User的方法
    @Bean
    public User myUser(){
        //先用mycat方法将组件从容器中拿出来
        Pet pet = myCat();
        return new User("zhangsan",20,pet);
    }
//如果@Configuration(proxyBeanMethods = true)代理对象调用方法。SpringBoot总会检查这个组件是否在容器中有。
        //从而保持组件单实例
        MyConfiguration bean = run.getBean(MyConfiguration.class);
        User user1 = bean.myUser();
        User user2 = bean.myUser();
        System.out.println("两个用户是否相等:"+(user1==user2));
        //返回值还是true,因为不管代理对象bean调用多少次myUser,他还是从容器中拿Pet类的对象

注意: 这里的使用的是代理对象bean调用

//从容器中拿出myUser组件
User myUser = run.getBean("myUser", User.class);
//从容器中拿出myCat组件
Pet myCat = run.getBean("myCat", Pet.class);
//比较myUser中的Pet类组件和容器中拿出myCat组件是否一样,返回值是 true
System.out.println("两个宠物是否相等:"+(myCat==myUser.getPet()));

  • 将方法 proxyBeanMethods() 改为 false (即关闭代理Bean 方法
@Configuration(proxyBeanMethods=false)

主程序中方法
//1、返回我们IOC容器
ConfigurableApplicationContext run = SpringApplication.run(ApplicationMain.class, args);
//2、查看容器里面的组件
String[] beanDefinitionNames = run.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
    System.out.println(beanDefinitionName);
}
//3、从容器中获取组件,这里直接用 run 对象获取就可以了
User myUser1 = run.getBean("myUser", User.class);
User myUser2 = run.getBean("myUser", User.class);
//返回值是:true
System.out.println("两个用户是否相等:"+(myUser1==myUser2));
//返回值是:true
System.out.println("两个宠物是否相等:"+(myUser1.getPet()==myUser2.getPet()));

//如果@Configuration(proxyBeanMethods = false),SpringBoot不会检查这个组件是否在容器中有。
MyConfiguration bean = run.getBean(MyConfiguration.class);
User user1 = bean.myUser();
User user2 = bean.myUser();
//返回值是:false
System.out.println("两个用户是否相等:"+(user1==user2));

User myUser = run.getBean("myUser", User.class);
Pet myCat = run.getBean("myCat", Pet.class);
//返回值是:false
System.out.println("两个宠物是否相等:"+(myCat==myUser.getPet()));

//将用 配置类 创建的对象 user1 和直接用 容器创建的 myUser 比较 两个结果都是 false
System.out.println("两个用户是否相等:"+(user1==myUser));
System.out.println("两个宠物是否相等:"+(myCat==user1.getPet()));

//将两个都在 IOC容器中创建的对象  myUser1 和  myUser 比较,结果为  true
System.out.println("两个用户是否相等:"+(myUser1==myUser));
System.out.println("两个宠物是否相等:"+(myUser1.getPet()==myUser.getPet()));

//前者是在IOC容器中创建的,后者是在 @Bean 注解下创建的对象,它们不相同  所以结果是false
System.out.println("两个宠物是否相等:"+(myCat==myUser1.getPet()));



总结:
  1. 第一个true:使用@Bean标注在方法上给容器注册组件是单例的,实质是从容器中拿的( 当然在 Bean 注解下面添加@Scope("prototype")变为原型模式,结果就为 false 了)
  2. 第二个true:因为都是从容器中拿到的组件,它们所依赖的对象也是一样的
  3. 第三个false:将代理Bean 方法设为false,这样每次使用Config类创建时,SpringBoot不会检查这个组件是否在容器中有,而是直接创建一个
  4. 第四个false:注册的myUser组件调用@Bean标注的方法获取到的Pet类的对象和下面IOC容器中的myCat对象不一样
  5. proxyBeanMethods配置类是用来指定@Bean注解标注的方法是否使用代理,默认是true使用代理,直接从IOC容器之中取得对象;如果设置为false,也就是不使用注解,每次调用@Bean标注的方法获取到的对象IOC容器中的都不一样,是一个新的对象


  • lite 模式:不用检查是否在容器,启动加载起来快(只注册组件,组件之中不存在依赖,就用lite模式)
  • full模式:存在组件依赖关系,会检查这个组件是否在容器中

你可能感兴趣的:(从零开始的后端,spring,boot,java,spring)