7.1 依赖查找来源
7.1.1 来源
来源 | 配置元数据 |
---|---|
Spring DeanDefinition | <bean id = "user" class="com.gcl.bean.User"/> |
@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 id = "user" class="com.gcl.bean.User"/> |
@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 外部化配置