第七章:Spring IoC依賴來源

第七章: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

總結

  1. 依賴注入和依賴查找的依賴來源是否相同?
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章