7.1 依赖查找来源
7.1.1 来源
来源 | 配置元数据 |
Spring DeanDefinition |
|
@Bean public User user {...} | |
BeanDefinitionBuilder | |
单例对象 | API实现 |
7.1.2 Spring 内建 BeanDefinition 以及内建单例对象
详情见 5.7 小结
如何通过 XML 开启注解功能?首先注解功能是由 AnnotationConfigUtils#registerAnnotationConfigProcessors 方法注册启动的,而该方法在 AnnotationConfigBeanDefinitionParser、ComponentScanBeanDefinitionParser、AnnotationBeanDefinitionReader、ClasspathBeanDefinitionScanner 中被调用,启动注解方式有两种:
<context:annotation-config/>
<!-- 不存在的路径也可以,只要有该元素即可 -->
<context:component-scan base-package="xxx"/>
7.2 依赖注入来源
来源 | 配置元数据 |
Spring DeanDefinition |
|
@Bean public User user {...} | |
BeanDefinitionBuilder | |
单例对象 | API实现 |
非 Spring 容器管理对象 |
public class DependencySourceDemo {
// 注入在 postProcessorProperties 方法执行,早于 Setter 注入,也早于 @PostConstructor
// 这四个对象在 AbstractApplicationContext 中进行注册,但是无法从容器中获取
@Resource
private BeanFactory factory;
@Resource
private ResourceLoader loader;
@Resource
private ApplicationContext context;
@Resource
private ApplicationEventPublisher publisher;
@PostConstruct
public void init() {
System.out.println("beanFactory == applicationContext : " + (factory == context));
System.out.println("beanFactory == applicationContext.getBeanFactory : " + (factory == context.getAutowireCapableBeanFactory()));
System.out.println("loader == applicationContext : " + (loader == context));
System.out.println("publisher == applicationContext : " + (publisher == context));
}
@PostConstruct
public void getBean() {
getBean(BeanFactory.class);
getBean(ApplicationEventPublisher.class);
getBean(ApplicationContext.class);
getBean(ResourceLoader.class);
}
private <T> T getBean(Class<T> type) {
try {
return factory.getBean(type);
} catch (NoSuchBeanDefinitionException e) {
System.err.println("当前类型" + type.getName() + "无法在 BeanFactory 中查找到!");
}
return null;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(DependencySourceDemo.class);
context.refresh();
System.out.println(context.getBean(User.class));
context.close();
}
@Bean
public User user() {
User user = new User();
user.setName("foo");
user.setAge(18);
return user;
}
}
// 运行结果:
beanFactory == applicationContext : false
beanFactory == applicationContext.getBeanFactory : true
loader == applicationContext : true
publisher == applicationContext : true
当前类型org.springframework.beans.factory.BeanFactory无法在 BeanFactory 中查找到!
当前类型org.springframework.context.ApplicationEventPublisher无法在 BeanFactory 中查找到!
当前类型org.springframework.context.ApplicationContext无法在 BeanFactory 中查找到!
当前类型org.springframework.core.io.ResourceLoader无法在 BeanFactory 中查找到!
User{name='foo', age=18}
protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
// ...
// BeanFactory interface not registered as resolvable type in a plain factory.
// MessageSource registered (and found for autowiring) as a bean.
beanFactory.registerResolvableDependency(BeanFactory.class, beanFactory);
beanFactory.registerResolvableDependency(ResourceLoader.class, this);
beanFactory.registerResolvableDependency(ApplicationEventPublisher.class, this);
beanFactory.registerResolvableDependency(ApplicationContext.class, this);
// ...
}
7.3 Spring 容器管理和游离对象
来源 | Spring Bean 对象 | 生命周期管理 | 配置元信息 | 使用场景 |
Spring BeanDefinition | 是 | 是 | 是 | 依赖查找、依赖注入 |
单体对象 | 是 | 否 | 否 | 依赖查找、依赖注入 |
Resolvable Dependency(游离对象) | 否 | 否 | 否 | 依赖注入 |
7.4 Spring BeanDefinition 作为依赖来源
- 元数据:BeanDefinition
- 注册:BeanDefinitionRegistry#registerBeanDefinition
- 类型:延迟和非延迟
- 顺序:Bean 生命周期顺序按照注册顺序
注册时会使用 Map 保存 name 和 BeanDefiniton 的映射,并且还会用一个 ArrayList 保存 name 顺序(Map无序),供后续实例化使用,并且需要注意在 Springboot 2.1 以后不允许注入同名 bean
7.5 单例对象作为依赖来源
- 要素
- 来源:外部普通 Java 对象(不一定是 POJO)
- 注册:SingletonBeanRegistry#registerSingleton
- 限制
- 无生命周期管理
- 无法实现延迟初始化 Bean
public class SingletonBeanRegistrationDemo {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
// 创建外部单体对象
DefaultUserFactory factory = new DefaultUserFactory();
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
// 注册外部单体对象
beanFactory.registerSingleton("userFactory", factory);
context.refresh();
// 依赖查找
UserFactory factory1 = context.getBean(UserFactory.class);
System.out.println(factory == factory1);
}
}
7.6 非 Spring 容器管理对象作为依赖来源
- 要素
- 注册:ConfigurableListableBeanFactory#registerResolvableDependency
- 限制
- 无生命周期管理
- 无法实现延迟初始化
- 无法通过依赖查找
public class ResolvableDependencySourceDemo {
@Resource
private String value;
@Resource
private BeanFactory factory;
@PostConstruct
public void init() {
System.out.println(value);
try {
factory.getBean(String.class);
} catch (Exception e) {
System.out.println("err");
}
}
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
ConfigurableListableBeanFactory factory = context.getBeanFactory();
factory.registerResolvableDependency(String.class, "Hello world");
context.register(ResolvableDependencySourceDemo.class);
context.refresh();
context.close();
}
}
7.7 外部化配置作为依赖来源(@Value)
- 要素
- 类型:非常规 Spring 对象依赖来源
- 限制
- 无生命周期管理
- 无法实现延迟初始化 Bean
- 无法通过依赖查找
@Configuration
@PropertySource(value = "default.properties", encoding = "UTF-8")
public class ExternalConfigurationDependencySourceDemo {
@Value("${usr.name:text}")
private String name;
@Value("${user.age:18}")
private int age;
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(ExternalConfigurationDependencySourceDemo.class);
context.refresh();
ExternalConfigurationDependencySourceDemo demo = context.getBean(ExternalConfigurationDependencySourceDemo.class);
System.out.println(demo.name);
System.out.println(demo.age);
context.close();
}
}
7.8 面试题
7.8.1 依赖注入和依赖查找来源是否相同
不同,依赖查找来源仅限于 Spring BeanDefinition 以及单例对象,而依赖注入的来源还包括 Resolvable Dependency 以及 @Value 所标注的外部化配置
7.8.2 单例对象能在 IoC 容器启动后注册吗?
可以,单例对象与 BeanDefinition 不同, BeanDefinition 会被 ConfigurableListableBeanFactory#freezeConfiguration 方法影响从而冻结注册,单例对象则没有该限制
7.8.3 Spring 依赖注入有哪些来源
Spring BeanDefinition
单例对象
Resolvable Dependency
@Value 外部化配置