深入挖掘Spring系列 -- 依赖的来源(下)

简介: 深入挖掘Spring系列 -- 依赖的来源(下)

非Spring容器的外部化配置


简单来说,这类配置主要是我们在工作中常用的一些@Value相关配置注入。来看一段代码案例:


package org.idea.spring.bean.source.resource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.io.InputStream;
/**
 * @Author linhao
 * @Date created in 11:28 上午 2021/5/3
 */
@Configuration
@PropertySource(value = "META-INF/default.properties",encoding = "UTF-8")
public class ResourceInjectDemo {
    @Value("${user.id}")
    private long id;
    @Value("${user.nickname}")
    private String name;
    @Value("${user.resource:classpath://default.properties}")
    private Resource resource;
    public static void main(String[] args) throws IOException {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(ResourceInjectDemo.class);
        annotationConfigApplicationContext.refresh();
        ResourceInjectDemo resourceInjectDemo = annotationConfigApplicationContext.getBean(ResourceInjectDemo.class);
        System.out.println(resourceInjectDemo.id);
        System.out.println(resourceInjectDemo.name);
        String fileName = resourceInjectDemo.resource.getFilename();
        System.out.println(fileName);
        annotationConfigApplicationContext.close();
    }
}
复制代码


配置文件:


网络异常,图片无法展示
|


上边的这段代码比较简单,主要就是针对一些外部化的资源加载进行配置。


如果需要避免注入属性为空的情况,可以在配置的时候加入冒号,代码截图如下:


网络异常,图片无法展示
|


最后小结


关于本篇文章着重介绍了Spring内部的三种依赖来源渠道,这里我们抽取几道经典问题来进行分析探讨。


依赖注入和依赖查找来源是否相同


不相同,依赖查找的来源只局限于Spring BeanDefinition和手动注入的Sington对象,但是对于Resolvable Dependency对象以及@Value这类外部化配置的对象并不支持。


当Spring容器初始化之后还能注册bean吗


可以的,这里我贴一段自己实践出来的代码供大家参考:


package org.idea.spring.bean.source;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.idea.spring.bean.beandefinitionbuilder.User;
/**
 * @Author linhao
 * @Date created in 4:44 下午 2021/5/3
 */
public class AddBeanAfterRefreshDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(AddBeanAfterRefreshDemo.class);
        annotationConfigApplicationContext.refresh();
        try {
            User user0 = (User) annotationConfigApplicationContext.getBean("user");
            System.out.println("user0 is "+user0);
        }catch (Exception b){
            b.printStackTrace();
        }
        System.out.println("启动后手动注入bean对象");
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.setScope("prototype");
        beanDefinitionBuilder
                .addPropertyValue("id",2)
                .addPropertyValue("name","idea");
        annotationConfigApplicationContext.registerBeanDefinition("user",beanDefinitionBuilder.getBeanDefinition());
        User user1 = (User) annotationConfigApplicationContext.getBean("user");
        User user2 = annotationConfigApplicationContext.getBean(User.class);
        BeanDefinition beanDefinition = annotationConfigApplicationContext.getBeanDefinition("user");
        System.out.println(beanDefinition.getScope());
        System.out.println(user1==user2);
        annotationConfigApplicationContext.close();
    }
}
复制代码


通过这段代码实践发现其实关于BeanDefinition定义的bean在容器进行初始化之后依旧可以动态注入,不过这里有个点需要注意下:


如果将案例代码稍微修改:


package org.idea.spring.bean.source;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.idea.spring.bean.beandefinitionbuilder.User;
/**
 * @Author linhao
 * @Date created in 4:44 下午 2021/5/3
 */
public class AddBeanAfterRefreshDemo {
    public static void main(String[] args) {
        AnnotationConfigApplicationContext annotationConfigApplicationContext = new AnnotationConfigApplicationContext();
        annotationConfigApplicationContext.register(AddBeanAfterRefreshDemo.class);
        annotationConfigApplicationContext.refresh();
        try {
            User user0 = (User) annotationConfigApplicationContext.getBean(User.class);
            System.out.println("user0 is "+user0);
        }catch (Exception b){
            b.printStackTrace();
        }
        System.out.println("启动后手动注入bean对象");
        BeanDefinitionBuilder beanDefinitionBuilder = BeanDefinitionBuilder.genericBeanDefinition(User.class);
        beanDefinitionBuilder.setScope("prototype");
        beanDefinitionBuilder
                .addPropertyValue("id",2)
                .addPropertyValue("name","idea");
        annotationConfigApplicationContext.registerBeanDefinition("user",beanDefinitionBuilder.getBeanDefinition());
        User user1 = (User) annotationConfigApplicationContext.getBean(User.class);
        User user2 = annotationConfigApplicationContext.getBean(User.class);
        BeanDefinition beanDefinition = annotationConfigApplicationContext.getBeanDefinition("user");
        System.out.println(beanDefinition.getScope());
        System.out.println(user1==user2);
        annotationConfigApplicationContext.close();
    }
}
复制代码


修改后的代码就会在运行的时候抛出异常。这是因为在Spring容器底层会有一个Map专门记录不同的beanClass类型对应不同的beanName集合:


代码位于:


org.springframework.beans.factory.support.DefaultListableBeanFactory
/** Map of singleton and non-singleton bean names, keyed by dependency type. */
  private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
复制代码


如果第一次尝试通过类型获取Bean失败了的话,后续的多次尝试获取也会出现失败。

在实际工作中我们可能比较少会遇到需要在容器初始化之后再去手动注入Bean对象的情况。如果有需要的时候记得重复调用Bean对象的时候借助名称查询,而不是类型查找。

目录
相关文章
|
1天前
|
人工智能 Java Spring
Spring Boot循环依赖的症状和解决方案
Spring Boot循环依赖的症状和解决方案
|
1天前
|
IDE Java Maven
Spring Boot之如何解决Maven依赖冲突Maven Helper 安装使用
Spring Boot之如何解决Maven依赖冲突Maven Helper 安装使用
23 2
|
1天前
|
缓存 Java 开发工具
【spring】如何解决循环依赖
【spring】如何解决循环依赖
13 0
|
1天前
|
存储 缓存 Java
【Spring系列笔记】依赖注入,循环依赖以及三级缓存
依赖注入: 是指通过外部配置,将依赖关系注入到对象中。依赖注入有四种主要方式:构造器注入、setter方法注入、接口注入以及注解注入。其中注解注入在开发中最为常见,因为其使用便捷以及可维护性强;构造器注入为官方推荐,可注入不可变对象以及解决循环依赖问题。本文基于依赖注入方式引出循环依赖以及三层缓存的底层原理,以及代码的实现方式。
24 0
|
1天前
|
存储 缓存 Java
【spring】06 循环依赖的分析与解决
【spring】06 循环依赖的分析与解决
9 1
|
1天前
|
存储 缓存 Java
Spring解决循环依赖
Spring解决循环依赖
|
1天前
|
缓存 算法 Java
开发必懂的Spring循环依赖图解 Spring 循环依赖
开发必懂的Spring循环依赖图解 Spring 循环依赖
22 1
|
1天前
|
缓存 算法 Java
Spring解决循环依赖
Spring解决循环依赖
21 1
|
1天前
|
容灾 Java 数据库
OceanBase数据库常见问题之spring boot应用增加了flyway的依赖但没执行如何解决
OceanBase 是一款由阿里巴巴集团研发的企业级分布式关系型数据库,它具有高可用、高性能、可水平扩展等特点。以下是OceanBase 数据库使用过程中可能遇到的一些常见问题及其解答的汇总,以帮助用户更好地理解和使用这款数据库产品。
|
1天前
|
Java 开发者 Spring
【Java】Spring循环依赖:原因与解决方法
【Java】Spring循环依赖:原因与解决方法
52 0