zoukankan      html  css  js  c++  java
  • SpringBoot自动装配原理之Configuration以及@Bean注解的使用

    Configuration以及Bean注解的使用

    该知识点在Spring中应该学过,没有学过或者遗忘的的朋友需要预习或温习前置知识点。SpringBoot其实就是Spring的进一步简化,所以前置知识点还是有必要的学习的,这样更能明白其底层的原理。

    好了,废话不多说,开始!

    结构目录:

    image-20210716230322208

    pojo--User:

    package com.xbhog.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class User {
        private  String name;
        private int age;
    }
    
    

    config-MyConfig:

    package com.xbhog.config;
    
    import com.xbhog.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration
    public class MyConfig {
        @Bean
        public User user(){
            return new User("xbhog",18);
        }
    }
    
    

    controller-Mycontroller:

    package com.xbhog.controller;
    
    import com.xbhog.config.MyConfig;
    import com.xbhog.pojo.User;
    import org.springframework.boot.autoconfigure.web.reactive.HttpHandlerAutoConfiguration;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class Mycontroller {
        public static void main(String[] args) {
            ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
            User user = context.getBean("user", User.class);
            System.out.println(user.toString());
        }
    }
    
    

    前面这三个文件埋了一个坑,使用SpringBoot启动的话是找不到Bean的,因为我们必须把文件放到与主启动程序同一目录下,这样才能找到,可以这样:这是由于SpringBootApplication的扫描路径决定的

    image-20210716232848777

    image-20210716232942926

    但是当我们把Myapp放入主程序文件夹时:发现并没有找到相应的组件信息

    image-20210716233055827

    在不改变原来的程序的情况下,我们可以使用手动扫描的方式,设置自定义扫名路径:

    package com.xbhog.springboot1times;
    
    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;
    
    //@SpringBootApplication
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan("com.xbhog")   //设置扫描路径
    public class Myapp {
        public static void main(String[] args) {
            /*1. 返回我们IOC容器*/
            ConfigurableApplicationContext run = SpringApplication.run(Myapp.class, args);
            /*2.查看容器里面的组件*/
            String[] names = run.getBeanDefinitionNames();
            for(String name:names){
                System.out.println(name);
            }
        }
    }
    
    

    效果显示:

    image-20210716233317002

    单实例问题:

    1. 判断组件在容器中是否为单实例:
    package com.xbhog.springboot1times;
    
    import com.xbhog.pojo.Pet;
    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;
    
    //@SpringBootApplication
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan("com.xbhog")
    public class Myapp {
        public static void main(String[] args) {
            /*1. 返回我们IOC容器*/
            ConfigurableApplicationContext run = SpringApplication.run(Myapp.class, args);
            /*2.从容器中获取组件*/
            Pet tom1 = run.getBean("tom11", Pet.class);
            Pet tom2 = run.getBean("tom11", Pet.class);
            System.out.println("组件是否为单实例:"+(tom1== tom2));
        }
    }
    
    

    组件是否为单实例:true

    Myconfig调用问题:

    因为配置类也属于组件,如果我们获取配置类组件后,通过实例化对象在调用其中的bean,是调用普通方法呢,还是调用容器中的相应的组件?

    package com.xbhog.springboot1times;
    
    import com.xbhog.config.MyConfig;
    import com.xbhog.pojo.Pet;
    import com.xbhog.pojo.User;
    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;
    
    //@SpringBootApplication
    @SpringBootConfiguration
    @EnableAutoConfiguration
    @ComponentScan("com.xbhog")
    public class Myapp {
        public static void main(String[] args) {
            /*1. 返回我们IOC容器*/
            ConfigurableApplicationContext run = SpringApplication.run(Myapp.class, args);
            /*2.查看容器里面的组件*/
            String[] names = run.getBeanDefinitionNames();
            for(String name:names){
                System.out.println(name);
            }
            /*3.从容器中获取组件*/
            Pet tom1 = run.getBean("tom11", Pet.class);
            Pet tom2 = run.getBean("tom11", Pet.class);
            System.out.println("组件是否为单实例:"+(tom1== tom2));
    
            MyConfig bean = run.getBean(MyConfig.class);
            System.out.println(bean);
    
            User user1 = bean.user();
            User user2 = bean.user();
            System.out.println("测试通过Myconfig类调用的user组件:"+(user1==user2));
        }
    }
    
    

    效果如下:

    组件是否为单实例:true
    com.xbhog.config.MyConfig EnhancerBySpringCGLIB 9b1ae7c2@6c0905f6
    测试通过Myconfig类调用的user组件:true
    

    上面的效果也就是Configuration(proxyBeanMethods=true)的作用,保证每个@Bean方法被调用多少次返回的组件都是单实例的

    image-20210716234805160

    实际上就是proxyBeanMethods:代理bean的方法(true),外部无论对配置类中的这个组件注册方法调用多少次获取的都是之前注册容器中的单实例对象,也叫:FULL模式.

    proxyBeanMethods=true时:

    MyConfig返回的Bean本身就是代理对象,CGLIB,并且测试通过Myconfig类调用的user组件:true.

    com.xbhog.config.MyConfig EnhancerBySpringCGLIB 9b1ae7c2@6c0905f6

    MyConfig bean = run.getBean(MyConfig.class);
    System.out.println(bean);
    //如果@Configuration(proxyBeanMethods = true)代理对象调用方法。
    // SpringBoot总会检查这个组件是否在容器中有。
    User user1 = bean.user();
    User user2 = bean.user();
    System.out.println("测试通过Myconfig类调用的user组件:"+(user1==user2));
    

    当:proxyBeanMethods=false时(Lite模式-轻量级):

    MyCnfig返回的就不是代理模式,测试通过Myconfig类调用的user组件:false

    总结:

    proxyBeanMethods:代理bean的方法 ;

    • Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的】
    • Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的】
    • 组件依赖必须使用Full模式默认。其他默认是否Lite模式

    使用场景:

    现在向pojo.User中添加Pet对象:

    package com.xbhog.pojo;
    
    import lombok.AllArgsConstructor;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    @NoArgsConstructor
    @AllArgsConstructor
    @Data
    public class User {
        private  String name;
        private int age;
        private  Pet pet;
    }
    

    proxyBeanMethods=true模式下才是正确的;

    package com.xbhog.config;
    
    import com.xbhog.pojo.Pet;
    import com.xbhog.pojo.User;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    
    @Configuration  //告诉SpringBoot这是一个配置类  ==  application.xml
    public class MyConfig {
        @Bean  //给容器添加组件,以方法名作为组件的id,返回类型就是组件类型。返回的值,就是组件在容器中的实例
        public User user(){
            User user = new User("xbhog", 18);
            //user组件依赖与Pet组件,用户中的宠物与容器中的宠物时一样的
            user.setPet(tomcat());
            return user;
        }
        @Bean("tom11")  //设置bean别名--》id的名字
        public Pet tomcat(){
            return new Pet("tomcat");
        }
    }
    
    
    User user = run.getBean("user", User.class);
    Pet tom3 = run.getBean("tom11", Pet.class);
    System.out.println("用户的宠物"+(user.getPet() == tom3));
    

    用户的宠物true;

    proxyBeanMethods=false模式后,就不会扫描容器,直接创建对象:

    组件是否为单实例:true
    com.xbhog.config.MyConfig@330c1f61
    测试通过Myconfig类调用的user组件:false
    用户的宠物false

    如果你看到这里或者正好对你有所帮助,希望能点个关注或者推荐,感谢;
    有错误的地方,欢迎在评论指出,作者看到会进行修改。

  • 相关阅读:
    boston_housing-多分类问题
    reuters-多分类问题
    IMDB-二分类问题
    神经网络学习技巧
    第一个神经网络
    Android依赖管理与私服搭建
    Android 内存泄漏分析与解决方法
    7 结构型模式之
    6 结构型模式之
    5 结构型模式之
  • 原文地址:https://www.cnblogs.com/xbhog/p/15023139.html
Copyright © 2011-2022 走看看