spring-core-5-43 | 单一类型依赖查找:如何查找已知名称或类型的Bean对象?

本文深入探讨Spring框架中依赖查找的多种方式,包括基于Bean名称、类型及组合方式的查找,并重点介绍了Spring 5.1中引入的延迟查找功能。通过示例代码展示了如何使用ObjectProvider进行高效且安全的依赖查找。
摘要由CSDN通过智能技术生成

单一类型依赖查找

单一类型依赖查找接口- BeanFactory

从这里我们可以看到一个特性, BeanFactory是单一查找的接口的核心

根据Bean 名称查找

• getBean(String)

• Spring 2.5 覆盖默认参数:getBean(String,Object…)
可以覆盖Bean的构造器的默认参数来获取Bean的实例.
建议这个方法不要使用, 十分危险
在这里插入图片描述
看它的描述, 返回的实例可能是一个shared(单例的)或者independent(原生的), 那么这里就会有一个不好的特点, 如果是shared的实例, 用这个getBean方法, 每调用一次就要覆盖它的方法, 对应大部分service实例来说, 我们往往希望其被初始化之后就是不变的, 那么这种getBean的方式就很不可取.

因此我们建议使用BeanFactory的只读的方法, 要么就删除掉旧的BeanDefinition, 后面做一个覆盖.

根据Bean 类型查找

Bean 实时查找

• Spring 3.0 getBean(Class)

• Spring 4.1 覆盖默认参数:getBean(Class,Object…)
建议覆盖默认参数这个方法不要使用, 十分危险
在这里插入图片描述

与2.5的那个方法同样道理, 通过类型进行覆盖的, 也不建议.

Spring 5.1 Bean 延迟查找

首先要确定一个问题就是你的spring版本要5.1

• getBeanProvider(Class)
具体例子见本节代码示例

• getBeanProvider(ResolvableType)
会在后面泛型的解析时进行讲解, 这个方法是用于处理多类型的时候, 因为从 Java 5 之后, 我们的类型不再是Class 唯一的类型, 有 Type, 有局部变量, Class也是Type的一个实现类了.
java.lang.reflect.Type
java.lang.reflect.TypeVariable

根据Bean 名称+ 类型查找:getBean(String,Class)

前面讲过了
DependencyLookupDemo.java
搜索22-2.3

代码示例

spring-core项目
搜索 43 | 单一类型依赖查找
ObjectProviderDemo.java

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You under the Apache License, Version 2.0
 * (the "License"); you may not use this file except in compliance with
 * the License.  You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.geekbang.thinking.in.spring.dependency.lookup;

import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;

/**
 * 43 | 单一类型依赖查找:如何查找已知名称或类型的Bean对象?
 * <p>
 * 通过 {@link ObjectProvider} 进行依赖查找
 *
 * 46 | 延迟依赖查找:非延迟初始化Bean也能实现延迟查找?
 * lookupIfAvailable
 * lookupByStreamOps
 *
 * @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
 * @since
 */
public class ObjectProviderDemo { // @Configuration 是非必须注解

    public static void main(String[] args) {
        // 创建 BeanFactory 容器
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        // 将当前类 ObjectProviderDemo 作为配置类(Configuration Class)
        // 前面讲过这里不加 @Configuration 注解也可以的
        applicationContext.register(ObjectProviderDemo.class);
        // 启动应用上下文
        applicationContext.refresh();
        // 依赖查找集合对象
        lookupByObjectProvider(applicationContext);
        // getIfAvailable 函数式扩展
        lookupIfAvailable(applicationContext);
        lookupByStreamOps(applicationContext);

        // 关闭应用上下文
        applicationContext.close();

    }

    /**
     * 46 Stream 扩展, spring 5.1提供的新的 API
     * @param applicationContext
     */
    private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) {
        // 根据类型查找
        ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
        // 之前讲到过如果存在多个相同类型的bean, 直接调 objectProvider.getObject()
        // 会返回标注了 @Primary 的那个bean
        // 这里演示一下遍历的情况
        // ObjectProvider 还是 ObjectFactory 的子类
        // ObjectProvider实际上覆盖了Iterable接口的方法, 这是个新特性
        // 注意这里还是延迟加载的
        // ObjectProvider 对象获取时,并没有获取实际 Bean 的对象,而是在 getObject() 或其他获取方法时才获取

//        Iterable<String> stringIterable = objectProvider;
//        for (String string : stringIterable) {
//            System.out.println(string);
//        }

        // 另一种写法, 利用stream和lambda
        // Stream -> Method reference
        objectProvider.stream().forEach(System.out::println);
    }

    /**
     * 46 getIfAvailable 函数式扩展
     * @param applicationContext
     */
    private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
        // 容器中没注册 User 这个bean, 那么这里就利用Supplier + lamda 的方式,
        // 如果没有bean ,就创建一个user 的 对象出来, 两种写法
        //User user = userObjectProvider.getIfAvailable(() -> User.createUser());
        User user = userObjectProvider.getIfAvailable(User::createUser);
        System.out.println("当前 User 对象:" + user);
    }

    /**
     * 43.1.1.2 Spring 5.1 Bean 延迟查找
     * getBeanProvider(Class)
     * <p>
     * 如果@Bean里面没有指定名称, 方法名就是 Bean 名称 = "helloWorld"
     *
     * 根据类型查找bean时, 如果有多个相同类型的bean,
     * 如这里两个String类型, @Primary 标注的就会优先被查找到
     *
     * @return
     */
    @Bean
    @Primary
    public String helloWorld() { // 方法名就是 Bean 名称 = "helloWorld"
        return "Hello,World";
    }

    @Bean
    public String message() {
        return "Message";
    }

    /**
     * 43.1.1.2 Spring 5.1 Bean 延迟查找
     * getBeanProvider(Class)
     *
     * @param applicationContext
     */
    private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
        ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
        System.out.println(objectProvider.getObject());
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值