向IoC中注册bean,有两种方式,分别是向其注册bean配置元数据和注册一个创建完成的单例对象,前者容器将负责bean实例的创建、依赖注入和生命周期的管理。这两种方式管理的对象均可用于依赖注入和依赖查找。
此外,还存在一种注册“依赖”的方式,一般用于框架内部使用,这种方式注册的对象只能用于依赖注入,不能用于依赖查找。
一、配置元数据注册接口
bean元数据注册接口.pngDefaultListableBeanFactory
实现注册接口,使用Map保存配置元数据
二、单例对象注册接口
- 管理单例对象
- 管理通过配置元数据定义的单例bean
- 支持直接注册由外部创建的单例对象
- 具体实现
默认实现类是DefaultSingletonBeanRegistry
,其内部是通过Map对单例对象进行管理的。该类也等效实现了Scope
接口的功能
getSingleton(String, ObjectFactory<?>)
方法实现逻辑如下图:
该方法可看作是Scope#get(String,ObjectFactory<?>)
的等效实现
Scope
支持创建各种不同作用域的bean,容器创建bean默认实现了单例和原型两种作用域
注意:从Scope中移除对象不等同于销毁对象
Spring Cloud中
RefreshScope
扩展了Scope
接口,用于支持bean的动态刷新
三、注册依赖
一般是由框架内部使用,如:
// 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);
这些依赖可用于依赖注入,但是不能被依赖查找
示例:
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
context.register(S6Configuration.class);
context.refresh();
// 框架内部注册的依赖,依赖注入成功
final S6Service s6Service = context.getBean(S6Service.class);
// 打印出被注入的依赖
s6Service.show();
// 框架内部注册的依赖,依赖查找失败
// 报错
final BeanFactory beanFactory = context.getBean(BeanFactory.class);
log.info("[{}]", beanFactory);
}
@Slf4j
@Service
public class S6Service {
@Autowired
private BeanFactory beanFactory;
@Autowired
private ApplicationContext applicationContext;
public void show() {
log.info("beanFactory={}", beanFactory);
log.info("applicationContext={}", applicationContext);
}
}
接口类图如下:
注册依赖.png四、使用时机
Ioc容器启动时
-
解析xml配置文件、注解等配置元数据,调用上述接口进行注册,解析过程详见前述章节
-
使用容器生命周期接口注册
BeanFactoryPostProcessor
BeanDefinitionRegistryPostProcessor
该接口执行时机比较早,在实例化bean之前会被容器优先调用
启动后运行中
在容器运行中注册bean,会导致其不能和其他bean很好地协作,因为此时,其他bean可能已经被实例化了
网友评论