Spring 延迟依赖查找Bean

Bean 延迟依赖查找接口

// 一个对象工厂
public interface ObjectFactory {

    // 返回一个对象
    T getObject() throws BeansException;
}

  • org.springframework.beans.factory.ObjectFactory

此接口定义了一个简单工厂,是一个函数式接口,可以在调用时返回一个对象实例(可能是共享的或独立的)。

org.springframework.beans.factory.ObjectProvider

ObjectProvider继承自ObjectFactory

// 1.可以看到ObjectProvider本身继承了ObjectFactory接口,所以它本身就是一个ObjectFactory
// 2.从5.1之后,这个接口还多继承了一个Iterable接口,意味着能对它进行迭代以及流式操作
public interface ObjectProvider extends ObjectFactory, Iterable {

    // 返回用指定参数创建的bean, 如果容器中不存在, 抛出异常
    T getObject(Object... args) throws BeansException;

    // 如果指定类型的bean注册到容器中, 返回 bean 实例, 否则返回 null
    @Nullable
    T getIfAvailable() throws BeansException;

    // 如果返回对象不存在,则用传入的Supplier获取一个Bean并返回,否则直接返回存在的对象
    default T getIfAvailable(Supplier defaultSupplier) throws BeansException {
        T dependency = getIfAvailable();
        return (dependency != null ? dependency : defaultSupplier.get());
    }

     // 消费对象的一个实例(可能是共享的或独立的),如果存在通过Consumer回调消耗目标对象。
     // 如果不存在则直接返回
    default void ifAvailable(Consumer dependencyConsumer) throws BeansException {
        T dependency = getIfAvailable();
        if (dependency != null) {
            dependencyConsumer.accept(dependency);
        }
    }

    // 如果不可用或不唯一(没有指定primary)则返回null。否则,返回对象。
    @Nullable
    T getIfUnique() throws BeansException;

    // 如果不存在唯一对象,则调用Supplier的回调函数
    default T getIfUnique(Supplier defaultSupplier) throws BeansException {
        T dependency = getIfUnique();
        return (dependency != null ? dependency : defaultSupplier.get());
    }

    // 如果存在唯一对象,则消耗掉该对象
    default void ifUnique(Consumer dependencyConsumer) throws BeansException {
        T dependency = getIfUnique();
        if (dependency != null) {
            dependencyConsumer.accept(dependency);
        }
    }

    // 返回符合条件的对象的Iterator,没有特殊顺序保证(一般为注册顺序)
    @Override
    default Iterator iterator() {
        return stream().iterator();
    }

    // 返回符合条件对象的连续的Stream,没有特殊顺序保证(一般为注册顺序)
    default Stream stream() {
        throw new UnsupportedOperationException("Multi element access not supported");
    }

    // 返回符合条件对象的连续的Stream。在标注Spring应用上下文中采用@Order注解或实现Order接口的顺序
    default Stream orderedStream() {
        throw new UnsupportedOperationException("Ordered element access not supported");
    }
}

  • 函数式接口
    • getIfAvailable(Supplier) / 单一查找
    • ifAvailable(Consumer) / 单一查找
  • Stream 扩展 - stream() / 集合查找

实体类Rumenz.java

package com.rumenz;
public class Rumenz{

    private Integer id;
    private String name;

    @Override
    public String toString() {
        return "Rumenz{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
    
   public static Rumenz createRumenz (){
        Rumenz r=new Rumenz();
        r.setId(123);
        r.setName("static创建的Rumenz");
        return r;
    }


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

配置类Config.java

package com.rumenz;
import org.springframework.context.annotation.Bean;
public class Config {
    @Bean
    public Rumenz rumenz1(){
        Rumenz r=new Rumenz();
        r.setId(456);
        r.setName("入门小站");
        return r;
    }
    @Bean
    public Rumenz rumenz(){
        Rumenz r=new Rumenz();
        r.setId(123);
        r.setName("入门小站");
        return r;
    }
}

ObjectProvider 单一查找(必须加@Primary)

package com.rumenz;



import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Map;


public class DemoApplication {

    public static void main(String[] args) {
         AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext();
         ac.register(Config.class); //注册Rumenz
         ac.refresh();
         Map map = ac.getBeansOfType(Rumenz.class);
         map.forEach((k,v)->{
            System.out.println(k+"==="+v.toString());
         });

        lookUpByObjectProvider(ac);

        ac.close();
    }

    private static void lookUpByObjectProvider(AnnotationConfigApplicationContext ac){
        ObjectProvider beanProvider = ac.getBeanProvider(Rumenz.class);
        System.out.println(beanProvider.getObject());

    }

}

报错

rumenz1===Rumenz{id=456, name='入门小站'} SuperRumenz{key='null'}
rumenz===Rumenz{id=123, name='入门小站'} SuperRumenz{key='null'}
Exception in thread "main" org.springframework.beans.factory.NoUniqueBeanDefinitionException: No qualifying bean of type 'com.rumenz.Rumenz' available: expected single matching bean but found 2: rumenz1,rumenz

原因

发现两个类型一样的Bean

解决方案

使用@Primary 推选一个主要的Bean

@Bean
@Primary //添加注解
public Rumenz rumenz(){
    Rumenz r=new Rumenz();
    r.setId(123);
    r.setName("入门小站");
    return r;
}

输出

Rumenz{id=123, name='入门小站'}

ObjectProvider / Supplier 单一查找(必须加@Primary)

如果当前获取的Bean不存在那么就创建一个Bean(达到延迟加载和兜底的优雅效果)

package com.rumenz;



import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Map;


public class DemoApplication {

    public static void main(String[] args) {
         AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext();
         ac.register(DemoApplication.class); //注意:不注册Config
         ac.refresh();
        lookUpAvailable(ac);

        ac.close();
    }



    private static void lookUpByObjectProvider(AnnotationConfigApplicationContext ac){
        ObjectProvider beanProvider = ac.getBeanProvider(Rumenz.class);
        System.out.println(beanProvider.getObject());

    }

}

输出

Rumenz{id=123, name='static创建的Rumenz'}

Stream 扩展集合查找 (不用加@Primary)

package com.rumenz;



import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Map;


public class DemoApplication {

    public static void main(String[] args) {
         AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext();
         ac.register(Config.class);
         ac.refresh();
        lookUpByStream(ac);

        ac.close();
    }

    private static void lookUpByStream(AnnotationConfigApplicationContext ac) {
        ObjectProvider beanProvider = ac.getBeanProvider(Rumenz.class);
        beanProvider.stream().forEach(System.out::println);
    }
}

输出

Rumenz{id=456, name='入门小站'}
Rumenz{id=123, name='入门小站'}
image.png

源码:https://github.com/mifunc/Spring-Bean-Delay-lookUp

原文: https://rumenz.com/rumenbiji/Spring-Bean-Delay-lookUp.html

你可能感兴趣的:(Spring 延迟依赖查找Bean)