Spring Boot IoC

郭攸之
• 阅读 2796

IoC(Inversion of Control),IoC是一种通过描述来生成或获取对象的技术。
每一个需要管理的对象称为Spring Bean,而Spring管理这些Bean的容器称为Spring IoC容器
Spring Boot是基于注解的开发,在Spring Boot中通过注解来装配Bean到Spring IoC容器。

注释说明

  • @Configuration:代表这是一个Java的配置文件,Spring的容器会根据它来生成IoC容器去装配Bean
  • @Bean:代表将方法返回的POJO装配到IoC容器中,属性name定义这个Bean的名称,如果没有配置则将方法名称作为Bean的名称保存到IoC容器
  • @Value: 指定具体的值,使得Spring IoC给对应的属性注入对应的值
  • @Component:标明该类会被Spring IoC容器扫描装配,指定的名称是该Bean 的名称,如果不指定该类第一个字母小写作为该Bean的名称
  • @ComponentScan:如果不指定包名,则只会扫描@Configuration所在的包下的Bean。如果指定报名,则扫描指定包名下的所有Bean。(具体请看接下来实例中AppConfig的注释)
  • @Autowired:自动注入。根据属性的类型找到对应的Bean进行注入。如果对应类型的Bean不是唯一的会根据属性名称和Bean的名称进行匹配。设置@Autowired的属性required为false时如果找不到匹配的Bean,允许设置为null而不抛出异常

实例1

目录结构如下
Spring Boot IoC

在com.springboot.test.bean包下有两个类,BookInfo和User
在com.springboot.test.config包下是AppConfig

AppConfig.java

@Configuration
@ComponentScan("com.springboot.test.bean")
public class AppConfig {
    @Bean(name="defaultBook")
    public BookInfo initDefBook() {
        BookInfo bk = new BookInfo();
        
        bk.setID("bk323411");
        bk.setName("Crazy Spring Boot");
        bk.setAuthor("Crazy Max");
        
        return bk;
    }
}

@Configuration注释标明这是一个配置文件,Spring根据它来扫描装配Bean
@ComponentScan注释指定了扫描"com.springboot.test.bean"包下的Bean
@Bean注释标明将initDefBook方法返回的BookInfo装配到Ioc容器,Bean的名称为defaultBook

BookInfo.java

package com.springboot.test.bean;

public class BookInfo {

    private String id;
    private String name;
    private String author;
    
    
    public void setID(String id) {
        this.id = id;
    }
    
    public String getID() {
        return id;
    }
    
    public void setName(String bkName) {
        this.name = bkName;
    }
    
    public String getName() {
        return name;
    }
    
    public void setAuthor(String bkAuthor) {
        this.author = bkAuthor;
    }
    
    public String getAuthor() {
        return author;
    }
}

BookInfo就是一个POJO(Plain Ordinary Java Object)

User.java

package com.springboot.test.bean;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component("user")
public class User {
    
    @Value("1")
    private Long id;
    
    @Value("user_name_1")
    private String name;
    
    @Value("note_1")
    private String note;
    
    public Long getId() {
        return id;
    }
}

User中使用了@Component("user")注释,标明这是一个Bean名称是user。在Spring IoC容器进行扫描装配时会装配该Bean。
@Value在Spring IoC容器装配Bean时对属性设定值

BookInfo和User都作为Bean被扫描装配。两个的方式是有区别的,BookInfo通过在方法initBookInfo前加注释@Bean对BookInfo Bean进行装配
User通过在类定义前加@Bean来说明自己是一个Bean

main方法内容

@SpringBootApplication
public class SpringIoCTestApplication {

    public static void main(String[] args) {

        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = ctx.getBean(User.class);
        System.out.println(user.getId()+"");
        
        System.out.println("-----------DefaultBook------------------");
        BookInfo book = ctx.getBean(BookInfo.class);
        System.out.println(book.getID());
        System.out.println(book.getName());
        System.out.println(book.getAuthor());
        
        SpringApplication.run(SpringIoCTestApplication.class, args);
    }

}

加载配置

属性文件中可以定义一些我们实际项目使用中的配置信息如url,用户名,密码等。默认的属性文件application.properties可以添加这些信息。同时也可以生成各自的properties文件加载其中信息。

现在application.properties文件中添加如下信息

redis.url=192.168.22.11
redis.username=root
redis.password=redis123

database.driverName=com.mysql.jdbc.Driver
database.url=jdbc:mysql://localhost:3306/dbtest
database.username=root
database.password=123456
取得指定的属性值

RedisConfig.java

@Component
public class RedisConfig {

    @Value("${redis.url")
    private String url = null;
    
    @Value("${redis.username}")
    private String username = null;
    
    @Value("${redis.password}")
    private String password = null;
    
    private long expiredMinutes = 0;
    
    public void setUrl(String url) {
        System.out.println("Redis.url:" + url);
        this.url = url;
    }

    public void setUsername(String username) {
        System.out.println("Redis.username:" + username);
        this.username = username;
    }
    
    public void setPassword(String password) {
        System.out.println("Redis.password:" + password);
        this.password = password;
    }
    
}

在其中通过@Value取得application.properties中的值设定到相应的属性和方法中
RedisConfig是一个Bean所以添加@Component注释
同时在之前的AppConfig中@ComponentScan需要添加RedisConfig所在的包名。RedisConfig放在包com.springboot.test.config.bean下,所以在@ComponentScan中添加“com.springboot.test.config.bean”

@ComponentScan("com.springboot.test.bean,com.springboot.test.config.bean")
取得属性名称组下的所有值

通过使用注释@ConfigurationProperties可以取得属性名称组下的所有值driverName,url,username,password都会自动匹配DatabaseConfig中对应的属性设定

DatabaseConfig.java

@Component
@ConfigurationProperties("database")
public class DatabaseConfig {
    private String driverName = null;
    private String url = null;
    private String username = null;
    private String password = null;
    
    public void setDriverName(String driverName) {
        System.out.println("database.driverName:" + driverName);
        this.driverName = driverName;
    }
    
    public void setUrl(String url) {
        System.out.println("database.url:" + url);
        this.url = url;
    }
    
    public void setUsername(String username) {
        System.out.println("database.username:" + username);
        this.username = username;
    }
    
    public void setPassword(String password) {
        System.out.println("database.password:" + password);
        this.password = password;
    }
}

注释@ConfigurationProperties("database")指定了database属性组,所以在application.properties中database下的所有配置
如果需要添加新的properties文件,加载其中设定按照如下方法来做

加载指定的属性文件配置

在工程的resources下新建一个config目录,新建一个文件mongo.properties文件
Spring Boot IoC

mongo.properties

mongo.url=192.168.112.23
mongo.username=developer
mongo.password=mongo123

MongoConfig.java

@Component
@PropertySource(name="mongo.properties", value= {"classpath:config/mongo.properties"}, ignoreResourceNotFound=false, encoding="UTF-8")
public class MongoConfig {

    @Value("${mongo.url}")
    private String url;
    
    @Value("${mongo.username}")
    private String username;
    
    @Value("${mongo.password}")
    private String password;
    
    public String showAllConfig() {
        String allConfig = "mongo.url:" + url + "," + "mongo.username:"+username+"," + "mongo.password:" + password + ",";
        return allConfig;
    }
}

在main中加入

    public static void main(String[] args) {

        ApplicationContext ctx = new AnnotationConfigApplicationContext(AppConfig.class);
        User user = ctx.getBean(User.class);
        System.out.println(user.getId()+"");

        System.out.println("-----------MongoDB configuration----------------");
        MongoConfig mgCfg = ctx.getBean(MongoConfig.class);
        System.out.println(mgCfg.getUrl());
        System.out.println(mgCfg.getUsername());
        System.out.println(mgCfg.getPassword());
        
        SpringApplication.run(SpringIoCTestApplication.class, args);
    }

测试结果
Spring Boot IoC

条件装配

实际使用过程中某些情况下如果配置未设定如果仍然对Bean进行装配和初始化会导致异常。这是我们希望能够检测要配置选项如果需要选项都存在再进行装配和初始化。
使用@Conditional可以帮助完成该功能

    @Bean(name="dataSource")
    @Conditional(DatabaseConditional.class)
    public Properties loadDataSource(
            @Value("${database.driverName}") String driver,
            @Value("${database.url") String url,
            @Value("${database.username}") String username,
            @Value("${database.password}") String password
            ) {
        
        Properties props = new Properties();
        props.setProperty("driverName", driver);
        props.setProperty("usrl", url);
        props.setProperty("username", username);
        props.setProperty("password", password);
        
        return props;
    }

@Conditional注明要DatabaseContitional来进行配置选项的判断

DatabaseConditional.java中对配置选项进行判断

public class DatabaseConditional implements Condition{

    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        // TODO Auto-generated method stub
        
        Environment env = context.getEnvironment();
        
        boolean allRequirements = env.containsProperty("database.driverName")
                && env.containsProperty("database.url")
                && env.containsProperty("database.username")
                && env.containsProperty("database.password");
        
        if(allRequirements) {
            System.out.println("Meet all database requirements");
        } else {
            System.out.println("Not all database requirements been met");
        }
        return allRequirements;
    }

}

DatabaseConditional实现matches方法

实例代码在SpringIoCTest

点赞
收藏
评论区
推荐文章
美凌格栋栋酱 美凌格栋栋酱
6个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
Easter79 Easter79
3年前
spring源码
SpringIOC容器源码解析系列,建议大家按顺序阅读,欢迎讨论(_spring源码均为4.1.6.RELEASE版本_)1.Spring源码IOC容器(一)构建简单IOC容器(https://my.oschina.net/u/2377110/blog/902073)2.Spring源码IOC容器(二)Bean的定位解析注
Wesley13 Wesley13
3年前
SSM的基本知识点
\SpringSpring框架是一个容器,它的主要作用是创建和管理对象。Spring框架实现了解耦。Spring框架通过DI实现了IoC。关于Spring框架,必须掌握和理解的:1. Spring的基本概念与特性;2. 常用的注解:通用的4个注解,自动装配的注解;3.
Easter79 Easter79
3年前
SpringIOC官方文档解读
IoC容器本章介绍了Spring的控制反转(IoC)容器。1.1。SpringIoC容器和Bean简介本章介绍了反转控制(IoC)原则的Spring框架实现。IoC也称为依赖注入(DI)。在此过程中,对象可以通过①构造函数参数(),②工厂方法的参数③或在构造或从工厂方法返回后在对象实例上设置的属性来定义其依
Stella981 Stella981
3年前
Spring Ioc之BeanFactory
   IoC(InversionofControl),即所谓的控制反转,就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器(BeanFactory)负责的。   Spring通过配置文件(或者注解、JavaConfig)描述Bean和Bean之间的依赖关系,利用反射机制实例化Bean并建立Bean之间的依赖关系。Spr
Easter79 Easter79
3年前
Spring系列(五) 容器初始化过程源码
IoC/DI的概念容器是Spring的核心之一(另一个核心是AOP).有了容器,IOC才可能实现.什么使IoC?IoC就是将类自身管理的与其由依赖关系的对象的创建/关联和管理交予容器实现,容器按照配置(比如xml文件)来组织应用对象的创建和关联.什么使DI?DI是IoC的实现方式,由容器
Stella981 Stella981
3年前
Spring Bean注册解析(一)
       Spring是通过IoC容器对Bean进行管理的,而Bean的初始化主要分为两个过程:Bean的注册和Bean实例化。Bean的注册主要是指Spring通过读取配置文件获取各个bean的声明信息,并且对这些信息进行注册的过程。Bean的实例化则指的是Spring通过Bean的注册信息对各个Bean进行实例化的过程。本文主要讲解Spring是如何
Stella981 Stella981
3年前
Spring IoC、面向切面编程、事务管理等Spring基本概念详解
一、SpringIoC1.1重要概念1)控制反转(Inversionofcontrol)控制反转是一种通过描述(在java中通过xml或者注解)并通过第三方去产生或获取特定对象的方式。控制反转IoC(InversionofControl)是说创建对象的控制权进行转移,以前创建对象的主动权和
Wesley13 Wesley13
3年前
Spring常用注解
使用注解来构造IoC容器用注解来向Spring容器注册Bean。需要在applicationContext.xml中注册<context:componentscanbasepackage”pagkage1\,pagkage2,…,pagkageN\”/。如:在basepackage指明一个包
Easter79 Easter79
3年前
Spring源码阅读——3
SpringIoC容器1、IoC容器概述控制反转、IoC容器、依赖注入控制反转:不是什么技术,而是一种设计思想。Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。IoC容器:IoC容器控制了对象的
小万哥 小万哥
1年前
掌握 Spring IoC 容器与 Bean 作用域:详解 singleton 与 prototype 的使用与配置
在您的应用程序中,由SpringIoC容器管理的形成其核心的对象被称为"bean"。一个bean是由SpringIoC容器实例化、组装和管理的对象。这些bean是通过您提供给容器的配置元数据创建的,例如,在前面章节中已经看到的XML定义。Bean定义包含了