自学内容网 自学内容网

SpringBoot框架学习笔记(二):容器功能相关注解详解

Spring 注入组件的注解

@Component、@Controller、 @Service、@Repository这些在 Spring 中的传统注解仍然有效,通过这些注解可以给容器注入组件 

2 @Configuration

2.1 应用实例

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

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

(1)创建 com\springboot\bean\Monster.java

package com.springboot.bean;

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 + '\'' +
                '}';
    }
}

 (2)创建 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">

    <bean id="monster03" class="com.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>

(3)在主程序中进行测试

ApplicationContext ioc = new ClassPathXmlApplicationContext("beans.xml");
Monster monster = ioc.getBean("monster03", Monster.class);
System.out.println("monster=" + monster);

运行结果

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

(1)创建 src\main\java\com\springboot\config\BeanConfig.java 

package com.springboot.config;

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

/**
 * 1. @Configuration 标识这是一个配置类, 等价于配置文件
 * 2. 程序员可以通过@Bean 注解注入bean对象到容器
 * 3. 当一个类被 @Configuration 标识,该类-Bean 也会注入容器
 */
@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")  这样设置就会让每次getBean()返回新的对象,即多例.
     */
    //@Bean(name = "monster_nmw")
    @Bean
    //@Scope("prototype")
    public Monster monster01() {
        return new Monster(200, "牛魔王", 500, "疯魔拳");
    }
    
}

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

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

//===演示 @Configuration====
Monster monster01 = ioc.getBean("monster01", Monster.class);
Monster monster02 = ioc.getBean("monster01", Monster.class);

System.out.println("monster01--" + monster01 + " " + monster01.hashCode());
System.out.println("monster02--" + monster02 + " " + monster02.hashCode());

运行结果

成功注入容器,且两次返回的对象的哈希值相同,可知返回的是同一个对象,即单例 

2.2 @Configuration 注意事项和细节 

(1)配置类本身也是组件, 因此也可以获取

//===演示 配置类也会被注入容器 ====

BeanConfig bean = ioc.getBean(BeanConfig.class);
System.out.println("bean--" + bean);

(2)pringBoot2 新增特性: proxyBeanMethods 指定 Full 模式 和 Lite 模式

proxyBeanMethods:代理bean的方法 

  • proxyBeanMethods = true 表示Full模式,保证每个@Bean方法被调用多少次返回的组件都是单实例的, 是代理方式
  • proxyBeanMethods = false 表示Lite模式,每个@Bean方法被调用多少次返回的组件都是新创建的, 是非代理方式
  • 特别说明: proxyBeanMethods 是在 调用@Bean方法才生效,因此,需要先获取BeanConfig 组件,再调用方法。而不是直接通过 SpringBoot 主程序得到的容器来获取bean, 直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效
  • 如何选择: 组件依赖必须使用Full模式默认。如果不需要组件依赖使用 Lite模式。默认为 true
  • Lite模 也称为轻量级模式,因为不检测依赖关系,运行速度快 
// 指定Lite模式
@Configuration(proxyBeanMethods = false)
public class BeanConfig {

主程序测试

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

//1. 先得到BeanConfig组件
BeanConfig beanConfig = ioc.getBean(BeanConfig.class);
Monster monster_01 = beanConfig.monster01();
Monster monster_02 = beanConfig.monster01();
//
System.out.println("monster_01-" + monster_01 + " " + monster_01.hashCode());
System.out.println("monster_02-" + monster_02 + " " + monster_02.hashCode());


//直接通过ioc.getBean() 获取Bean, proxyBeanMethods 值并没有生效

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

运行结果

(3)配置类可以有多个, 就和 Spring 可以有多个 ioc 配置文件是一个道理。但是bean的id不能重复

@Import

通过查看@Import 源码可以了解,该注解可以通过指定一个 class类型的数组, 来注入指定类型的Bean

public @interface Import {
    Class<?>[] value();
}

通过@Import 方式注入的组件, 默认组件id就是对应类型的全类名

1.3.1 应用实例

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

(1)创建 bean\Cat.java 和 bean\Dog.java 

package com.springboot.bean;

public class Cat {
}
package com.springboot.bean;

public class Dog {
}

(2)修改 BeanConfig.java 通过@Import 注入组件

// 这样配置即可将 Dog,Cat注入组件
// 默认id为com.springboot.bean.Dog 和 com.springboot.bean.Cat
@Import({Dog.class, Cat.class})

(3)修改 MainApp.java 完成测试

//===测试@Import 使用

Dog dogBean = ioc.getBean(Dog.class);
Cat catBean = ioc.getBean(Cat.class);
System.out.println("dogBean--" + dogBean);
System.out.println("catBean--" + catBean);

 运行结果

@Conditional 

4.1 @Conditional 介绍

(1)条件装配:满足 Conditional 指定的条件,则进行组件注入

(2)@Conditional 是一个根注解,下面有很多扩展注解 

4.2 应用实例

需求说明: 演示在 SpringBoot, 如何通过 @ConditionalOnBean 来注入组件,只有在容器中有 name = monster_nmw 的组件时,才注入 dog01

代码实现:

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

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

特别说明:@ConditionalOnBean(name = "monster_nmw") 也可以放在配置类上,表示对该配置类的所有要注入的组件,都进行条件约束

主方法中加入测试

//===演示 @ConditionalOnBean 使用 start ====

Dog dog01 = ioc.getBean("dog01", Dog.class);
System.out.println("dog01--" + dog01);

运行结果

由运行结果可知,由于容器中没有 name = monster_nmw 的组件,所以 dog01 没有被注入容器

@ImportResource

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

5.1 @ImportResource 应用实例 

需求: 将 beans.xml 导入到 BeanConfig.java 配置类, 并测试是否可以获得 beans.xml 注入/配置的组件 。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">

    <bean id="monster03" class="com.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)创建新的 BeanConfig3.java 来测试, 使用@ImportResource 导入 beans.xml

package com.springboot.config;

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

@Configuration
//导入beans.xml - 就可以获取到beans.xml 中配置的bean
//可以简写为@ImportResource("classpath:beans.xml")
//可以同时导入多个配置文件,如下
//@ImportResource(locations = {"classpath:beans.xml","classpath:beans02.xml"})
@ImportResource(locations = "classpath:beans.xml")
public class BeanConfig3 {
}

(2)在 MainApp.java 测试

//演示@ImportResource 使用 start===

System.out.println("monster03 bean 是否存在-" + ioc.containsBean("monster03"));

运行结果

6 @ConfigurationProperties 配置绑定 

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

6.1 应用实例

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

(1)在 application.properties 文件中指定k-v

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

(2)创建 bean\furn.java,使用 @ConfigurationProperties 注解完成配置绑定

package com.springboot.bean;

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

@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;
    }
}

(3) controller/FurnController.java

package com.springboot.controller;

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

import javax.annotation.Resource;

@Controller
public class FurnController {
    // 装配到FurnController
    @Resource
    private Furn furn;

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

(4)启动SpringBoot主程序,在浏览器中输入网址 localhost:8080/furn,完成测试。效果如下

  

(5)特别说明,在 Furn 类上注销 @Component 并 在 BeanConfig.java( 也 可 以 是 其 它 配 置 类 ) 配 置 @EnableConfigurationProperties(Furn.class) 或 @Import( Furn.class), 效果一样

6.2 注意事项和细节

(1)如果 application.properties 有中文, 需要转成 unicode 编码写入, 否则出现乱码 

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

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

(3)解决 @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/2301_76144723/article/details/138400741

免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!