ObjectProvider<T>
接口Spring 4.3
版本中新加入了ObjectProvider<T>
接口,ObjectProvider<T>
接口源码如下:
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;
/**
* A variant of {@link ObjectFactory} designed specifically for injection points,
* allowing for programmatic optionality and lenient not-unique handling.
*
* <p>As of 5.1, this interface extends {@link Iterable} and provides {@link Stream}
* support. It can be therefore be used in {@code for} loops, provides {@link #forEach}
* iteration and allows for collection-style {@link #stream} access.
*
* @author Juergen Hoeller
* @since 4.3
* @param <T> the object type
* @see BeanFactory#getBeanProvider
* @see org.springframework.beans.factory.annotation.Autowired
*/
public interface ObjectProvider<T> extends ObjectFactory<T>, Iterable<T> {
/**
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* <p>Allows for specifying explicit construction arguments, along the
* lines of {@link BeanFactory#getBean(String, Object...)}.
* @param args arguments to use when creating a corresponding instance
* @return an instance of the bean
* @throws BeansException in case of creation errors
* @see #getObject()
*/
T getObject(Object... args) throws BeansException;
/**
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* @return an instance of the bean, or {@code null} if not available
* @throws BeansException in case of creation errors
* @see #getObject()
*/
@Nullable
T getIfAvailable() throws BeansException;
/**
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* @param defaultSupplier a callback for supplying a default object
* if none is present in the factory
* @return an instance of the bean, or the supplied default object
* if no such bean is available
* @throws BeansException in case of creation errors
* @since 5.0
* @see #getIfAvailable()
*/
default T getIfAvailable(Supplier<T> defaultSupplier) throws BeansException {
T dependency = getIfAvailable();
return (dependency != null ? dependency : defaultSupplier.get());
}
/**
* Consume an instance (possibly shared or independent) of the object
* managed by this factory, if available.
* @param dependencyConsumer a callback for processing the target object
* if available (not called otherwise)
* @throws BeansException in case of creation errors
* @since 5.0
* @see #getIfAvailable()
*/
default void ifAvailable(Consumer<T> dependencyConsumer) throws BeansException {
T dependency = getIfAvailable();
if (dependency != null) {
dependencyConsumer.accept(dependency);
}
}
/**
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* @return an instance of the bean, or {@code null} if not available or
* not unique (i.e. multiple candidates found with none marked as primary)
* @throws BeansException in case of creation errors
* @see #getObject()
*/
@Nullable
T getIfUnique() throws BeansException;
/**
* Return an instance (possibly shared or independent) of the object
* managed by this factory.
* @param defaultSupplier a callback for supplying a default object
* if no unique candidate is present in the factory
* @return an instance of the bean, or the supplied default object
* if no such bean is available or if it is not unique in the factory
* (i.e. multiple candidates found with none marked as primary)
* @throws BeansException in case of creation errors
* @since 5.0
* @see #getIfUnique()
*/
default T getIfUnique(Supplier<T> defaultSupplier) throws BeansException {
T dependency = getIfUnique();
return (dependency != null ? dependency : defaultSupplier.get());
}
/**
* Consume an instance (possibly shared or independent) of the object
* managed by this factory, if unique.
* @param dependencyConsumer a callback for processing the target object
* if unique (not called otherwise)
* @throws BeansException in case of creation errors
* @since 5.0
* @see #getIfAvailable()
*/
default void ifUnique(Consumer<T> dependencyConsumer) throws BeansException {
T dependency = getIfUnique();
if (dependency != null) {
dependencyConsumer.accept(dependency);
}
}
/**
* Return an {@link Iterator} over all matching object instances,
* without specific ordering guarantees (but typically in registration order).
* @since 5.1
* @see #stream()
*/
@Override
default Iterator<T> iterator() {
return stream().iterator();
}
/**
* Return a sequential {@link Stream} over all matching object instances,
* without specific ordering guarantees (but typically in registration order).
* @since 5.1
* @see #iterator()
* @see #orderedStream()
*/
default Stream<T> stream() {
throw new UnsupportedOperationException("Multi element access not supported");
}
/**
* Return a sequential {@link Stream} over all matching object instances,
* pre-ordered according to the factory's common order comparator.
* <p>In a standard Spring application context, this will be ordered
* according to {@link org.springframework.core.Ordered} conventions,
* and in case of annotation-based configuration also considering the
* {@link org.springframework.core.annotation.Order} annotation,
* analogous to multi-element injection points of list/array type.
* @since 5.1
* @see #stream()
* @see org.springframework.core.OrderComparator
*/
default Stream<T> 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<T>
接口的一种变体,专为注入点设计,允许编程可选性和宽松的非唯一处理。描述非常抽象,下面详细解释ObjectProvider<T>
接口的作用。
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
配置文件的<bean></bean>
标签对中。
从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<T>
接口。
Spring
依赖关系的改进版编程Spring 4.3
中引入了ObjectProvider<T>
接口。它是现有ObjectFactory<T>
接口的扩展,具有方便的签名。例如getIfAvailable()
和getIfUnique()
。只有在它实际存在时才会检索Bean
,同时支持可选,可以确定单个候选者在多个匹配的Bean
的情况下。
使用ObjectProvider<T>
进行构造器注入,可以灵活选择合适的Bean
进行注入:
@Service
public class TestService {
private final TestComponent testComponent;
public TestService(ObjectProvider<TestComponent> 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
注入进来的依赖都是初始化后的状态。
ObjectProvider<T>
源码分析在Spring 4.3
后,使用构造器注入依赖不需要精确地指定@Autowired
注解,毫无疑问是简化了开发,但是与此同时也带来了新的问题。在使用构造器注入依赖时,如果容器中不存在或者存在多个符合的Bean
,此时Spring
会抛出异常。为了解决这个问题,ObjectProvider<T>
接口应运而生。使用ObjectProvider<T>
则可以避免强依赖导致的依赖对象不存在异常。如果容器中存在多个类型相同的Bean
实例,ObjectProvider<T>
中提供的方法可以根据Bean
实现的Ordered
接口或者@Order
注解指定的先后顺序获取一个Bean
。这个过程的实现具体体现在org.springframework.beans.factory.support.DefaultListableBeanFactory#resolveDependency()
方法中:
@Override
@Nullable
public Object resolveDependency(DependencyDescriptor descriptor, @Nullable String requestingBeanName,
@Nullable Set<String> autowiredBeanNames, @Nullable TypeConverter typeConverter) throws BeansException {
// descriptor 代表当前需要注入的字段或者方法参数, 也就是注入点
// ParameterNameDiscovery 用于解析方法参数名称
descriptor.initParameterNameDiscovery(getParameterNameDiscoverer());
// 1.Optional<T>
if (Optional.class == descriptor.getDependencyType()) {
return createOptionalDependency(descriptor, requestingBeanName);
}
// 2.ObjectFactory<T>、ObjectProvider<T>
else if (ObjectFactory.class == descriptor.getDependencyType() ||
ObjectProvider.class == descriptor.getDependencyType()) {
return new DependencyObjectProvider(descriptor, requestingBeanName);
}
// 3.javax.inject.Provider<T>
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<T>
或者ObjectProvider<T>
时,会new
一个DependencyObjectProvider
返回出去,可以看看DependencyObjectProvider
的继承关系:
BeanObjectProvider<T>
:
private interface BeanObjectProvider<T> extends ObjectProvider<T>, Serializable {
}
DependencyObjectProvider
:
private class DependencyObjectProvider implements BeanObjectProvider<Object> {
private final DependencyDescriptor descriptor;
private final boolean optional;
@Nullable
private final String beanName;
public DependencyObjectProvider(DependencyDescriptor descriptor, @Nullable String beanName) {
this.descriptor = new NestedDependencyDescriptor(descriptor);
this.optional = this.descriptor.getDependencyType() == Optional.class;
this.beanName = beanName;
}
public Object getObject() throws BeansException {
if (this.optional) {
return DefaultListableBeanFactory.this.createOptionalDependency(this.descriptor, this.beanName);
} else {
Object result = DefaultListableBeanFactory.this.doResolveDependency(this.descriptor, this.beanName, (Set)null, (TypeConverter)null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
} else {
return result;
}
}
}
public Object getObject(final Object... args) throws BeansException {
if (this.optional) {
return DefaultListableBeanFactory.this.createOptionalDependency(this.descriptor, this.beanName, args);
} else {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
public Object resolveCandidate(String beanName, Class<?> requiredType, BeanFactory beanFactory) {
return beanFactory.getBean(beanName, args);
}
};
Object result = DefaultListableBeanFactory.this.doResolveDependency(descriptorToUse, this.beanName, (Set)null, (TypeConverter)null);
if (result == null) {
throw new NoSuchBeanDefinitionException(this.descriptor.getResolvableType());
} else {
return result;
}
}
}
@Nullable
public Object getIfAvailable() throws BeansException {
try {
if (this.optional) {
return DefaultListableBeanFactory.this.createOptionalDependency(this.descriptor, this.beanName);
} else {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
public boolean isRequired() {
return false;
}
};
return DefaultListableBeanFactory.this.doResolveDependency(descriptorToUse, this.beanName, (Set)null, (TypeConverter)null);
}
} catch (ScopeNotActiveException var2) {
return null;
}
}
public void ifAvailable(Consumer<Object> dependencyConsumer) throws BeansException {
Object dependency = this.getIfAvailable();
if (dependency != null) {
try {
dependencyConsumer.accept(dependency);
} catch (ScopeNotActiveException var4) {
}
}
}
@Nullable
public Object getIfUnique() throws BeansException {
DependencyDescriptor descriptorToUse = new DependencyDescriptor(this.descriptor) {
public boolean isRequired() {
return false;
}
@Nullable
public Object resolveNotUnique(ResolvableType type, Map<String, Object> matchingBeans) {
return null;
}
};
try {
return this.optional ? DefaultListableBeanFactory.this.createOptionalDependency(descriptorToUse, this.beanName) : DefaultListableBeanFactory.this.doResolveDependency(descriptorToUse, this.beanName, (Set)null, (TypeConverter)null);
} catch (ScopeNotActiveException var3) {
return null;
}
}
public void ifUnique(Consumer<Object> dependencyConsumer) throws BeansException {
Object dependency = this.getIfUnique();
if (dependency != null) {
try {
dependencyConsumer.accept(dependency);
} catch (ScopeNotActiveException var4) {
}
}
}
@Nullable
protected Object getValue() throws BeansException {
return this.optional ? DefaultListableBeanFactory.this.createOptionalDependency(this.descriptor, this.beanName) : DefaultListableBeanFactory.this.doResolveDependency(this.descriptor, this.beanName, (Set)null, (TypeConverter)null);
}
public Stream<Object> stream() {
return this.resolveStream(false);
}
public Stream<Object> orderedStream() {
return this.resolveStream(true);
}
private Stream<Object> resolveStream(boolean ordered) {
DependencyDescriptor descriptorToUse = new StreamDependencyDescriptor(this.descriptor, ordered);
Object result = DefaultListableBeanFactory.this.doResolveDependency(descriptorToUse, this.beanName, (Set)null, (TypeConverter)null);
return result instanceof Stream ? (Stream)result : Stream.of(result);
}
}
可以看看DependencyObjectProvider
中的getIfAvailable()
方法:
@Override
@Nullable
public Object getIfAvailable() throws BeansException {
try {
// 用于解决嵌套的情况, 类似于ObjectProvider<Optional<T>>
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;
}
}