• SpringBoot-容器功能


    SpringBoot-容器功能

    1.Spring 注入组件的注解

    1.@Component、@Controller、 @Service、@Repository

    说明: 这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件

    2.案例演示

    1.创建src\main\java\com\llp\bean\A.java

    @Repository
    public class A {
    }
    
    • 1
    • 2
    • 3

    2.修改MainApp.java主启动类

    @SpringBootApplication(scanBasePackages = {"com"})
    public class MainApp {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
        	//演示spring中传统的注解依然可以使用@Controller @Service @Repository
            A bean = ioc.getBean(A.class);
            //com.llp.bean.A@6c17c0f8
            System.out.println(bean);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    A类被@Repository修饰,可以看到A被注入到了Spring的ioc容器中,而默认的以类名首字母小写的方式作为bean的id

    image-20220728225711741

    image-20220728225525910

    2.@Configuration

    1.应用实例

    ● @Configuration 应用实例需求

    演示在 SpringBoot, 如何通过@Configuration 创建配置类来注入组件

    ● 回顾传统方式如何通过配置文件注入组件

    1.创建src\main\java\com\llp\bean\Monster.java

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class Monster {
        private Integer id;
        private String name;
        private Integer age;
        private String skill;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    2.创建src\main\resources\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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
       <bean id="monster03" class="com.llp.bean.Monster">
          <property name="id" value="100"/>
          <property name="name" value="孙悟空"/>
          <property name="age" value="1000"/>
          <property name="skill" value="刷光棍"/>
       bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.修改主启动类

    @SpringBootApplication(scanBasePackages = {"com"})
    public class MainApp {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
            ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
            Monster monster03 = ac.getBean("monster03", Monster.class);
            //Monster(id=100, name=孙悟空, age=1000, skill=刷光棍)
            System.out.println(monster03);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    SpringBoot是支持传统的方式去获取bean对象的

    image-20220728230729495

    ● 使用 SpringBoot 的@Configuration 添加/注入组件

    1.创建src\main\java\com\llp\config\BeanConfig.java

    @Configuration
    public class BeanConfig {
    
        /**
         * 1. @Bean : 给容器添加组件, 就是Monster bean
         * 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
         * 3. Monster : 注入类型, 注入bean的类型是Monster
         * 4. new Monster(200,"库里林",200,"铁头功") 注入到容器中具体的Bean
         * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字
         * 6. 默认是单例注入
         * 7. 通过 @Scope("prototype")  可以每次返回新的对象,就多例.
         */
        //@Bean(name = "monster_nmw")
        @Bean
        //@Scope("prototype")
        public Monster monster01(){
            return new Monster(200,"库里林",200,"铁头功");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    2.修改主启动类,进行测试

    @SpringBootApplication(scanBasePackages = {"com"})
    public class MainApp {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
            Monster monster01 = ioc.getBean("monster01", Monster.class);
            //Monster(id=200, name=库里林, age=200, skill=铁头功)
            System.out.println(monster01);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    image-20220728231440370

    debug查看ioc容器

    image-20220728231732844

    beanDefinitionMap, 只是存放了 bean 定义信息, 真正存放 Bean 实例的在 singleonObjectis 的 Map 中, 对于非单例,是每次动态反射生成的实例

    image-20220728231815481

    2.@Configuration注意事项和细节

    1. 配置类本身也是组件, 因此也可以获取, 测试 修改 MainApp.java
    2. SpringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 和 Lite 模式

    (1)修改src\main\java\com\llp\config\BeanConfig.java 设置proxyBeanMethods = true(默认为true)

    /**
     * 1. proxyBeanMethods:代理bean的方法
     * (1) Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式】
     * (2) Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式】
     * (3) 特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法
     * 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
     * (4) 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模式
     * (5) Lite模式 也称为轻量级模式,因为不检测依赖关系,运行速度快
     */
    @Configuration(proxyBeanMethods = true)
    public class BeanConfig {
    
        /**
         * 1. @Bean : 给容器添加组件, 就是Monster bean
         * 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
         * 3. Monster : 注入类型, 注入bean的类型是Monster
         * 4. new Monster(200,"库里林",200,"铁头功") 注入到容器中具体的Be
         * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字
         * 6. 默认是单例注入
         * 7. 通过 @Scope("prototype")  可以每次返回新的对象,就多例.
         */
        //@Bean(name = "monster_nmw")
        @Bean
        //@Scope("prototype")
        public Monster monster01(){
            return new Monster(200,"库里林",200,"铁头功");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    修改主程序进行测试

    @SpringBootApplication(scanBasePackages = {"com"})
    public class MainApp {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
            BeanConfig bean = ioc.getBean(BeanConfig.class);
            Monster monster01 = bean.monster01();
            Monster monster02 = bean.monster01();
            //monster01 ---  1533783975
            System.out.println("monster01 ---  " + monster01.hashCode());
            //monster02 ---  1533783975
            System.out.println("monster02 ---  " + monster02.hashCode());
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式】

    image-20220728232421518

    (2)修改src\main\java\com\llp\config\BeanConfig.java 设置proxyBeanMethods = fasle

    /**
     * 1. proxyBeanMethods:代理bean的方法
     * (1) Full(proxyBeanMethods = true)、【保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式】
     * (2) Lite(proxyBeanMethods = false)【每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式】
     * (3) 特别说明: proxyBeanMethods 是在 调用@Bean方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法
     * 而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 注意观察直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
     * (4) 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模式
     * (5) Lite模式 也称为轻量级模式,因为不检测依赖关系,运行速度快
     */
    @Configuration(proxyBeanMethods = false)
    public class BeanConfig {
    
        /**
         * 1. @Bean : 给容器添加组件, 就是Monster bean
         * 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
         * 3. Monster : 注入类型, 注入bean的类型是Monster
         * 4. new Monster(200,"库里林",200,"铁头功") 注入到容器中具体的Be
         * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字
         * 6. 默认是单例注入
         * 7. 通过 @Scope("prototype")  可以每次返回新的对象,就多例.
         */
        //@Bean(name = "monster_nmw")
        @Bean
        //@Scope("prototype")
        public Monster monster01(){
            return new Monster(300,"库里林",200,"铁头功");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28

    这里要注意一个坑,在前面我们使用lombok的@Data注解会重新hashCode方法如下图,这样会导致一个问题,只要我们对象属性的值一样那么计算出来的hashCode值就是一样的,因此要验证(lite模式)轻量级模式就需要去修改Monster.java不要使用lombok @Data注解的方式

    image-20220728235333224

    image-20220728235235547

    1. 配置类可以有多个, 就和 Spring 可以有多个 ioc 配置文件是一个道理.

    (1)创建src\main\java\com\llp\config\BeanConfig2.java

    @Configuration
    public class BeanConfig2 {
    
        @Bean
        public Monster monster02() {
            return new Monster(800,"蚂蚁精",80,"吃小昆虫");
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    (2)修改主启动类测试

    @SpringBootApplication(scanBasePackages = {"com"})
    public class MainApp {
    
        public static void main(String[] args) {
            ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
            Monster monster02 = ioc.getBean("monster02", Monster.class);
            //Monster(id=800, name=蚂蚁精, age=80, skill=吃小昆虫)
            System.out.println(monster02);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    3.@Import

    1.应用实例

    演示在 SpringBoot, 如何通过 @Import 来注入组件

    1.创建src\main\java\com\llp\bean\Cat.java和src\main\java\com\llp\bean\Dog.java

    public class Cat {
    }
    public class Dog {
    }
    
    • 1
    • 2
    • 3
    • 4

    2.创建src\main\java\com\llp\config\BeanConfig3.java,采用@Import({Dog.class, Cat.class})的方式注入bean到ioc容器中

    /**
     * 1. @Import 代码 可以看到,可以指定 class的数组, 可以注入指定类型的Bean
     * public @interface Import {
     *
     * 	 	Class[] value()}
     *
     * 2. 通过@Import 方式注入了组件, 默认组件名字/id就是对应类型的全类名
     */
    @Import({Dog.class, Cat.class})
    @Configuration
    public class BeanConfig3 {
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    3.运行主程序,查看ioc容器单例池

    image-20220729223955258

    4.@Conditional

    1.@Conditional 介绍

    1. 条件装配:满足 Conditional 指定的条件,则进行组件注入
    2. @Conditional 是一个根注解,下面有很多扩展注解

    image-20220729224434961

    3.@Conditional扩展注解应用场景

    image-20220729224738586

    2.应用实例

    1. 要求: 演示在 SpringBoot, 如何通过 @ConditionalOnBean 来注入组件
    2. 只有在容器中有 name = cat007组件时,才注入 dog01, 代码如下
    @Bean(name = "cat007")
    public Cat cat01(){
        return new Cat();
    }
    
    /**
     * 1. @ConditionalOnBean(name = "cat007") 表示
     * 2. 当容器中有一个Bean , 名字是cat007 (类型不做约束), 就注入dog01这个Dog bean
     * 3. 如果没有 名字是cat007 的Bean 就不注入dog01这个Dog bean
     * 4. @ConditionalOnMissingBean(name = "cat007") 表示在容器中,
     * 没有 名字/id 为 cat007 才注入dog01这个Bean
     * 5. @ConditionalOnBean(name = "cat007") 也可以放在配置类
     * 表示对该配置类的所有要注入的组件,都进行条件约束.
     */
    @Bean
    @ConditionalOnBean(name = "cat007")
    public Dog dog01(){
        return new Dog();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    image-20220729231628468

    image-20220729231751011

    5.@ImportResource

    1.作用

    原生配置文件引入, 也就是可以直接导入 Spring 传统的 beans.xml ,可以认为是 SpringBoot 对 Spring 容器文件的兼容.

    不使用@ImportResource引入,从ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args); ioc中是获取不到bean的

    image-20220729232414148

    image-20220729232353816

    2.@ImportResource 应用实例

    1. 需求: 将 beans.xml 导入到 BeanConfig.java 配置类, 并测试是否可以获得 beans.xml 注入/配置的组件

    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 http://www.springframework.org/schema/beans/spring-beans.xsd">
    
       <bean id="monster03" class="com.llp.bean.Monster">
          <property name="id" value="100"/>
          <property name="name" value="孙悟空"/>
          <property name="age" value="1000"/>
          <property name="skill" value="刷光棍"/>
       bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    beans02.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 http://www.springframework.org/schema/beans/spring-beans.xsd">
        
        <bean id="monster04" class="com.llp.bean.Monster">
            <property name="name" value="狐狸精">property>
            <property name="age" value="9000">property>
            <property name="skill" value="美人计">property>
            <property name="id" value="2000">property>
        bean>
    beans>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    1. 创建新的 BeanConfig4.java来测试, 使用@ImportResource 导入 beans.xml、beans02.xml
    /**
     * @Retention(RetentionPolicy.RUNTIME)
     * @Target({ElementType.TYPE})
     * @Documented
     * public @interface ImportResource {
     *     @AliasFor("locations")
     *     String[] value() default {};
     *
     *     @AliasFor("value")
     *     String[] locations() default {};
     *
     *     Class reader() default BeanDefinitionReader.class;
     * }
     */
    @Configuration
    @ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})
    public class BeanConfig4 {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19

    3.运行主启动类,进行测试

    image-20220729232938593

    6.配置绑定

    1.作用

    一句话:使用 Java 读取到 SpringBoot 核心配置文件 application.properties 的内容, 并且把它封装到 JavaBean 中

    2.应用实例

    1. 需求: 将 application.properties 指定的 k-v 和 JavaBean 绑定

    在application.properties文件中加入

    furn01.id=100
    furn01.name=悟空
    furn01.price=0.02
    
    • 1
    • 2
    • 3

    创建src\main\java\com\llp\bean\Furn.java

    这里javaBean需要提供get和set方法,在容器启动时会利用反射调用set方法进行赋值,在获取bean进行序列化时会调用get方法

    @Data
    @Component
    @ConfigurationProperties(prefix = "furn01")
    public class Furn {
        private Integer id;
        private String name;
        private Double price;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    修改HelloController.java

    @RestController
    public class HelloController {
    
        @Autowired
        private Furn furn;
    
        @RequestMapping("/hello")
        public String hello(){
            return "hello SpringBoot";
        }
    
        @RequestMapping("/furn")
        public Furn furn(){
            System.out.println(furn);
            return furn;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    启动容器访问测试

    image-20220730083748167

    3.注意事项和细节

    1. 如果 application.properties 有中文, 需要转成 unicode 编码写入, 否则出现乱码;也可以设置idea工具的编码格式

    1. 使用 @ConfigurationProperties(prefix = “furn01”) 会提示如下信息, 但是不会影响使用

    image-20220730084406208

    1. 解决 @ConfigurationProperties(prefix = “furn01”) 提示信息, 在 pom.xml 增加依赖, 即可

    ​ 4.配置绑定还可以在配置类中添加 @EnableConfigurationProperties({Furn.class})配置如下:

    @Data
    //@Component
    @ConfigurationProperties(prefix = "furn01")
    public class Furn {
        private Integer id;
        private String name;
        private Double price;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    @Configuration
    @EnableConfigurationProperties({Furn.class})
    public class BeanConfig5 {
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    重启测试,发现也是可以的

    image-20220730084807645

  • 相关阅读:
    CAT监控以及依赖MySQL,tomcat和JDK安装
    Vue3如何优雅的加载大量图片?
    【23种设计模式】工厂方法模式(Factory Method Pattern) .Net Core实现
    见缝插针游戏针不会更着上面旋转的小球运动
    SpringBoot集成JWT(极简版):
    Docker命令 常用中间件运维部署,方便构建自己服务
    第十八章:Swing自述
    机器学习之桑基图(用于用户行为分析)
    力扣876:链表的中间结点
    Comparator和Comparable
  • 原文地址:https://blog.csdn.net/qq_44981526/article/details/126067481