Spring 4.3版本中新加入了ObjectProvider
package org.springframework.beans.factory; import java.util.Iterator; import java.util.function.Consumer; import java.util.function.Supplier; import java.util.stream.Stream; import org.springframework.beans.BeansException; import org.springframework.lang.Nullable; public interface ObjectProviderextends ObjectFactory , Iterable { T getObject(Object... args) throws BeansException; @Nullable T getIfAvailable() throws BeansException; default T getIfAvailable(Supplier defaultSupplier) throws BeansException { T dependency = getIfAvailable(); return (dependency != null ? dependency : defaultSupplier.get()); } default void ifAvailable(Consumer dependencyConsumer) throws BeansException { T dependency = getIfAvailable(); if (dependency != null) { dependencyConsumer.accept(dependency); } } @Nullable T getIfUnique() throws BeansException; 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); } } @Override default Iterator iterator() { return stream().iterator(); } default Stream stream() { throw new UnsupportedOperationException("Multi element access not supported"); } default Stream orderedStream() { throw new UnsupportedOperationException("Ordered element access not supported"); } }
看看官方提供的注释:A variant of {@link ObjectFactory} designed specifically for injection points,allowing for programmatic optionality and lenient not-unique handling.
注释的意思是:属于ObjectFactory
接口的一种变体,专为注入点设计,允许编程可选性和宽松的非唯一处理。描述非常抽象,下面详细解释ObjectProvider 接口的作用。
2.Spring构造函数隐式注入
在Spring 4.3版本之前,如果使用构造函数的方式注入另外的一个Bean,必须显示依赖@Autowired注解,如下所示:
@Service
public class TestService {
private final TestComponent testComponent;
@Autowired
public TestService(TestComponent testComponent) {
this.testComponent = testComponent;
}
}
这是非常常见的构造器注入方式。但是如果忘记添加构造函数上的@Autowired注解,启动时容器将抛出一个寻找默认构造函数的异常,除非在Bean定义设置中明确指出autowire模式为constructor模式。如在XML配置文件的
从Spring 4.3版本开始,不再需要在上述这种单构造函数场景中指定显式注入所需的@Autowired注解。对于某些根本不带任何容器注释的类来说,这是特别优雅的。Spring容器在启动时,创建TestService这个Bean的时候,会从BeanFactory中查找TestComponent这个Bean并注入进来。
同时,@Configuration注解修饰的类不在历史上不支持构造函数注入。从Spring 4.3版本开始,也允许在单构造函数场景中省略@Autowired注解。
TestService:
@Service
public class TestService {
private final TestComponent testComponent;
public TestService(TestComponent testComponent) {
this.testComponent = testComponent;
}
}
TestConfiguration:
@Configuration
public class TestConfiguration {
private final TestComponent testComponent;
public TestConfiguration(TestComponent testComponent) {
this.testComponent = testComponent;
}
@Bean
public TestService testService() {
return new TestService(this.testComponent);
}
}
但是隐式注入也不是完美的,它存在强依赖,如果这个依赖不存在,就会发生这样的悲剧:
Parameter 0 of constructor in com.xxx.xxx.xxxx required a bean of type 'com.xxx.xxx.xxxx' that could not be found.
如何解决上述这种场景的问题,就要使用到本文介绍的ObjectProvider
3.Spring依赖关系的改进版编程
Spring 4.3中引入了ObjectProvider
使用ObjectProvider
@Service
public class TestService {
private final TestComponent testComponent;
public TestService(ObjectProvider testComponentObjectProvider) {
this.testComponent = testComponentObjectProvider.getIfUnique();
}
}
这样注入的好处很明显,如果容器中不存在testComponent或者存在多个testComponent时,可以从容处理。
Spring中依赖注入的方式有很多种,为什么要一直关注构造器注入,并且Spring官方推荐的依赖注入方式也是构造器注入?
如果依赖关系是强制的,那么最好使用构造函数进行注入。Spring官方这样推荐的理由是:
先来看看Spring官方文档中的描述:The Spring team generally advocates constructor injection as it enables one to implement application components as immutable objects and to ensure that required dependencies are not null. Furthermore constructor-injected components are always returned to client (calling) code in a fully initialized state.
大致意思就是:Spring团队通常提倡构造器注入,因为它可以将应用程序组件实现为不可变对象,并确保所需的依赖项不为空。此外,构造函数注入的组件总是以完全初始化的状态返回给客户端(调用)代码。
1️⃣单一职责原则:当使用构造函数注入依赖时,开发者很容易识别参数是否过多。此时就需要考虑这个类的职责是否过大,是否需要拆分等问题。而使用@Resource和@Autowired注解注入时,不容易发现与识别这个问题。
2️⃣依赖不可变:使用构造器注入时,使用final关键字修饰field。
3️⃣依赖不为空:使用构造器注入时,当要实例化一个Bean时,由于自己实现了有参构造函数,Spring不会调用默认构造函数,此时Spring容器注入所需的依赖,会存在两种情况:
- 容器中存在所需要的Bean,直接注入。
- 容器中不存在所需要的Bean,此时Spring会抛出异常。所以Spring会保证注入的依赖不为空。
4️⃣完全初始化状态:这个点可以根据上面依赖不为空结合起来。Spring调用构造器实例化某个Bean时,要确保注入的依赖不为空,那么肯定会调用所依赖组件的构造方法完成组件的实例化。所以Spring注入进来的依赖都是初始化后的状态。
4.ObjectProvider
在Spring 4.3后,使用构造器注入依赖不需要精确地指定@Autowired注解,毫无疑问是简化了开发,但是与此同时也带来了新的问题。在使用构造器注入依赖时,如果容器中不存在或者存在多个符合的Bean,此时Spring会抛出异常。为了解决这个问题,ObjectProvider
@Override @Nullable public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName, @Nullable SetautowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException { // descriptor 代表当前需要注入的字段或者方法参数, 也就是注入点 // ParameterNameDiscovery 用于解析方法参数名称 descriptor.initParameterNameDiscovery(getParameterNameDiscoverer()); // 1.Optional if (Optional.class == descriptor.getDependencyType()) { return createOptionalDependency(descriptor, requestingBeanName); } // 2.ObjectFactory 、ObjectProvider else if (ObjectFactory.class == descriptor.getDependencyType() || ObjectProvider.class == descriptor.getDependencyType()) { return new DependencyObjectProvider(descriptor, requestingBeanName); } // 3.javax.inject.Provider else if (javaxInjectProviderClass == descriptor.getDependencyType()) { return new Jsr330Factory().createDependencyProvider(descriptor, requestingBeanName); } // 4.@Lazy else { Object result = getAutowireCandidateResolver().getLazyResolutionProxyIfNecessary( descriptor, requestingBeanName); // 5.正常情况 if (result == null) { result = doResolveDependency(descriptor, requestingBeanName, autowiredBeanNames, typeConverter); } return result; } }
可以看到,当注入点为ObjectFactory
BeanObjectProvider
private interface BeanObjectProviderextends ObjectProvider , Serializable { }
DependencyObjectProvider :
private class DependencyObjectProvider implements BeanObjectProvider
可以看看DependencyObjectProvider中的getIfAvailable()方法:
@Override
@Nullable
public Object getIfAvailable() throws BeansException {
try {
// 用于解决嵌套的情况, 类似于ObjectProvider>
if (this.optional) {
return createOptionalDependency(this.descriptor, this.beanName);
}
else {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
@Override
public boolean isRequired() {
return false;
}
};
// 最终还是会调用doResolveDependency()方法解决依赖
return doResolveDependency(descriptorToUse, this.beanName, null, null);
}
}
catch (ScopeNotActiveException ex) {
// Ignore resolved bean in non-active scope
return null;
}
}



