大数跨境
0
0

【Spring揭秘】ObjectProvider:让依赖注入更加灵活和安全

【Spring揭秘】ObjectProvider:让依赖注入更加灵活和安全 Spring全家桶实战案例
2023-10-21
0
导读:【Spring揭秘】ObjectProvider:让依赖注入更加灵活和安全

环境:Spring5.3.23


在Spring框架中,依赖注入是一种常见的模式,它能够使代码更加模块化和可维护。然而,在实际开发中,依赖注入也可能会带来一些问题,比如依赖为空或注入方式过于繁琐等。为了解决这些问题,Spring框架提供了ObjectProvider接口,它能够让依赖注入更加灵活和安全。

1. ObjectProvider简介

      ObjectProvider是Spring框架中的一个接口,它扩展了ObjectFactory接口,专门为注入点设计。通过使用ObjectProvider,我们可以将对象的创建和注入分开,使得代码更加清晰和可维护。同时,ObjectProvider还支持多态性,可以适应不同的注入场景。

      他是ObjectFactory的一种变体,专门为注入点设计,允许编程可选性和宽松的非唯一处理。从5.1开始,该接口扩展了Iterable并提供Stream的支持。因此,它可以用于for循环,提供forEach迭代,并允许集合样式的流访问。核心方法如下:

ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {  getObject(Object... args) throws BeansException;  @Nullable  getIfAvailable() throws BeansException;  default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {    T dependency = getIfAvailable();    return (dependency != null ? dependency : defaultSupplier.get());  }  default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {    T dependency = getIfAvailable();    if (dependency != null) {      dependencyConsumer.accept(dependency);    }  }  @Nullable  getIfUnique() throws BeansException;  default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {    T dependency = getIfUnique();    return (dependency != null ? dependency : defaultSupplier.get());  }  default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {    T dependency = getIfUnique();    if (dependency != null) {      dependencyConsumer.accept(dependency);    }  }  default Iterator<T> iterator() {    return stream().iterator();  }  default Stream<T> stream() {    throw new UnsupportedOperationException("Multi element access not supported");  }  default Stream<T> orderedStream() {    throw new UnsupportedOperationException("Ordered element access not supported");  }
}


2. 使用ObjectProvider实现依赖注入

案例一:按需注入

  • MessageService接口和实现类:

public interface MessageService {  void sendMessage(String message);}@Servicepublic class SmsMessageServiceImpl implements MessageService {  @Override  public void sendMessage(String message) {    System.out.printf("发送短信:%s%n", message) ;  }}
  • 使用ObjectProvider进行按需注入:

@Componentpublic class MessageServiceConsumer {  private final ObjectProvider<MessageService> messageServiceProvider;  public MessageServiceConsumer(ObjectProvider<MessageService> messageServiceProvider) {    this.messageServiceProvider = messageServiceProvider;  }  public void sendMessageByType(String messageType, String message) {    try {      MessageService messageService = messageServiceProvider.getIfAvailable() ;      messageService.sendMessage(message);    } catch (NoSuchBeanException e) {      System.err.printf("不存在Bean, %s%n", e.getMessage()) ;    } catch (NoUniqueBeanDefinitionException e) {      System.err.printf("存在多个Bean: %s%n", e.getMessage()) ;    }  }}

案例二:获取指定类型的所有实例

接着上面示例,再定义一个MessageService实现类。

@Servicepublic class EmailMessageServiceImpl implements MessageService {  @Override  public void sendMessage(String message) {    System.out.printf("发送Email:%s%n", message);  }}

使用ObjectProvider获取所有的实例Bean

@Componentpublic class MessageServiceConsumer2 {  private final ObjectProvider<MessageService> messageServiceProvider;
public MessageServiceConsumer2(ObjectProvider<MessageService> messageServiceProvider) { this.messageServiceProvider = messageServiceProvider; }
public void sendMessage(String message) {    // 通过orderedStream()方法获取所有匹配的实例Bean this.messageServiceProvider.orderedStream().forEach(ms -> ms.sendMessage(message)) ; }}

orderStream() 方法返回的实例是有顺序的,我们可以为每个实例通过@Order注解定义优先级或者是实现Ordered接口,示例如下:

在MessageService实现类上添加Order注解

@Service@Order(2)public class EmailMessageServiceImpl implements MessageService {}@Service@Order(1)public class SmsMessageServiceImpl implements MessageService {}

@Order注解,值越小的优先级越高。所以通过orderStream方法返回的顺序将是SmsMessageServiceImplEmailMessageServiceImpl

3. ObjectProvider原理

核心处理依赖注入是在DefaultListableBeanFactory#resolveDependency方法中

public class DefaultListableBeanFactory {  public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,      @Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); }    // ObjectProvider继承自ObjectFactory    // 直接返回一个实现类DependencyObjectProvider,当在具体调用内部方法时 else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, requestingBeanName); }    // ... }}

DependencyObjectProvider

private class DependencyObjectProvider implements BeanObjectProvider<Object> {  public Object getObject() throws BeansException {    // 只有调用具体的方法时才会再去DefaultListableBeanFactory中查找具体的类    Object result = doResolveDependency(this.descriptor, this.beanName, nullnull) ;  }  public Stream<Object> orderedStream() {    // 参数决定了是否排序    return resolveStream(true);  }  private Stream<Object> resolveStream(boolean ordered) {    DependencyDescriptor descriptorToUse = new StreamDependencyDescriptor(this.descriptor, ordered);    Object result = doResolveDependency(descriptorToUse, this.beanName, null, null);    return (result instanceof Stream ? (Stream<Object>) result : Stream.of(result));  }}

完毕!!!

求关注、求转发


【声明】内容源于网络
0
0
Spring全家桶实战案例
Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
内容 832
粉丝 0
Spring全家桶实战案例 Java全栈开发,前端Vue2/3全家桶;Spring, SpringBoot 2/3, Spring Cloud各种实战案例及源码解读
总阅读38
粉丝0
内容832