第七章:Spring IoC依賴來源(Dependency Sources)
依賴查找的來源
- 查找來源
來源 | 配置元數據 |
---|---|
Spring BeanDefinition | <bean id="user" class="..."/> |
Spring BeanDefinition | @Bean public User user(){…} |
Spring BeanDefinition | BeanDefinitionBuilder |
單例對象 | API 實現 |
- Spring 內建 BeanDefinition
Bean 名稱 | Bean 實例 | 使用場景 |
---|---|---|
org.springframework.context.annotation.internalConfigurationAnnotationProcessor | ConfigurationClassPostProcessor 對象 |
處理 Spring 配置類 |
org.springframework.context.annotation.internalAutowiredAnnotationProcessor | AutowiredAnnotationBeanPostProcessor 對象 | 處理 @Autowired 以及 @Value 註解 |
org.springframework.context.annotation.internalCommonAnnotationProcessor | CommonAnnotationBeanProcessor 對象 | (條件激活)處理 JSR-250 註解 ,如 @PostContruct |
org.springframework.context.event.internalEventListenerProcessor | EventListenerMethodProcessor 對象 | 處理標註 @EventListener 的 Spring 事件監聽方法 |
org.springframework.context.event.internalEventListenerFactory | DefaultEventListenerFactory 對象 | @EventListener 事件監聽方法適配爲 ApplicationListener |
org.springframework.context.annotation.internalPersistenceAnnotationProcessor | PersistenceAnnotationBeanPostProcessor 對象 | (條件激活)處理 JPA 註解 |
org.springframework.context.annotation.AnnotationConfigUtils
- Spring 內建單例對象
Bean 名稱 | Bean 實例 | 使用場景 |
---|---|---|
environment | Environment 對象 | 外部化配置以及 Profiles |
systemProperties | java.util.Properties 對象 | Java 系統屬性 |
systemEnvironment | java.util.Map 對象 | 操作系統環境變量 |
messageSource | MessageSource 對象 | 國際化文案 |
lifecycleProcessor | LifecycleProcessor 對象 | Lifecycle Bean 處理器 |
applicationEventMulticaster | ApplicationEventMulticaster 對象 | Spring 事件廣播器 |
org.springframework.context.support.AbstractApplicationContext
依賴注入的來源
- 注入來源
來源 | 配置元數據 |
---|---|
Spring BeanDefinition | <bean id="user" class="..."/> |
Spring BeanDefinition | @Bean public User user(){…} |
Spring BeanDefinition | BeanDefinitionBuilder |
單例對象 | API 實現 |
非 Spring 容器管理對象 (ResolvableDependency 又稱:可處理的依賴、非推廣對象、遊離對象 ) |
xxx |
AbstractApplicationContext#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);
public class DependencySourceDemo {
// 注入在 postProcessProperties 方法執行,早於 setter注入,也早於 @PostConstruct
@Autowired
private BeanFactory beanFactory;
@Autowired
private ResourceLoader resourceLoader;
@Autowired
private ApplicationContext applicationContext;
@Autowired
private ApplicationEventPublisher applicationEventPublisher;
@PostConstruct
public void initByInjection() {
System.out.println("beanFactory == applicationContext " + (beanFactory == applicationContext));
System.out.println("beanFactory == applicationContext.getBeanFactory() " + (beanFactory == applicationContext.getAutowireCapableBeanFactory()));
System.out.println("resourceLoader == applicationContext " + (resourceLoader == applicationContext));
System.out.println("ApplicationEventPublisher == applicationContext " + (applicationEventPublisher == applicationContext));
}
@PostConstruct
public void initByLookup() {
getBean(BeanFactory.class);
getBean(ApplicationContext.class);
getBean(ResourceLoader.class);
getBean(ApplicationEventPublisher.class);
}
private <T> T getBean(Class<T> beanType) {
try {
return beanFactory.getBean(beanType);
} catch (NoSuchBeanDefinitionException e) {
System.err.println("當前類型" + beanType.getName() + " 無法在 BeanFactory 中查找!");
}
return null;
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(DependencySourceDemo.class);
applicationContext.refresh();
DependencySourceDemo demo = applicationContext.getBean(DependencySourceDemo.class);
applicationContext.close();
}
}
Spring 容器管理和遊離對象
- 依賴對象
來源 | Spring bean 對象 | 生命週期管理 | 配置元信息 | 使用場景 |
---|---|---|---|---|
Spring Beandifinition | 是 |
是 |
有 |
依賴查找、依賴注入 |
單體對象 | 是 |
否 | 無 | 依賴查找、依賴注入 |
ResolvableDependency |
否 | 否 | 無 | 依賴注入 |
Spring BeanDefinition 作爲依賴來源
- 要素
- 元數據 : BeanDifinition
- 註冊 :
BeanDifinitionRegistry
#registerBeanDifinition - 類型 : 延遲和非延遲
- 順序 : Bean 生命週期順序按照註冊順序
DefaultListableBeanFactory 是 BeanDifinitionRegistry 的一個基本實現類
if (hasBeanCreationStarted()) {
// Cannot modify startup-time collection elements anymore (for stable iteration)
synchronized (this.beanDefinitionMap) {
this.beanDefinitionMap.put(beanName, beanDefinition);
List<String> updatedDefinitions = new ArrayList<>(this.beanDefinitionNames.size() + 1);
updatedDefinitions.addAll(this.beanDefinitionNames);
updatedDefinitions.add(beanName);
this.beanDefinitionNames = updatedDefinitions;
removeManualSingletonName(beanName);
}
}
else {
// Still in startup registration phase
this.beanDefinitionMap.put(beanName, beanDefinition);
this.beanDefinitionNames.add(beanName);
removeManualSingletonName(beanName);
}
this.frozenBeanDefinitionNames = null;
單例對象作爲依賴來源
- 要素
- 來源:外部普通 Java 對象(不一定 POJO)
- 註冊:
SingletonBeanRegistry
#registerSingleton - 可用於依賴查找和依賴注入
- 限制
- 生命週期不由
Spring 上下文
來管理 - 無法實現延遲初始化 Bean
- 生命週期不由
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry
@Override
public void registerSingleton(String beanName, Object singletonObject) throws IllegalStateException {
Assert.notNull(beanName, "Bean name must not be null");
Assert.notNull(singletonObject, "Singleton object must not be null");
synchronized (this.singletonObjects) {
Object oldObject = this.singletonObjects.get(beanName);
if (oldObject != null) {
throw new IllegalStateException("Could not register object [" + singletonObject +
"] under bean name '" + beanName + "': there is already object [" + oldObject + "] bound");
}
addSingleton(beanName, singletonObject);
}
}
protected void addSingleton(String beanName, Object singletonObject) {
synchronized (this.singletonObjects) {
this.singletonObjects.put(beanName, singletonObject);
this.singletonFactories.remove(beanName);
this.earlySingletonObjects.remove(beanName);
this.registeredSingletons.add(beanName);
}
}
public class SingletonBeanRegistrationDemo {
public static void main(String[] args) throws InterruptedException {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
SingletonBeanRegistry singletonBeanRegistry = applicationContext.getBeanFactory();
// 創建一個外部 UserFactory 對象
UserFactory userFactory = new DefaultUserFactory();
// 註冊外部單例對象
singletonBeanRegistry.registerSingleton("userFactory", userFactory);
// 啓動 Spring 應用上下文
applicationContext.refresh();
// 通過依賴查找的方式來獲取 UserFactory
UserFactory userFactoryByLookup = applicationContext.getBean("userFactory", UserFactory.class);
System.out.println("userFactory == userFactoryByLookup : " + (userFactory == userFactoryByLookup));
// 關閉 Spring 應用上下文
applicationContext.close();
}
}
非 Spring 容器管理對象作爲依賴來源
- 要素
- 註冊:
ConfigurableListableBeanFactory
#registerResolvableDependency
- 註冊:
- 限制
- 生命週期不由
Spring 上下文
來管理 - 無法實現延遲初始化 Bean
- 無法通過依賴查找
- 生命週期不由
默認實現:DefaultListableBeanFactory
//---------------------------------------------------------------------
// Implementation of ConfigurableListableBeanFactory interface
//---------------------------------------------------------------------
@Override
public void registerResolvableDependency(Class<?> dependencyType, @Nullable Object autowiredValue) {
Assert.notNull(dependencyType, "Dependency type must not be null");
if (autowiredValue != null) {
if (!(autowiredValue instanceof ObjectFactory || dependencyType.isInstance(autowiredValue))) {
throw new IllegalArgumentException("Value [" + autowiredValue +
"] does not implement specified dependency type [" + dependencyType.getName() + "]");
}
this.resolvableDependencies.put(dependencyType, autowiredValue);
}
}
public class ResolvableDependencySourceDemo {
@Autowired
private String value;
@PostConstruct
public void init() {
System.out.println(value);
}
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ResolvableDependencySourceDemo.class);
applicationContext.addBeanFactoryPostProcessor(beanFactory -> {
// 註冊 Resolvable Dependency
beanFactory.registerResolvableDependency(String.class, "Hello,World");
});
applicationContext.refresh();
applicationContext.close();
}
}
外部化配置作爲依賴來源
- 要素
- 類型:非常規 Spring 對象依賴來源
- 限制
- 生命週期不由
Spring 上下文
來管理 - 無法實現延遲初始化 Bean
- 無法通過
依賴查找
- 生命週期不由
默認實現: AutowiredAnnotationBeanPostProcessor
public AutowiredAnnotationBeanPostProcessor() {
this.autowiredAnnotationTypes.add(Autowired.class);
this.autowiredAnnotationTypes.add(Value.class);
try {
this.autowiredAnnotationTypes.add((Class<? extends Annotation>)
ClassUtils.forName("javax.inject.Inject", AutowiredAnnotationBeanPostProcessor.class.getClassLoader()));
logger.trace("JSR-330 'javax.inject.Inject' annotation found and supported for autowiring");
}
catch (ClassNotFoundException ex) {
// JSR-330 API not available - simply skip.
}
}
@Configuration
@PropertySource(value = "META-INF/default.properties",encoding="UTF-8")
public class ExternalConfigurationDependencySourceDemo {
@Value("${user.id:-1}")
private Long id;
@Value("${usr.name}")
private String name;
@Value("${user.resource:classpath://default.properties}")
private Resource resource;
public static void main(String[] args) {
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
applicationContext.register(ExternalConfigurationDependencySourceDemo.class);
applicationContext.refresh();
// 依賴查找 ExternalConfigurationDependencySourceDemo Bean
ExternalConfigurationDependencySourceDemo demo = applicationContext.getBean(ExternalConfigurationDependencySourceDemo.class);
System.out.println("demo.id = " + demo.id);
System.out.println("demo.name = " + demo.name);
System.out.println("demo.resource = " + demo.resource);
applicationContext.close();
}
}
user.id = 1
usr.name = 小馬哥
user.resource = classpath://META-INF/default.properties
總結
- 依賴注入和依賴查找的依賴來源是否相同?