Bean 延遲依賴(lài)查找接口
// 一個(gè)對(duì)象工廠(chǎng)
public interface ObjectFactory<T> {
// 返回一個(gè)對(duì)象
T getObject() throws BeansException;
}
- org.springframework.beans.factory.ObjectFactory
此接口定義了一個(gè)簡(jiǎn)單工廠(chǎng),是一個(gè)函數(shù)式接口疟羹,可以在調(diào)用時(shí)返回一個(gè)對(duì)象實(shí)例(可能是共享的或獨(dú)立的)县好。
org.springframework.beans.factory.ObjectProvider
ObjectProvider繼承自O(shè)bjectFactory
// 1.可以看到ObjectProvider本身繼承了ObjectFactory接口围橡,所以它本身就是一個(gè)ObjectFactory
// 2.從5.1之后,這個(gè)接口還多繼承了一個(gè)Iterable接口缕贡,意味著能對(duì)它進(jìn)行迭代以及流式操作
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
// 返回用指定參數(shù)創(chuàng)建的bean, 如果容器中不存在, 拋出異常
T getObject(Object... args) throws BeansException;
// 如果指定類(lèi)型的bean注冊(cè)到容器中, 返回 bean 實(shí)例, 否則返回 null
@Nullable
T getIfAvailable() throws BeansException;
// 如果返回對(duì)象不存在翁授,則用傳入的Supplier獲取一個(gè)Bean并返回拣播,否則直接返回存在的對(duì)象
default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
T dependency = getIfAvailable();
return (dependency != null ? dependency : defaultSupplier.get());
}
// 消費(fèi)對(duì)象的一個(gè)實(shí)例(可能是共享的或獨(dú)立的),如果存在通過(guò)Consumer回調(diào)消耗目標(biāo)對(duì)象收擦。
// 如果不存在則直接返回
default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
T dependency = getIfAvailable();
if (dependency != null) {
dependencyConsumer.accept(dependency);
}
}
// 如果不可用或不唯一(沒(méi)有指定primary)則返回null贮配。否則,返回對(duì)象塞赂。
@Nullable
T getIfUnique() throws BeansException;
// 如果不存在唯一對(duì)象泪勒,則調(diào)用Supplier的回調(diào)函數(shù)
default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {
T dependency = getIfUnique();
return (dependency != null ? dependency : defaultSupplier.get());
}
// 如果存在唯一對(duì)象,則消耗掉該對(duì)象
default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
T dependency = getIfUnique();
if (dependency != null) {
dependencyConsumer.accept(dependency);
}
}
// 返回符合條件的對(duì)象的Iterator减途,沒(méi)有特殊順序保證(一般為注冊(cè)順序)
@Override
default Iterator<T> iterator() {
return stream().iterator();
}
// 返回符合條件對(duì)象的連續(xù)的Stream酣藻,沒(méi)有特殊順序保證(一般為注冊(cè)順序)
default Stream<T> stream() {
throw new UnsupportedOperationException("Multi element access not supported");
}
// 返回符合條件對(duì)象的連續(xù)的Stream。在標(biāo)注Spring應(yīng)用上下文中采用@Order注解或?qū)崿F(xiàn)Order接口的順序
default Stream<T> orderedStream() {
throw new UnsupportedOperationException("Ordered element access not supported");
}
}
- 函數(shù)式接口
- getIfAvailable(Supplier) / 單一查找
- ifAvailable(Consumer) / 單一查找
- Stream 擴(kuò)展 - stream() / 集合查找
實(shí)體類(lèi)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創(chuàng)建的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;
}
}
配置類(lèi)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("入門(mén)小站");
return r;
}
@Bean
public Rumenz rumenz(){
Rumenz r=new Rumenz();
r.setId(123);
r.setName("入門(mén)小站");
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); //注冊(cè)Rumenz
ac.refresh();
Map<String, Rumenz> 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<Rumenz> beanProvider = ac.getBeanProvider(Rumenz.class);
System.out.println(beanProvider.getObject());
}
}
報(bào)錯(cuò)
rumenz1===Rumenz{id=456, name='入門(mén)小站'} SuperRumenz{key='null'}
rumenz===Rumenz{id=123, name='入門(mén)小站'} 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
原因
發(fā)現(xiàn)兩個(gè)類(lèi)型一樣的Bean
解決方案
使用@Primary 推選一個(gè)主要的Bean
@Bean
@Primary //添加注解
public Rumenz rumenz(){
Rumenz r=new Rumenz();
r.setId(123);
r.setName("入門(mén)小站");
return r;
}
輸出
Rumenz{id=123, name='入門(mén)小站'}
ObjectProvider / Supplier 單一查找(必須加@Primary)
如果當(dāng)前獲取的Bean不存在那么就創(chuàng)建一個(gè)Bean(達(dá)到延遲加載和兜底的優(yōu)雅效果)
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); //注意:不注冊(cè)Config
ac.refresh();
lookUpAvailable(ac);
ac.close();
}
private static void lookUpByObjectProvider(AnnotationConfigApplicationContext ac){
ObjectProvider<Rumenz> beanProvider = ac.getBeanProvider(Rumenz.class);
System.out.println(beanProvider.getObject());
}
}
輸出
Rumenz{id=123, name='static創(chuàng)建的Rumenz'}
Stream 擴(kuò)展集合查找 (不用加@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<Rumenz> beanProvider = ac.getBeanProvider(Rumenz.class);
beanProvider.stream().forEach(System.out::println);
}
}
輸出
Rumenz{id=456, name='入門(mén)小站'}
Rumenz{id=123, name='入門(mén)小站'}
image.png
源碼:https://github.com/mifunc/Spring-Bean-Delay-lookUp
原文: https://rumenz.com/rumenbiji/Spring-Bean-Delay-lookUp.html