当前位置:网站首页>3. 容器功能

3. 容器功能

2022-08-10 23:35:00 要学就学灰太狼


3.1 Spring 注入组件的注解

3.1.1 @Component、@Controller、 @Service、@Repository

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

3.1.2 案例演示

  1. 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\A.java
package com.xjs.springboot.bean;

import org.springframework.stereotype.Repository;

/** * @Author: 谢家升 * @Version: 1.0 */
@Repository
public class A {
    
}

  1. 在 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java 获取,完成测试,其他几个注解就不测试了
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //如何查看容器中注入的组件
        //String[] beanDefinitionNames = ioc.getBeanDefinitionNames();
        //for (String beanDefinitionName : beanDefinitionNames) {
    
        // System.out.println("beanDefinitionName= " + beanDefinitionName);
        //}

        //演示Spring中传统的注解依然可以使用 @Controller @Service @Repository
        A a = ioc.getBean(A.class);
        System.out.println("a= " + a);

    }
}


  .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.5.3)


a= [email protected]

3.2 @Configuration

3.2.1 应用实例

  • 需求说明:

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

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

  1. 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Monster.java
package com.xjs.springboot.bean;

/** * @Author: 谢家升 * @Version: 1.0 */
public class Monster {
    
    private Integer id;
    private String name;
    private Integer age;
    private String skill;

    public Monster(Integer id, String name, Integer age, String skill) {
    
        this.id = id;
        this.name = name;
        this.age = age;
        this.skill = skill;
    }

    public Monster() {
    
    }

    public Integer getId() {
    
        return id;
    }

    public void setId(Integer id) {
    
        this.id = id;
    }

    public String getName() {
    
        return name;
    }

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

    public Integer getAge() {
    
        return age;
    }

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

    public String getSkill() {
    
        return skill;
    }

    public void setSkill(String skill) {
    
        this.skill = skill;
    }

    @Override
    public String toString() {
    
        return "Monster{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", age=" + age +
                ", skill='" + skill + '\'' +
                '}';
    }
}

  1. 创建 D:\xjs_springboot\quickstart\src\main\resources\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">

    <!--配置了Monster Bean-->
    <bean id="monster01" class="com.xjs.springboot.bean.Monster">
        <property name="name" value="牛魔王"></property>
        <property name="age" value="666"></property>
        <property name="skill" value="芭蕉扇"></property>
        <property name="id" value="100"></property>
    </bean>

</beans>
  1. 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java ,获取 Bean对象
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //测试在springboot中依然可以使用spring的配置bean/注入bean/获取bean 的方式
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        Monster monster01 = ac.getBean("monster01", Monster.class);
        System.out.println("monster01= " + monster01);

    }
}

-----输出结果-----

monster01= Monster{id=100, name='牛魔王', age=666, skill='芭蕉扇'}
  • 使用 SpringBoot 的@Configuration 添加/注入组件
  1. 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig.java
package com.xjs.springboot.config;

import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/** * @Author: 谢家升 * @Version: 1.0 * <p> * 解读: * 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml] * 2. 程序员可以通过 @Bean注解 注入bean对象到容器 * 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中 */
@Configuration
public class BeanConfig {
    

    /** * 解读: * 1. @Bean : 给容器添加组件,就是一个 Monster bean对象 * 2. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字 * 3. Monster : 注入类型,注入的bean的类型是 Monster * 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息 * 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe * 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的 * 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象 * @return */
    //@Bean(name = "monster_hhe")
    @Bean
    //@Scope("prototype")
    public Monster monster02() {
    
        return new Monster(200, "红孩儿", 300, "三味真火");
    }

}

  1. 修改 MainApp.java , 从配置文件/容器获取 bean ,并完成测试
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //测试在springboot中依然可以使用spring的配置bean/注入bean/获取bean 的方式
        //=====传统方式开始=====
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        Monster monster01 = ac.getBean("monster01", Monster.class);
        System.out.println("monster01= " + monster01);
        //=====传统方式结束=====

        //获取 BeanConfig 配置类的组件/bean 实例
        Monster monster02 = ioc.getBean("monster02", Monster.class);
        System.out.println("monster02= " + monster02);

        //配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的
        Monster monster03 = ioc.getBean("monster02", Monster.class);
        System.out.println(monster02 == monster03);//true

    }
}

  1. 也可以通过 Debug 来查看 ioc 容器是否存在 monster02 Bean 实例

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

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

3.2.2 @Configuration 注意事项和细节

  1. 配置类本身也是组件, 因此也可以获取,测试 修改 MainApp.java
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //=====演示 配置类-Bean 也会被注入到容器中 开始=====
        BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
        System.out.println("beanConfig= " + beanConfig);

        //=====演示 配置类-Bean 也会被注入到容器中 结束=====

    }
}

  1. SpringBoot2 新增特性: proxyBeanMethods 指定 Full 模式Lite 模式
  • 修改配置类 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig.java
package com.xjs.springboot.config;

import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/** * @Author: 谢家升 * @Version: 1.0 * <p> * 解读: * 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml] * 2. 程序员可以通过 @Bean注解 注入bean对象到容器 * 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中 */

/** * 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. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字 * 3. Monster : 注入类型,注入的bean的类型是 Monster * 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息 * 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe * 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的 * 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象 * @return */
    //@Bean(name = "monster_hhe")
    @Bean
    //@Scope("prototype")
    public Monster monster02() {
    
        return new Monster(200, "红孩儿", 300, "三味真火");
    }

}

  • 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //=====演示 @Configuration(proxyBeanMethods = xxx) 开始=====
        //1. 获取到 BeanConfig组件
        BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
        Monster monster_01 = beanConfig.monster02();
        Monster monster_02 = beanConfig.monster02();

        System.out.println("monster_01= " + monster_01 + " " + monster_01.hashCode());
        System.out.println("monster_02= " + monster_02 + " " + monster_02.hashCode());

        //特别说明: proxyBeanMethods 是在 调用@Bean 方法 才生效,因此,需要先获取BeanConfig 组件,再调用方法,
        //而不是直接通过 SpringBoot 主程序得到的容器来获取 bean, 
        //注意观察直接通过 ioc.getBean() 获取 Bean, proxyBeanMethods 值并没有生效
        Monster monster01 = ioc.getBean("monster02", Monster.class);
        Monster monster02 = ioc.getBean("monster02", Monster.class);
        System.out.println("monster01= "  + monster01 + " " + monster01.hashCode());
        System.out.println("monster02= "  + monster02 + " " + monster02.hashCode());

        //=====演示 @Configuration(proxyBeanMethods = xxx) 结束=====

    }
}

  1. 配置类可以有多个,就和 Spring 可以有多个 ioc 配置文件是一个道理
  • 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig2.java
package com.xjs.springboot.config;

import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/** * @Author: 谢家升 * @Version: 1.0 * * 第二个配置类 */
@Configuration
public class BeanConfig2 {
    

    @Bean
    public Monster monster04() {
    
        return new Monster(400, "狐狸精", 200, "美人计");
    }

}

  • 完成测试,修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //=====演示 可以有多个配置类 开始=====
        Monster monster04 = ioc.getBean("monster04", Monster.class);
        Monster monster02 = ioc.getBean("monster02", Monster.class);
        System.out.println("monster04= " + monster04);
        System.out.println("monster02= " + monster02);
        //=====演示 可以有多个配置类 结束=====


    }
}

在这里插入图片描述

3.3 @Import

3.3.1 应用实例

  • 说明:演示在 SpringBoot,如何通过 @Import 来注入组件
  1. 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Dog.java
package com.xjs.springboot.bean;

/** * @Author: 谢家升 * @Version: 1.0 */
public class Dog {
    
}

  • 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Cat.java
package com.xjs.springboot.bean;

/** * @Author: 谢家升 * @Version: 1.0 */
public class Cat {
    
}

  • 修改 BeanConfig.java 通过@Import 注入组件

在这里插入图片描述

package com.xjs.springboot.config;

import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;

/** * @Author: 谢家升 * @Version: 1.0 * <p> * 解读: * 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml] * 2. 程序员可以通过 @Bean注解 注入bean对象到容器 * 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中 */

/** * 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 模 也称为轻量级模式,因为不检测依赖关系,运行速度快 */

/** * 解读 : * 1. @Import 注解 ,看源码可以知道,可以指定 class的数组,可以注入指定类型的Bean * public @interface Import { * Class<?>[] value(); * } * * 2. 通过 @Import 方式注入了组件,默认组件的 名字/id 就是对应类型的全类名 */
@Import({
    Dog.class, Cat.class})
@Configuration
public class BeanConfig {
    

    /** * 解读: * 1. @Bean : 给容器添加组件,就是一个 Monster bean对象 * 2. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字 * 3. Monster : 注入类型,注入的bean的类型是 Monster * 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息 * 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe * 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的 * 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象 * * @return */
    //@Bean(name = "monster_hhe")
    @Bean
    //@Scope("prototype")
    public Monster monster02() {
    
        return new Monster(200, "红孩儿", 300, "三味真火");
    }

}

  1. 修改 MainApp.java 完成测试
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
        
        //=====测试 @Import 使用 开始=====
        Dog dog = ioc.getBean(Dog.class);
        Cat cat = ioc.getBean(Cat.class);
        System.out.println("dog= " + dog);
        System.out.println("cat= " + cat);
        //=====测试 @Import 使用 结束=====

    }
}

在这里插入图片描述

在这里插入图片描述

3.4 @Conditional

3.4.1 @Conditional 介绍

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

在这里插入图片描述

@Conditional扩展注解作用(判断是否满足当前指定条件)
@ConditionOnJava系统的Java版本是否符合要求
@ConditionOnBean容器中存在指定Bean
@ConditionOnMissingBean容器中不存在指定Bean
@ConditionOnExpression满足SpEL表达式指定
@ConditionOnClass系统中有指定的类
@ConditionOnMissingClass系统中没有指定的类
@ConditionOnSingleCandidate容器中只有一个指定的bean,或者这个bean是首选bean
@ConditionOnProperty系统中指定的属性是否有指定的值
@ConditionOnResource类路径下是否存在指定资源文件
@ConditionalOnWebApplication当前是web环境
@ConditionalOnNoWebApplication当前不是web环境
@ConditionalOnJndiJNDI存在指定项

3.4.2 应用实例

  1. 要求:演示在 SpringBoot,通过 @ConditionalOnBean 来注入组件
  2. 只有在容器中有 name = monster_nmw 组件时,才注入 dog01,代码如图

在这里插入图片描述

  • 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\config\BeanConfig.java
package com.xjs.springboot.config;

import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.Scope;

/** * @Author: 谢家升 * @Version: 1.0 * <p> * 解读: * 1. @Configuration 表示这是一个配置类,等价于配置文件[beans.xml] * 2. 程序员可以通过 @Bean注解 注入bean对象到容器 * 3. 当一个类被 @Configuration 标识,该类对应的-Bean 也会注入到容器中 * <p> * 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 模式 也称为轻量级模式,因为不检测依赖关系,运行速度快 */


/** * 解读 : * 1. @Import 注解 ,看源码可以知道,可以指定 class的数组,可以住人指定类型的Bean * public @interface Import { * Class<?>[] value(); * } * * 2. 通过 @Import 方式注入了组件,默认组件的 名字/id 就是对应类型的全类名 */
@Import({
    Dog.class, Cat.class})
@Configuration
//@ConditionalOnBean(name = "monster_nmw")
public class BeanConfig {
    

    /** * 解读: * 1. @Bean : 给容器添加组件,就是一个 Monster bean对象 * 2. monster02() : 默认 你的方法名 monster02 作为Bean的 id/名字 * 3. Monster : 注入类型,注入的bean的类型是 Monster * 4. new Monster(200, "红孩儿", 300, "三味真火") : 注入到容器中具体的Bean信息 * 5. @Bean(name = "monster_hhe") : 在配置、注入Bean 指定名字/id 为 monster_hhe * 6. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的 * 7. 如果想获取多例的,再加上 @Scope("prototype") 注解即可,每次获取的都是新的对象 * * @return */
    //@Bean(name = "monster_hhe")
    @Bean
    //@Scope("prototype")
    public Monster monster02() {
    
        return new Monster(200, "红孩儿", 300, "三味真火");
    }

    @Bean(name = "monster_nmw")
    public Cat cat01() {
    
        return new Cat();
    }

    /** * 解读: * 1. @ConditionalOnBean(name = "monster_nmw") 表示 * 2. 当容器中有一个Bean,它的名字是 monster_nmw (类型不做约束) 我们就注入 dog01 这个Dog Bean * 3. 如果容器中中没有名字是 monster_nmw 的Bean,就不注入 dog01 这个Dog Bean * 4. 还有很多其他的条件约束注解... * * 5. @ConditionalOnMissingBean(name = "monster_nmw") 表示 * 6. 在容器中没有 名字/id 为 monster_nmw 才注入dog01 这个Dog Bean * * 7. @ConditionalOnBean(name = "monster_nmw") 也可以标识配置类 * 表示对该配置类的所有要注入的组件,都进行条件约束 * * @return */
    @Bean
    @ConditionalOnBean(name = "monster_nmw")
    //@ConditionalOnMissingBean(name = "monster_nmw")
    public Dog dog01() {
    
        return new Dog();
    }

}

  • 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\MainApp.java ,完成测试
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //=====演示 @Conditional 的使用 开始=====
        Dog dog01 = ioc.getBean("dog01", Dog.class);
        System.out.println("dog01= " + dog01);
        //=====演示 @Conditional 的使用 结束=====

    }
}

3.5 @ImportResource

3.5.1 @ImportResource 介绍

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

3.5.2 @ImportResource 应用实例

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

在这里插入图片描述

  1. 修改 BeanConfig.java / 或者创建新的 BeanConfig3.java(建议创建新的配置类) 来测试,使用@ImportResource 导入 beans.xml

在这里插入图片描述

package com.xjs.springboot.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.ImportResource;

/** * @Author: 谢家升 * @Version: 1.0 */
@Configuration
//导入beans.xml文件 -就可以获取到beans.xml文件中配置的bean
@ImportResource(locations = "classpath:beans.xml")
public class BeanConfig3 {
    
}

  1. 在 MainApp.java 测试
package com.xjs.springboot;

import com.xjs.springboot.bean.A;
import com.xjs.springboot.bean.Cat;
import com.xjs.springboot.bean.Dog;
import com.xjs.springboot.bean.Monster;
import com.xjs.springboot.config.BeanConfig;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/** * @Author: 谢家升 * @Version: 1.0 * @SpringBootApplication : 表示这是一个 springboot应用/项目 * @SpringBootApplication(scanBasePackages = "com.xjs") : 表示springboot要扫描的包和子包(可以传入多个包[数组]) * 如果有多个包,可以这样配置 @SpringBootApplication(scanBasePackages = {"com.xjs","xxx,yyy.zzz"}) */
@SpringBootApplication(scanBasePackages = "com.xjs")
public class MainApp {
    

    public static void main(String[] args) {
    

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);

        //=====演示 @ImportResource 的使用 开始=====
        Monster monster01 = ioc.getBean("monster01", Monster.class);
        System.out.println("monster01= " + monster01);

        System.out.println("monster01 bean 是否存在 => " + ioc.containsBean("monster01"));
        //=====演示 @ImportResource 的使用 结束=====

    }
}

在这里插入图片描述

3.6 配置绑定

3.6.1 基本介绍

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

3.6.2 应用实例

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

在这里插入图片描述

#修改server的监听端口[默认是8080]
server.port=8888
#server.servlet.context-path=/abc

#修改文件上传的大小
#比如: 默认 spring.servlet.multipart.max-file-size=1MB

#解读:这个配置是在哪里读取的!
#该属性可以指定 springboot 上传文件大小的限制-体现约定优于配置
#默认配置最终都是映射到某个类上, 比如这里配置会 映射/关联 到 MultipartProperties[该类也会作为Bean注入到容器中]
#把光标放在该属性, ctrl+b 就可以定位该配置映射到的类(属性类)
spring.servlet.multipart.max-file-size=10MB

#自定义配置属性
my.website=https://www.baidu.com

#设置Furn的属性 k-v
#前面的 furn01 是用于指定/区分不同的绑定对象,这样可以在绑定Furn bean属性值时
#通过 furn01 前缀来进行区分
#furn01.id 中的id 就是 你要绑定的 Furn bean的属性名
furn01.id=100
furn01.name=TV
furn01.price=666.88

  1. 创建 D:\xjs_springboot\quickstart\src\main\java\com\xjs\springboot\bean\Furn.java
package com.xjs.springboot.bean;

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/** * @Author: 谢家升 * @Version: 1.0 */

/** * 解读: * 1. @Component 将 Furn 注册为一个组件 * 2. @ConfigurationProperties(prefix = "furn01") 指定在 application.properties 前缀 * 这样 Furn 组件就会属性文件中的 值绑定了 */
@Component
@ConfigurationProperties(prefix = "furn01")
public class Furn {
    
    private Integer id;
    private String name;
    private Double price;


    public Integer getId() {
    
        return id;
    }

    public void setId(Integer id) {
    
        this.id = id;
    }

    public String getName() {
    
        return name;
    }

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

    public Double getPrice() {
    
        return price;
    }

    public void setPrice(Double price) {
    
        this.price = price;
    }

    @Override
    public String toString() {
    
        return "Furn{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", price=" + price +
                '}';
    }
}

  1. 修改 D:\xjs_springboot\quickstart\src\main\java\com\xjs\HiController.java
package com.xjs;

import com.xjs.springboot.bean.Furn;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;

/** * @Author: 谢家升 * @Version: 1.0 */
@Controller
public class HiController {
    

    //需求: website属性值 application.properties 的 k-v 来获取
    @Value("${my.website}")
    private String website;

    //装配到 HiController
    @Resource
    private Furn furn;

    @RequestMapping("/hi")
    @ResponseBody
    public String hi() {
    
        System.out.println("website= " + website);
        return "hi~, SpringBoot";
    }

    @RequestMapping("/furn")
    @ResponseBody
    public Furn furn() {
    
        return furn;
    }

}

  1. 启动 SpringBoot ,测试

在这里插入图片描述


  1. 配置绑定还有第 2 种方式,完成测试,效果一样
  • 注意:如果注销 @Component ,需要在 BeanConfig.java (说明:也可以是其它配类) 配置 @EnableConfigurationProperties(Furn.class),否则会提示错误

在这里插入图片描述

在这里插入图片描述

//@EnableConfigurationProperties(Furn.class)解读
//1、开启 Furn 配置绑定功能
//2、把 Furn 组件自动注册到容器中
@EnableConfigurationProperties(Furn.class)
public class BeanConfig {
    
}

在这里插入图片描述


3.6.3 注意事项和细节

  1. 如果 application.properties 有中文,需要转成 unicode 编码写入,否则出现乱码
#设置Furn的属性 k-v
#前面的 furn01 是用于指定/区分不同的绑定对象,这样可以在绑定Furn bean属性值时
#通过 furn01 前缀来进行区分
#furn01.id 中的id 就是 你要绑定的 Furn bean的属性名
furn01.id=100
furn01.name=TV~~~\u7535\u89c6\u673a
furn01.price=666.88

在这里插入图片描述


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

在这里插入图片描述

  1. 解决 @ConfigurationProperties(prefix = "furn01") 提示信息
  • 在 pom.xml 增加依赖,即可
<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-configuration-processor</artifactId>
	<optional>true</optional>
</dependency>

在这里插入图片描述

原网站

版权声明
本文为[要学就学灰太狼]所创,转载请带上原文链接,感谢
https://blog.csdn.net/weixin_60766221/article/details/125961610