Spring核心接口ObjectProvider

ObjectProvider

1.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>接口的作用。


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配置文件的<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>接口。


3.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注入进来的依赖都是初始化后的状态。


4.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;
			}
		}
  • 5
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
package com.xiangyixiang.www.cloud.business.gateway.configure; import org.springframework.beans.factory.ObjectProvider; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.reactive.CorsWebFilter; import org.springframework.web.cors.reactive.UrlBasedCorsConfigurationSource; import org.springframework.web.util.pattern.PathPatternParser; import java.util.stream.Collectors; /**网关统一配置允许跨域 * zj 解决跨域问题 * @author 张静 */ @Configuration public class CorsConfig { @Bean public CorsWebFilter corsFilter() { CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedMethod("*"); config.addAllowedOrigin("http://39.105.36.172:9250"); config.addAllowedHeader("*"); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(new PathPatternParser()); source.registerCorsConfiguration("/**", config); return new CorsWebFilter(source); } @Bean @ConditionalOnMissingBean public HttpMessageConverters messageConverters(ObjectProvider<HttpMessageConverter<?>> converters) { return new HttpMessageConverters(converters.orderedStream().collect(Collectors.toList())); } }
06-10

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值