SpringBoot容器--注解的使用

文章目录

  • 容器功能--注解
    • Spring 注入组件的注解
      • @Component、@Controller、@Service、@Repository
      • 案例演示
    • @Configuration
      • 应用实例
        • 传统方式应用实例
        • 使用SpringBoot 的@Configuration 添加/注入组件
      • @Configuration 注意事项和细节
    • @Import
      • 应用实例
    • @Conditional
      • @Conditional 介绍
      • 应用实例
    • @ImportResource
      • @ImportResource 应用实例
    • 配置绑定
      • 应用实例
      • 注意事项和细节

容器功能–注解

Spring 注入组件的注解

@Component、@Controller、@Service、@Repository

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

案例演示

  1. 创建quickstart\src\main\java\com\nlc\springboot\bean\A.java

SpringBoot容器--注解的使用_第1张图片

其他的就不做演示了

  1. 在quickstart\src\main\java\com\nlc\springboot\MainApp.java 获取, 完成测试

SpringBoot容器--注解的使用_第2张图片

@Configuration

应用实例

传统方式应用实例

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

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

1.创建quickstart\src\main\java\com\nlc\springboot\bean\Monster.java

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. 创建quickstart\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.nlc.springboot.bean.Monster">
        <property name="name" value="牛魔王~">property>
        <property name="age" value="5000">property>
        <property name="skill" value="芭蕉扇~">property>
        <property name="id" value="1000">property>
    bean>
beans>

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

  1. 创建quickstart\src\main\java\com\nlc\springboot\config\BeanConfig.java

程序员可以通过@Bean 注解注入bean对象到容器。

当一个类被 @Configuration 标识,该类-Bean 也会注入容器。

//@Configuration 标识这是一个配置类: 等价配置文件
@Configuration
public class BeanConfig {
    /**
     * 解读
     * 1. @Bean : 给容器添加组件, 就是Monster bean
     * 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
     * 3. Monster : 注入类型, 注入bean的类型是Monster
     * 4. new Monster(200,"牛魔王",500,"疯魔拳") 注入到容器中具体的Bean信息
     * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字/id monster_nmw
     * 6. 默认是单例注入
     * 7. 通过 @Scope("prototype")  可以每次返回新的对象,就多例.
     */
    //@Bean(name = "monster_nmw")
    @Bean
    //@Scope("prototype")
    public Monster monster01() {
        return new Monster(200, "牛魔王", 500, "疯魔拳");
    }
}

2.修改MainApp.java , 从配置文件/容器获取bean , 并完成测试

 public static void main(String[] args) {

    //启动springboot应用程序/项目
    ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
	//1. ioc.getBean("monster01", Monster.class) 是从BeanConfig 配置类/容器获取bean实例
	//2. 默认是单列模式, 所以monster01 == monster02
	//获取BeanConfig 配置类的组件/bean 实例
	Monster monster01 = ioc.getBean("monster01", Monster.class);
    System.out.println(monster01);
    Monster monster02 = ioc.getBean("monster01", Monster.class);
    System.out.println(monster01 == monster02);
}
  1. 也可以通过Debug 来查看ioc 容器是否存在monster01 Bean 实例

SpringBoot容器--注解的使用_第3张图片

SpringBoot容器--注解的使用_第4张图片

SpringBoot容器--注解的使用_第5张图片

SpringBoot容器--注解的使用_第6张图片

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

SpringBoot容器--注解的使用_第7张图片

SpringBoot容器--注解的使用_第8张图片

@Configuration 注意事项和细节

  1. 配置类本身也是组件, 因此也可以获取, 测试修改MainApp.java
public static void main(String[] args) {
    ConfigurableApplicationContext ioc =  SpringApplication.run(MainApp.class, args);
    //1. ioc.getBean("monster01", Monster.class) 是从BeanConfig 配置类/容器获取bean 实例
    //2. 默认是单列模式, 所以monster01 == monster02
    //获取BeanConfig 配置类的组件/bean 实例
    Monster monster01 = ioc.getBean("monster01", Monster.class);
    System.out.println(monster01);

    Monster monster02 = ioc.getBean("monster01", Monster.class);
    System.out.println(monster01 == monster02);

    //配置类本身也是组件, 因此也可以获取
    BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
    System.out.println("beanConfig= " + beanConfig);
}
  1. SpringBoot2 新增特性: proxyBeanMethods 指定Full 模式和Lite 模式

修改quickstart\src\main\java\com\nlc\springboot\config\BeanConfig.java

/**
 *  * 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 标识这是一个配置类: 等价配置文件
@Configuration(proxyBeanMethods = false)
public class BeanConfig {
    /**
     * 解读
     * 1. @Bean : 给容器添加组件, 就是Monster bean
     * 2. monster01() : 默认 你的方法名monster01 作为Bean的名字/id
     * 3. Monster : 注入类型, 注入bean的类型是Monster
     * 4. new Monster(200,"牛魔王",500,"疯魔拳") 注入到容器中具体的Bean信息
     * 5. @Bean(name = "monster_nmw") : 在配置、注入Bean指定名字/id monster_nmw
     * 6. 默认是单例注入
     * 7. 通过 @Scope("prototype")  可以每次返回新的对象,就多例.
     */
    //@Bean(name = "monster_nmw")
    @Bean
    //@Scope("prototype")
    public Monster monster01() {
        return new Monster(200, "牛魔王", 500, "疯魔拳");
    }
}
  1. 修改quickstart\src\main\java\com\nlc\springboot\MainApp.java
@SpringBootApplication(scanBasePackages = "com.nlc")
public class MainApp {
    public static void main(String[] args) {
        //启动SpringBoot 应用程序
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
        //1. ioc.getBean("monster01", Monster.class) 是从BeanConfig 配置类/容器获取bean实例
        //2. 默认是单列模式, 所以monster01 == monster02
        //获取BeanConfig 配置类的组件/bean 实例
        Monster monster01 = ioc.getBean("monster01", Monster.class);
        System.out.println(monster01);
        Monster monster02 = ioc.getBean("monster01", Monster.class);
        System.out.println(monster01 == monster02);

        //配置类本身也是组件, 因此也可以获取,monster01 != monster02
        //上面配置了@Configuration(proxyBeanMethods = false),获取到的都是新创建的
        BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
        System.out.println("beanConfig= " + beanConfig);
        Monster monster03 = beanConfig.monster01();
        Monster monster04 = beanConfig.monster01();
        System.out.println("monster03 == monster04 : " + (monster03 == monster04));
    }
}
  1. 配置类可以有多个, 就和Spring 可以有多个ioc 配置文件是一个道理.

创建quickstart\src\main\java\com\nlc\springboot\config\BeanConfig2.java

@Configuration
public class BeanConfig2 {
    @Bean
    public Monster monster100() {
    	return new Monster(200, "牛魔王~~", 500, "芭蕉扇");
    }
}

完成测试quickstart\src\main\java\com\nlc\springboot\MainApp.java

@SpringBootApplication
public class MainApp {
    public static void main(String[] args) {
        //启动SpringBoot 应用程序
        ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
        Monster monster100 = ioc.getBean("monster100", Monster.class);
        System.out.println(monster100);
    }
}

image-20230805215006417

@Import

应用实例

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

创建quickstart\src\main\java\com\nlc\springboot\bean\Cat.java

public class Cat {
}

创建quickstart\src\main\java\com\nlc\springboot\bean\Dog.java

public class Dog {
}
  1. 修改BeanConfig.java 通过@Import 注入组件
/**
* Import 可以传入一个数组,可以一次注入多个组件
* public @interface Import {
* Class[] value();
* }
* 注意@Import 方式注入的组件, 默认组件的名字就是全类名
*/
@Import({Dog.class, Cat.class})
// @Configuration//标识这是一个配置类: 等价配置文件
@Configuration(proxyBeanMethods = false)
public class BeanConfig {
}
  1. 修改MainApp.java 完成测试
public static void main(String[] args) {

        //启动springboot应用程序/项目
        ConfigurableApplicationContext ioc =
                SpringApplication.run(MainApp.class, args);
    	Dog dogBean = ioc.getBean(Dog.class);
        Cat catBean = ioc.getBean(Cat.class);
        System.out.println("dogBean--" + dogBean);
        System.out.println("catBean--" + catBean);
}

默认类型导入是单例的,如果有多个同类型bean就会报错。

@Conditional

@Conditional 介绍

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

SpringBoot容器--注解的使用_第9张图片

应用实例

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

SpringBoot容器--注解的使用_第10张图片

@Bean
public Dog dog01() {
	return new Dog();
}
  1. 先测试下,当前是否能注入dog01

SpringBoot容器--注解的使用_第11张图片

System.out.println("容器是否注入了dog01= " + ioc.containsBean(“dog01”));

4.修改BeanConfig.java , 加入@ConditionalOnBean 条件约束,并完成测试

@Import({Dog.class, Cat.class})
// @Configuration//标识这是一个配置类: 等价配置文件
@Configuration(proxyBeanMethods = false)
//设置每次获取bean都创建新的,要符合条件才生效
public class BeanConfig {
    /**
    * 1. @Bean : 给容器中添加组件
    * 2. monster01() : 默认方法名作为组件的id
    * 3. Monster: 返回类型就是组件类型, 返回的值就是new Monster(100, "牛魔王", 500, "
    芭蕉扇")
    * 4. @Bean("monster_nmw"): 重新指定组件的id = “monster_nmw”
    * 5. 配置类里面使用@Bean 标注在方法上给容器注册组件,默认是单实例的
    */
    // @Bean("monster_nmw")
    @Bean
    public Monster monster01() {
    return new Monster(100, "牛魔王", 500, "芭蕉扇");
    }
    /**
    * @ConditionalOnBean(name = "monster_nmw"):
    * 1. 表示只有容器中注入了name = monster_nmw 的组件,下面的组件(dog01)才会被注入
    * 2. @ConditionalOnBean(name = "monster_nmw") 也可以放在类名处,
    * 则表示对该配置类中所有要注入的组件都进行条件约束
    * 3. 还有很多其它条件约束注解,用到时在讲解.
    */
    @ConditionalOnBean(name = "monster_nmw")
    @Bean
    public Dog dog01() {
    	return new Dog();
    }
}

自己测试,打开注解,看是否注入。

@ImportResource

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

@ImportResource 应用实例

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

将beans.xml放在resource资源目录下


<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.nlc.springboot.bean.Monster">
        <property name="name" value="牛魔王~">property>
        <property name="age" value="5000">property>
        <property name="skill" value="芭蕉扇~">property>
        <property name="id" value="1000">property>
    bean>
beans>
  1. 修改BeanConfig.java / 或者创建新的BeanConfig3.java(建议创建新的配置类) 来测试,使用@ImportResource 导入beans.xml
//外部导入bean
@Import({Dog.class, Cat.class})
// @Configuration//标识这是一个配置类: 等价配置文件
@Configuration(proxyBeanMethods = false)
//导入beans.xml
@ImportResource("classpath:beans.xml")
public class BeanConfig {
}
  1. 在MainApp.java 测试
public static void main(String[] args) {
    ConfigurableApplicationContext ioc = SpringApplication.run(MainApp.class, args);
    System.out.println("容器是否注入了dog01= " + ioc.containsBean("dog01"));
    System.out.println("monster03: " + ioc.containsBean("monster03"));
    System.out.println(ioc.getBean("monster03"));
}

配置绑定

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

应用实例

  1. 需求: 将application.properties 指定的k-v 和JavaBean 绑定
#默认server.port=8080
server.port=10000
#比如: 默认spring.servlet.multipart.max-file-size=1MB
#默认配置最终都是映射到某个类上,比如这里配置会映射到MultipartProperties
spring.servlet.multipart.max-file-size=10MB
#设置属性k-v
#前面的futn01用于指定/区分不同的绑定对象
furn01.id=100
furn01.name=soft_chair!!
furn01.price=45678.9
  1. 创建quickstart\src\main\java\com\nlc\springboot\bean\Furn.java
@Component
@ConfigurationProperties(prefix = "furn01")
//指定前缀。以 前缀匹配properties 文件的值,将值注入bean
/**
 * 说明:
 * 1. Equivalent to {@code @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode}
 * 2. @Data 注解等价使用了 如下注解 @Getter @Setter @RequiredArgsConstructor @ToString @EqualsAndHashCode
 */
//@Data
//说明: @NoArgsConstructor 在编译时,会生成无参构造器, 前面说过,默认情况下,会生成一个无参构造器
//说明:当我们有其它构造器生成时,如果你希望仍然有无参构造器就需要使用@NoArgsConstructor指定一下,否则就会覆盖无参构造器,从而代码错误
@NoArgsConstructor
//说明:@AllArgsConstructor 在编译时,会生成全参构造器
@AllArgsConstructor
//@ToString 在编译时,生成toString, 默认情况下,会生成一个无参构造器
@ToString
//生成所有的set/get方法
@Setter
@Getter
public class Furn {
    private Integer id;
    private String name;
    private Double price;
}
  1. 修改HelloController.java
@Controller
public class HelloController {
    @RequestMapping("/hello")
    @ResponseBody
    public String hello(){
    	return "hello, spring boot";
    }
    
    @Autowired
    Furn furn;
    
    @RequestMapping("/furn")
    @ResponseBody
    public Furn furn(){
    	return furn;
    }
}
  1. 启动SpringBoot 主程序,测试

SpringBoot容器--注解的使用_第12张图片

如果测试时发现有结果为空,说明properties 文件的属性写错了。

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

SpringBoot容器--注解的使用_第13张图片

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

}

SpringBoot容器--注解的使用_第14张图片

注意事项和细节

1.如果application.properties 有中文, 需要转成unicode 编码写入, 否则出现乱码。可以使用unicode转码工具进行转换。

#设置属性k-v
furn01.id=100
furn01.name=soft_chair\u6c99\u53d1!!
furn01.price=45678.9

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

SpringBoot容器--注解的使用_第15张图片

  1. 解决@ConfigurationProperties(prefix = “furn01”) 提示信息, 在pom.xml 增加依赖, 即可
<dependency>
    <groupId>org.springframework.bootgroupId>
    <artifactId>spring-boot-configuration-processorartifactId>
    <optional>trueoptional>
dependency>

你可能感兴趣的:(SpringBoot,spring,boot,java,后端)