单一类型依赖查找
单一类型依赖查找接口- BeanFactory
从这里我们可以看到一个特性, BeanFactory是单一查找的接口的核心
根据Bean 名称查找
• getBean(String)
• Spring 2.5 覆盖默认参数:getBean(String,Object…)
可以覆盖Bean的构造器的默认参数来获取Bean的实例.
建议这个方法不要使用, 十分危险
看它的描述, 返回的实例可能是一个shared(单例的)或者independent(原生的), 那么这里就会有一个不好的特点, 如果是shared的实例, 用这个getBean方法, 每调用一次就要覆盖它的方法, 对应大部分service实例来说, 我们往往希望其被初始化之后就是不变的, 那么这种getBean的方式就很不可取.
因此我们建议使用BeanFactory的只读的方法, 要么就删除掉旧的BeanDefinition, 后面做一个覆盖.
根据Bean 类型查找
Bean 实时查找
• Spring 3.0 getBean(Class)
• Spring 4.1 覆盖默认参数:getBean(Class,Object…)
建议覆盖默认参数这个方法不要使用, 十分危险
与2.5的那个方法同样道理, 通过类型进行覆盖的, 也不建议.
Spring 5.1 Bean 延迟查找
首先要确定一个问题就是你的spring版本要5.1
• getBeanProvider(Class)
具体例子见本节代码示例
• getBeanProvider(ResolvableType)
会在后面泛型的解析时进行讲解, 这个方法是用于处理多类型的时候, 因为从 Java 5 之后, 我们的类型不再是Class 唯一的类型, 有 Type, 有局部变量, Class也是Type的一个实现类了.
java.lang.reflect.Type
java.lang.reflect.TypeVariable
根据Bean 名称+ 类型查找:getBean(String,Class)
前面讲过了
DependencyLookupDemo.java
搜索22-2.3
代码示例
spring-core项目
搜索 43 | 单一类型依赖查找
ObjectProviderDemo.java
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.geekbang.thinking.in.spring.dependency.lookup;
import org.geekbang.thinking.in.spring.ioc.overview.domain.User;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
/**
* 43 | 单一类型依赖查找:如何查找已知名称或类型的Bean对象?
* <p>
* 通过 {@link ObjectProvider} 进行依赖查找
*
* 46 | 延迟依赖查找:非延迟初始化Bean也能实现延迟查找?
* lookupIfAvailable
* lookupByStreamOps
*
* @author <a href="mailto:mercyblitz@gmail.com">Mercy</a>
* @since
*/
public class ObjectProviderDemo { // @Configuration 是非必须注解
public static void main(String[] args) {
// 创建 BeanFactory 容器
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
// 将当前类 ObjectProviderDemo 作为配置类(Configuration Class)
// 前面讲过这里不加 @Configuration 注解也可以的
applicationContext.register(ObjectProviderDemo.class);
// 启动应用上下文
applicationContext.refresh();
// 依赖查找集合对象
lookupByObjectProvider(applicationContext);
// getIfAvailable 函数式扩展
lookupIfAvailable(applicationContext);
lookupByStreamOps(applicationContext);
// 关闭应用上下文
applicationContext.close();
}
/**
* 46 Stream 扩展, spring 5.1提供的新的 API
* @param applicationContext
*/
private static void lookupByStreamOps(AnnotationConfigApplicationContext applicationContext) {
// 根据类型查找
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
// 之前讲到过如果存在多个相同类型的bean, 直接调 objectProvider.getObject()
// 会返回标注了 @Primary 的那个bean
// 这里演示一下遍历的情况
// ObjectProvider 还是 ObjectFactory 的子类
// ObjectProvider实际上覆盖了Iterable接口的方法, 这是个新特性
// 注意这里还是延迟加载的
// ObjectProvider 对象获取时,并没有获取实际 Bean 的对象,而是在 getObject() 或其他获取方法时才获取
// Iterable<String> stringIterable = objectProvider;
// for (String string : stringIterable) {
// System.out.println(string);
// }
// 另一种写法, 利用stream和lambda
// Stream -> Method reference
objectProvider.stream().forEach(System.out::println);
}
/**
* 46 getIfAvailable 函数式扩展
* @param applicationContext
*/
private static void lookupIfAvailable(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<User> userObjectProvider = applicationContext.getBeanProvider(User.class);
// 容器中没注册 User 这个bean, 那么这里就利用Supplier + lamda 的方式,
// 如果没有bean ,就创建一个user 的 对象出来, 两种写法
//User user = userObjectProvider.getIfAvailable(() -> User.createUser());
User user = userObjectProvider.getIfAvailable(User::createUser);
System.out.println("当前 User 对象:" + user);
}
/**
* 43.1.1.2 Spring 5.1 Bean 延迟查找
* getBeanProvider(Class)
* <p>
* 如果@Bean里面没有指定名称, 方法名就是 Bean 名称 = "helloWorld"
*
* 根据类型查找bean时, 如果有多个相同类型的bean,
* 如这里两个String类型, @Primary 标注的就会优先被查找到
*
* @return
*/
@Bean
@Primary
public String helloWorld() { // 方法名就是 Bean 名称 = "helloWorld"
return "Hello,World";
}
@Bean
public String message() {
return "Message";
}
/**
* 43.1.1.2 Spring 5.1 Bean 延迟查找
* getBeanProvider(Class)
*
* @param applicationContext
*/
private static void lookupByObjectProvider(AnnotationConfigApplicationContext applicationContext) {
ObjectProvider<String> objectProvider = applicationContext.getBeanProvider(String.class);
System.out.println(objectProvider.getObject());
}
}