Spring-IOC(二)

refresh

在AnnotationConfigApplicationContext中说完了无参构造和register两个方法,接下来看最重要的一个方法:refresh,该方法包括了一个bean从实例化到初始化完成所有的流程,该方法在org.springframework.context.support.AbstractApplicationContext#refresh
public void refresh() throws BeansException, IllegalStateException {
	synchronized (this.startupShutdownMonitor) {
		// Prepare this context for refreshing.
		prepareRefresh();

		// Tell the subclass to refresh the internal bean factory.
		ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();

		// Prepare the bean factory for use in this context.
		prepareBeanFactory(beanFactory);

		try {
			// Allows post-processing of the bean factory in context subclasses.
			postProcessBeanFactory(beanFactory);

			// Invoke factory processors registered as beans in the context.
			invokeBeanFactoryPostProcessors(beanFactory);

			// Register bean processors that intercept bean creation.
			registerBeanPostProcessors(beanFactory);

			// Initialize message source for this context.
			initMessageSource();

			// Initialize event multicaster for this context.
			initApplicationEventMulticaster();

			// Initialize other special beans in specific context subclasses.
			onRefresh();

			// Check for listener beans and register them.
			registerListeners();

			// Instantiate all remaining (non-lazy-init) singletons.
			finishBeanFactoryInitialization(beanFactory);

			// Last step: publish corresponding event.
			finishRefresh();
		}

		catch (BeansException ex) {
			if (logger.isWarnEnabled()) {
				logger.warn("Exception encountered during context initialization - " +
						"cancelling refresh attempt: " + ex);
			}

			// Destroy already created singletons to avoid dangling resources.
			destroyBeans();

			// Reset 'active' flag.
			cancelRefresh(ex);

			// Propagate exception to caller.
			throw ex;
		}

		finally {
			// Reset common introspection caches in Spring's core, since we
			// might not ever need metadata for singleton beans anymore...
			resetCommonCaches();
		}
	}
}

这个方法自己没做任何逻辑,全都是调用别的方法来完成bean的创建,先总体说下流程和大体时序图(即每个方法在哪个类中实现的),然后再分点说明,这个流程说完整个IOC也就说完了

流程步骤

  1. 准备工作,初始化属性源等
  2. 获取beanFactory
  3. 准备工作,其实就是对上一步获取的beanFactory设置一些属性等
  4. 后置处理BeanFactory
  5. 调用BeanFactoryPostProcessor
  6. 注册BeanPostProcessor
  7. 初始化message
  8. 初始化应用事件广播器
  9. 调用onRefresh
  10. 注册监听器
  11. 初始化单例bean
  12. 完成刷新

时序图

image

准备上下文环境

在这里主要是对上下文环境的设置,比如记录启动时间、设置活动标志等等

protected void prepareRefresh() {
	// Switch to active.
	this.startupDate = System.currentTimeMillis();
	// 设置关闭标志
	this.closed.set(false);
	// 设置活动标志
	this.active.set(true);

	if (logger.isDebugEnabled()) {
		if (logger.isTraceEnabled()) {
			logger.trace("Refreshing " + this);
		}
		else {
			logger.debug("Refreshing " + getDisplayName());
		}
	}

	// Initialize any placeholder property sources in the context environment.
	// 初始化资源,这是一个空方法,留给子类实现
	initPropertySources();

	// Validate that all properties marked as required are resolvable:
	// see ConfigurablePropertyResolver#setRequiredProperties
	// 获取环境变量并校验所需的属性
	getEnvironment().validateRequiredProperties();

	// Store pre-refresh ApplicationListeners...
	// 判断早期事件监听是否为空,如果为空创建一个集合用来存放
	if (this.earlyApplicationListeners == null) {
		this.earlyApplicationListeners = new LinkedHashSet<>(this.applicationListeners);
	}
	else {
		// Reset local application listeners to pre-refresh state.
		this.applicationListeners.clear();
		this.applicationListeners.addAll(this.earlyApplicationListeners);
	}

	// Allow for the collection of early ApplicationEvents,
	// to be published once the multicaster is available...
	// 存放早期应用事件
	this.earlyApplicationEvents = new LinkedHashSet<>();
}

获取beanFactory

调用obtainFreshBeanFactory方法获取beanFactory其实就是获取DefaultListableBeanFactory,在上一篇文章中说到DefaultListableBeanFactory这个类的创建是在GenericApplicationContext的无参构造方法中new出来的,所以这里获取的beanFactory就是从GenericApplicationContext中获取的

protected ConfigurableListableBeanFactory obtainFreshBeanFactory() {
	/**
	 * 1.如果程序是以xml形式启动的(ClassPathXmlApplicationContext方式),那么这一步会进入{@link AbstractRefreshableApplicationContext}
	 *      xml 方式为什么是这个类:因为 ClassPathXmlApplicationContext 这个类继承了 AbstractRefreshableApplicationContext
	 *
	 * 2.如果程序是以注解形式启动的(AnnotationConfigApplicationContext方式),那么这一步会进入{@link GenericApplicationContext}
	 */
	refreshBeanFactory();
	return getBeanFactory();
}

这是一个标准的模板方法,refreshBeanFactory和getBeanFactory都是抽象方法,具体实现由子类实现。我们都知道spring的配置有两种,一种是xml配置,一种是注解配置,两种配置所对应的处理逻辑是不同的,所以这里获取beanFactory的方式也不同,如果是xml的话,这里获取beanFactory是在AbstractRefreshableApplicationContext中,如果是注解的话获取beanFactory是在GenericApplicationContext中。显然这里是通过GenericApplicationContext获取beanFactory。

@Override
protected final void refreshBeanFactory() throws IllegalStateException {
	if (!this.refreshed.compareAndSet(false, true)) {
		throw new IllegalStateException(
				"GenericApplicationContext does not support multiple refresh attempts: just call 'refresh' once");
	}
	this.beanFactory.setSerializationId(getId());
}

@Override
public final ConfigurableListableBeanFactory getBeanFactory() {
	return this.beanFactory;
}

准备beanFactory

这个方法主要是对beanFactory做一些属性上的配置,比如设置几个忽略自动装配的接口、添加后置处理器等等

protected void prepareBeanFactory(ConfigurableListableBeanFactory beanFactory) {
	// Tell the internal bean factory to use the context's class loader etc.
	// 设置beanFactory的classLoader为当前context的classloader
	beanFactory.setBeanClassLoader(getClassLoader());
	// 设置beanFactory的表达式语言处理器
	beanFactory.setBeanExpressionResolver(new StandardBeanExpressionResolver(beanFactory.getBeanClassLoader()));
	beanFactory.addPropertyEditorRegistrar(new ResourceEditorRegistrar(this, getEnvironment()));

	// Configure the bean factory with context callbacks.
	// 添加这个BeanPostProcessor 的实现类是为了解析程序员写的类实现 ApplicationContextAware 接口
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

	// 设置几个忽略自动装配的接口,这几个接口都在ApplicationContextAwareProcessor中操作,所以这里需要忽略
	beanFactory.ignoreDependencyInterface(EnvironmentAware.class);
	beanFactory.ignoreDependencyInterface(EmbeddedValueResolverAware.class);
	beanFactory.ignoreDependencyInterface(ResourceLoaderAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationEventPublisherAware.class);
	beanFactory.ignoreDependencyInterface(MessageSourceAware.class);
	beanFactory.ignoreDependencyInterface(ApplicationContextAware.class);

	// 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);

	// Register early post-processor for detecting inner beans as ApplicationListeners.
	// 添加一个BeanPostProcessor:ApplicationListenerDetector,这个processor主要是处理spring事件监听器的
	beanFactory.addBeanPostProcessor(new ApplicationListenerDetector(this));

	// Detect a LoadTimeWeaver and prepare for weaving, if found.
	// 增加对AspectJ的支持
	if (beanFactory.containsBean(LOAD_TIME_WEAVER_BEAN_NAME)) {
		beanFactory.addBeanPostProcessor(new LoadTimeWeaverAwareProcessor(beanFactory));
		// Set a temporary ClassLoader for type matching.
		beanFactory.setTempClassLoader(new ContextTypeMatchClassLoader(beanFactory.getBeanClassLoader()));
	}

	// Register default environment beans.
	// 注册默认环境变量 bean
	if (!beanFactory.containsLocalBean(ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(ENVIRONMENT_BEAN_NAME, getEnvironment());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_PROPERTIES_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_PROPERTIES_BEAN_NAME, getEnvironment().getSystemProperties());
	}
	if (!beanFactory.containsLocalBean(SYSTEM_ENVIRONMENT_BEAN_NAME)) {
		beanFactory.registerSingleton(SYSTEM_ENVIRONMENT_BEAN_NAME, getEnvironment().getSystemEnvironment());
	}
}

首先看下如果注入的是BeanFactory、ResourceLoader、ApplicationEventPublisher、ApplicationContext四种类型的话,因为这四个接口的实现太多,如果注入的话不知道到底应该是哪个具体的实现类,所以spring这里就直接替我们选择好了。如果是BeanFactory的话,那么注入的实际类型是DefaultListableBeanFactory,如果注入的是ResourceLoader,那么注入的实际类型是AnnotationConfigApplicationContext,接下来用一段代码来证实这个结论:

@Component
public class SpringAutoRegister {

	@Autowired
	private BeanFactory beanFactory;

	@Autowired
	private ResourceLoader  resourceLoader;

	@Autowired
	private ApplicationEventPublisher   applicationEventPublisher;

	@Autowired
	private ApplicationContext  applicationContext;

	@Override
	public String toString() {
		return "SpringAutoRegister{" +
				"beanFactory=" + beanFactory +
				", resourceLoader=" + resourceLoader +
				", applicationEventPublisher=" + applicationEventPublisher +
				", applicationContext=" + applicationContext +
				'}';
	}
}

public class Main {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		SpringAutoRegister aspectService = context.getBean("springAutoRegister", SpringAutoRegister.class);
		System.out.println(aspectService);
	}
}

运行结果如下:

SpringAutoRegister{beanFactory=org.springframework.beans.factory.support.DefaultListableBeanFactory@45283ce2: defining beans [org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.event.internalEventListenerProcessor,org.springframework.context.event.internalEventListenerFactory,appConfig,conServiceA,conServiceB,serviceImpl,springAutoRegister,org.springframework.aop.config.internalAutoProxyCreator]; root of factory hierarchy, resourceLoader=org.springframework.context.annotation.AnnotationConfigApplicationContext@30f39991, started on Wed Jul 21 17:59:32 CST 2021, applicationEventPublisher=org.springframework.context.annotation.AnnotationConfigApplicationContext@30f39991, started on Wed Jul 21 17:59:32 CST 2021, applicationContext=org.springframework.context.annotation.AnnotationConfigApplicationContext@30f39991, started on Wed Jul 21 17:59:32 CST 2021}

看运行结果是符合我们的预期,那么我们在工作中也会遇到一个接口有多个实现类,那么在注入的时候应该注入哪种实际类型呢?
接下来再看一个例子:

public interface MultiService {
}

@Service
public class ServiceImpl {
	@Autowired
	private MultiService multiService;

	@Override
	public String toString() {
		return "ServiceImpl{" +
				"service=" + multiService +
				'}';
	}

	@Component("conServiceA")
	public static class ConServiceA implements MultiService{}

	@Component("conServiceB")
	public static class ConServiceB implements MultiService{}
}

public class RunTest {

	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		System.out.println(context.getBean("serviceImpl"));
	}
}

上面这段程序中MultiService接口有两个实现类ConServiceA和ConServiceB,在ServiceImpl类中注入了MultiService,那么应该是注入的哪个?这段程序的运行结果是什么?
运行结果如下:

expected single matching bean but found 2: conServiceA,conServiceB

很显然spring无法识别我们需要注入哪个,直接给我们报错了,那又如何解决呢?
改造一
可以参数spring的方式使用registerResolvableDependency方法来指定使用哪个实际类型,做法如下(先不用管为何实现BeanFactoryPostProcessor,后续会着重介绍这个):

@Component
public class MultiBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
   @Override
   public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
      ServiceImpl.ConServiceA conServiceA = new ServiceImpl.ConServiceA();
      beanFactory.registerResolvableDependency(MultiService.class,conServiceA);
   }
}

增加这么一个类,然后再运行刚才的程序,结果如下:

ServiceImpl{service=com.xxx.spring.multiimpl.ServiceImpl$ConServiceA@4563e9ab}

程序正常运行了,这里是参数spring的方法来做的,但在实际工作中毕竟这种方式不多,所以可以使用第二种方式:
改造二
将Autowired注解改为Resource注解并使用name指明使用哪个

@Service
public class ServiceImpl {

   @Resource(name = "conServiceA")
   private MultiService multiService;
   @Override
   public String toString() {
      return "ServiceImpl{" +
            "service=" + multiService +
            '}';
   }
   @Component("conServiceA")
   public static class ConServiceA implements MultiService{}

   @Component("conServiceB")
   public static class ConServiceB implements MultiService{}
}

这样运行的结果如下:

ServiceImpl{service=com.xxx.spring.multiimpl.ServiceImpl$ConServiceA@511baa65}

程序也正常运行起来了,这两种方式比较显然第二种方式更符合我们业务开发的思维,但这也从侧面说明了spring的可扩展性的强大。
这仅仅是一点,到后续的实例化、属性注入和初始化阶段时更能体现spring扩展性的强大。

postProcessBeanFactory

这个方法是个空实现,留给子类实现

posted @ 2021-07-27 18:31  扭不动的奥利奥  阅读(75)  评论(0)    收藏  举报