Skip to content

SpringIOC的朴素解释

分类:

Spring Framework是构建与IOC与AOP之上的。这篇文章与另一篇文章SpringAOP的朴素解释是互补的。IOC意为控制反转,在Spring官方文档中这个IOC与DI(依赖注入)是同一个概念。

1.控制反转 这是一种程序设计思想。将程序中的对象的创建与对象与对象之间的依赖关系的解决交给IOC容器管理。 在传统的开发中对象的创建与依赖的解决通常是这样的(假设A的对象依赖与B的对象):

  • 形式1:
java
public class A{
	private B b;
	public A() {
		b = new B();
	}
	public void doSomething(){
		b.say();
	}
    public static void main(String[] args) {
	A a =new A();	
	}
}
  • 形式2:
java
public class A{
	private B b;
	public A(B b) {
		this.b = b; 
	}
	public void doSomething(){
		b.say();
	}
    public static void main(String[] args) {
    B b = new B();
	A a =new A(b);	
	}
}
  • 形式3:
java
public class A{
	private B b;
	public void setB(B b) {
		this.b = b; 
	}
	public void doSomething(){
		b.say();
	}
    public static void main(String[] args) {
        B b = new B();
        A a =new A();	
        a.setB(b);
	}
}
  • 或者是使用工厂,建造者等等方式得到对象实例,在这个过程或者实例化之后将依赖关系解决。

上述的对象的创建与与依赖关系的解决是存在诸多问题的。在开始阐述这些问题之前我们首先要遵从几条编程原则。一是依赖抽象而非依赖实现,这样的被依赖的类在具体实现变化的时候也不会影响依赖方的业务,这是对高内聚低耦合原则的一个实践;二是将业务与非业务逻辑分离,业务开发者应该将精力放在业务开发上面,而非一些边缘系统与边缘功能的实现上;三是尽可能节省系统资源,不论是CPU资源还是内存资源能省则省,限制一个类对象的数量,控制对象的生命周期。 很显然上述的几种形式都违反了上述原则中的一条或多条。形式1会创建很多的B的对象,在B对象是无状态的时候创建这么多多余的对象是对资源的浪费,另外一个点就是A依赖了B的具体实现,不论B是一个接口还是一个抽象类,在其调用构造器实例化的时候都是会依赖具体实现的,B对象的生命周期与创建它的A对象相绑定了,这使得B对象的生命周期最小化了,为了解决依赖实现的问题,形式2、3都是将依赖从外部传递进来,同时如果在外部控制得当,B的对象可以保持始终只有一个,而此时我们会想,A的对象数量也应该的到限制,并且对象的创建与依赖关系的解决不属于业务范畴,业务开发者是不关心对象是如何创建的,他的依赖关系是如何解决的,他只关心我拿到的对象是可用的已经解决好依赖的对象。于是一个专门获取对象的工厂就应运而生,他有这样一个方法,可以直接获取我想要的对象并且我拿到的这个对象应该是直接可用的。而这个可以直接获取对象,能够解决依赖关系的外部工厂就是IOC的核心,叫做IOC容器。

**注:**IOC的实现方式主要有两种:依赖注入和依赖查找;依赖注入方式容器会将相关依赖直接注入到对象中,而依赖查找则使用回调的方式将Context与条件给到会掉方法,回调得自己解决依赖。

2.IOC容器

当人们问起SpringIOC的时候一般问的都是SpringIOC容器。在Spring官方文档中说,ApplicationContext接口代表SpringIOC容器,也就是说SpringIOC容器必然是ApplicationContext接口的某个具体实现。以下是官方文档翻译:

text
org.springframework.context.ApplicationContext接口代表Spring IoC容器,负责实例化、配置和组装Bean。容器通过读取配置元数据来获取关于要实例化、配置和组装哪些对象的指令。配置元数据用XML、Java注解或Java代码表示。它让你可以表达组成你的应用程序的对象以及这些对象之间丰富的相互依赖关系。

ApplicationContext有着非常复杂的继承与实现关系,对于一个SpringBoot应用来说,你需要着重注意以下类或者接口(已标明层次关系):

java
BeanFactory
├─ DefaultListableBeanFactory 
└─ ApplicationContext
    └─ ConfigurableApplicationContext
       ├─ AnnotationConfigApplicationContext
       ├─ AnnotationConfigServletWebServerApplicationContext
       └─ AnnotationConfigReactiveWebServerApplicationContext

@EnableAutoConfiguration、@ComponentScan和@Configuration文中有提到,SpringBoot有三种类型的应用:普通Java应用,响应式Web应用和ServletWeb应用。而这三种应用对应的三个具体ApplicationContext实现分别是AnnotationConfigApplicationContext、AnnotationConfigReactiveWebServerApplicationContext和AnnotationConfigServletWebServerApplicationContext。这三个具体实现到基于GenericApplicationContext这个实现,这个ApplicationContext内部定义有一个DefaultListableBeanFactory属性:

java
public class GenericApplicationContext extends AbstractApplicationContext implements BeanDefinitionRegistry {
	private final DefaultListableBeanFactory beanFactory;
	public GenericApplicationContext() {
		this.beanFactory = new DefaultListableBeanFactory();
	}
	public GenericApplicationContext(DefaultListableBeanFactory beanFactory) {
		Assert.notNull(beanFactory, "BeanFactory must not be null");
		this.beanFactory = beanFactory;
	}
...................
}

所有的bean都从这个beanFactory里面拿。DefaultListableBeanFactory里面有一堆map、set与list存储bean、beanDefinition及解决依赖关系。也就是说IOC容器在DefaultListableBeanFactory已经实现了,里面有几个常用且重要的属性

java
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    //------------------以下是一些需要重点关注的属性-------------
    //存储这个类的所有beanName
    private final Map<Class<?>, String[]> allBeanNamesByType = new ConcurrentHashMap<>(64);
    //存储这个单例bean的所有beanName
    private final Map<Class<?>, String[]> singletonBeanNamesByType = new ConcurrentHashMap<>(64);
    //beanDefinition名称的list
    private volatile List<String> beanDefinitionNames = new ArrayList<>(256);
    //BeanDefinition的map
    private final Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);
    //所有的beanPostProcessors
    private final List<BeanPostProcessor> beanPostProcessors = new CopyOnWriteArrayList<>();
    //自定义scope
    private final Map<String, Scope> scopes = new LinkedHashMap<>(8);
    //缓存
    private final Map<String, Object> singletonObjects = new ConcurrentHashMap<>(256);
    //bean的依赖关系的map,bean name -> 这个bean所依赖的bean的Set
    private final Map<String, Set<String>> dependenciesForBeanMap = new ConcurrentHashMap<>(64);
    //bean的依赖关系的map,bean name -> 这个bean被那些bean所依赖Set
    private final Map<String, Set<String>> dependentBeanMap = new ConcurrentHashMap<>(64);
}

上面的集合与map基本上是在创建对象和解决依赖上用到的:

allBeanNamesByType、singletonBeanNamesByType :这个类的所有beanName,在调用getBean(Class<T>)的时候会用到,因为本质上Spring只提供了getBean(beanName,)这样的通过名称查找到基本方法。 beanDefinitionNames:在检查bean是否存在时有用到,在注册BeanDefinition和一些其他场景会用到,本质是为了加快bean查找并且查找的时候bean不会被实例化。 beanDefinitionMap :在getBean()的时候会用到。 beanPostProcessors:在getBean()的时候会用到,AOP是在应用beanPostProcessor这一步处理的,BeanPostProcessor在Spring中是一个非常重要的接口。 scopes :自定义scope的map,Scope标识 -> Scope实现 singletonObjects :已缓存的单例bean的map,只有单例需要缓存。 dependenciesForBeanMap、dependentBeanMap:用与解决依赖。

使用:

java
//依赖TestClass
public class TestClass2 {
	private TestClass testClass;
	//默认是使用内省注入依赖的,所以它是必须的
	public void setTestClass(TestClass testClass) {
		this.testClass = testClass;
	}
	public void doSomething(){
		testClass.doSomething();
	}
}

public class TestClass {
	public void doSomething(){
		System.out.println("----------TestClass doSomething----------");
	}
}

public class OtherTest {
	public static void main(String[] args) throws BeansException, NoSuchFieldException, SecurityException {

		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		beanFactory.addBeanPostProcessor(new BeanPostProcessor() {
			@Override
			public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
				System.out.println(bean);
				System.out.println(beanName);
				return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
			}

			@Override
			public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
				System.out.println(bean);
				System.out.println(beanName);
				return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
			}
		});
		System.out.println("-----------------------");

		//定义beanDefinition、自动注入依赖
		BeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition(TestClass2.class)
				.addAutowiredProperty("testClass")
				.addDependsOn("testClass").getBeanDefinition();
		
		beanFactory.registerBeanDefinition("testClass", new RootBeanDefinition(TestClass.class));
		beanFactory.registerBeanDefinition("testClass2", beanDefinition);

		beanFactory.getBean(TestClass2.class).doSomething();

		System.out.println("--------OtherTest------------");
	}
}

上述只是一个大概用法,不过你也可以感受到,BeanFactory实际上以及是一个IOC容器了。

那么为什么使用ApplicationContext呢?原因ApplicationContext的getBean()虽然是委托给内部BeanFactory来实现的,但是其他增强功能比如XXXXXXAware、BeanFactoryPostProcessor、Application事件及事件处理、Message增强与Resource增强等等一大堆,用Spring官方的话就是:它扩展了BeanFactory接口,以更加面向应用框架的方式提供额外的功能。他有几个重要的属性:

java
public class AnnotationConfigServletWebServerApplicationContext extends ServletWebServerApplicationContext
		implements AnnotationConfigRegistry {
    //扫描器
    private final ClassPathBeanDefinitionScanner scanner;
    //此上下文所使用的环境。里面封装着k,v参数
    private ConfigurableEnvironment environment;
    //上面所说的beanFactory
    private final DefaultListableBeanFactory beanFactory;
    //BeanFactoryPostProcessor列表
    private final List<BeanFactoryPostProcessor> beanFactoryPostProcessors = new ArrayList<>();
    //这个ApplicationContext的生命周期处理器
    private LifecycleProcessor lifecycleProcessor;
    //国际化相关
    private MessageSource messageSource;
    //事件监听器
    private final Set<ApplicationListener<?>> applicationListeners = new LinkedHashSet<>();
    //服务器抽象
    private volatile WebServer webServer;
    //servlet应用上下文
    private ServletContext servletContext;
    //资源加载器
    private ResourceLoader resourceLoader;
}

上面的基本上是AppicationContext要使用到的工具: scanner:从基包中扫描并注册BeanDefinition,在refresh()是会被postProcessBeanFactory()所使用。 environment:当前ApplicationContext的运行环境的抽象,就是一大堆properties的抽象,包括了当前active的配置。 beanFactory:getBean()是委托给这个factory的,同时其他组件也是注册到这了容器里面的。 beanFactoryPostProcessors:BeanFactoryPostProcessor处理器,在准备好环境后使用,分为两类:BeanDefinitionRegistryPostProcessor先于其他BeanFactoryPostProcessor之前执行,它甚至可以注册BeanFactoryPostProcessor到ApplicationContext;在BeanDefinitionRegistryPostProcessor执行完后BeanFactoryPostProcessor才会执行,包括前面的BeanDefinitionRegistryPostProcessor对应的方法也会被执行。有个重要的实现ConfigurationClassPostProcessor,在Spring是如何处理@EnableXXXXXX注解的,以及该如何优雅得实现自己得starter?有描述。注意,通过@Component是注册到内部的beanFactory,在执行的时候会执行beanFactory里面的beanFactoryPostProcessor。 lifecycleProcessor:ApplicationContext生命周期的Hook。 messageSource:用于解析消息的策略接口,支持这些消息的参数化和国际化。 applicationListeners :Spring自带EventBus的监听器。 webServer:服务器抽象,这里就是对Tomcat服务器的抽象。 ServletContext :servlet定义中Application作用域指的就是这个。他是对servlet应用的抽象。 resourceLoader:加载资源,它是对一类资源的加载策略,如jar,如classpath下里面的file,在Spring中资源是一个统一的接口Resource。

使用:

java
//BeanDefinitionRegistryPostProcessor
@Component
public class TestBeanDefinitionRegistryPostProcessor implements BeanDefinitionRegistryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("---------postProcessBeanFactory----------");
	}

	@Override
	public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
		System.out.println("---------postProcessBeanDefinitionRegistry----------");
		registry.registerBeanDefinition("testBeanFactoryPostProcessor", BeanDefinitionBuilder.genericBeanDefinition(TestBeanFactoryPostProcessor.class).getBeanDefinition());
	}

}
//BeanFactoryPostProcessor ,他是通过上面那个BeanDefinitionRegistryPostProcessor注册的
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("-------------TestBeanFactoryPostProcessor--------------");
	}

}
//自定义事件
public class TestEvent extends ApplicationEvent {
	/**
	 * 
	 */
	private static final long serialVersionUID = 5999682579759600650L;

	public TestEvent(String message) {
		super(message);
	}	
}
//自定义事件监听器。会注册到ApplicationContext的applicationListeners
@Component
public class TestListener implements ApplicationListener<TestEvent> {

	@Override
	public void onApplicationEvent(TestEvent event) {
		System.out.println("====================="+event.getSource()+"---------------------------");
	}

}
/**你无法覆盖默认实现,也不推荐你覆盖,只能像这样添加一个实现。它可以在容器生命周期被回调,isRunning返回false才会回调start()。基本上就只是做一些资源回收工作,但是这一般都是教给bean的preDestroy方法处理。*/
@Component
public class TestLifecycle implements SmartLifecycle,ApplicationContextAware {
	private ApplicationContext applicationContext;
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
		this.applicationContext = applicationContext;
	}
	@Override
	public void start() {
		System.out.println("---------------start---------------");
	}

	@Override
	public void stop() {
		System.out.println("---------------stop---------------");
	}

	@Override
	public boolean isRunning() {
		System.out.println("---------------isRunning---------------");
		return true;
	}
}
//注入这些工具以使用
@Component
public class TestClass implements ServletContextAware,ResourceLoaderAware,MessageSourceAware{
	@Autowired
	private ApplicationEventPublisher applicationEventPublisher;
	private ServletContext servletContext;
	private ResourceLoader resourceLoader;
	private MessageSource messageSource;
	@Autowired
	private AnnotationConfigServletWebServerApplicationContext applicationContext;
	
	public void doSomething(){
		System.out.println("----------TestClass doSomething----------");
	}
	public void doEvent() {
		applicationContext.getWebServer();
		applicationEventPublisher.publishEvent(new TestEvent("hello world!!!"));
	}
	@Override
	public void setServletContext(ServletContext servletContext) {
		this.servletContext = servletContext;
	}
	@Override
	public void setResourceLoader(ResourceLoader resourceLoader) {
		this.resourceLoader = resourceLoader;
	}
	@Override
	public void setMessageSource(MessageSource messageSource) {
		String msg = messageSource.getMessage("aaa.a", null,Locale.getDefault());
		this.messageSource = messageSource;
	}
}
//启动并验证
@SpringBootApplication
public class DemoApplication {

	public static void main(String[] args) {
		
		ConfigurableApplicationContext app = SpringApplication.run(DemoApplication.class, args);
		
		TestClass c = app.getBean(TestClass.class);
		c.doEvent();
		c.doSomething();
		app.stop();
	}

}

注:GenericApplicationContext的特殊之处是beanFactory是不会变化的,而AbstractRefreshableApplicationContext派生出来的ApplicationContext每次refresh()都创建一个新的beanFactory,并且重新加载与注册BeanDefinition。他们都是使用DefaultListableBeanFactory的。 注:在Spring中,一切都是bean,你基本上可以使用将所有的比如:ApplicationEventPublisher、ApplicationContext、Environment、MessageSource、ResourceLoader、BeanFactory等等等等一大堆注入到你的bean里面,只要他们的生命周期与上述不冲突。 注:上面虽然说可以注入到自定义bean,但是我们依然应该优先实现XXXXXAware接口用以感知这些实例,并且XXXXXAware接口可以感知到一些无法自动注入的依赖,比如:ClassLoader等等。 :建议自己注入一个MessageSourece,Springboot自己的message不支持自定义位置。

java
@Configuration
public class MessageConfig {
	@Bean
	public MessageSource messageSource() {
		ReloadableResourceBundleMessageSource bundleMessageSource= new ReloadableResourceBundleMessageSource();
		bundleMessageSource.setBasename("classpath:/messages/messages");
		return bundleMessageSource;
	}
}

注:建议优先使用Spring的扩展点增强Spring应用而非自己修改官方的框架,这点非常重要。最重要的俩个扩展点是BeanFactoryPostProcessor与BeanPostProcessor。

3.容器生命周期 SpringIOC容器的生命周期使用了模板模式,AbstractApplicationContext提供了基础实现,最重要的时里面的refresh()方法。当然前期依然有一些环境准备、配置准备工作需要完成(Springboot的servlet web为例):

  • 1.创建SpringApplication
java
public SpringApplication(ResourceLoader resourceLoader, Class<?>... primarySources) {
    //这里为空
    this.resourceLoader = resourceLoader;
    //推断应用类型:NONE、SERVLET、REACTIVE
    this.webApplicationType = WebApplicationType.deduceFromClasspath();

    //这三步都是使用SpringFactoriesLoader从META-INF/spring.factories配置中加载配置的类,并构造出对象
    this.bootstrappers = new ArrayList<>(getSpringFactoriesInstances(Bootstrapper.class));
    setInitializers((Collection) getSpringFactoriesInstances(ApplicationContextInitializer.class));
    setListeners((Collection) getSpringFactoriesInstances(ApplicationListener.class));

    //推断运行的main类,因为你可以传入多个Class对象,并且你必须传入当前运行main()的Class对象
    this.mainApplicationClass = deduceMainApplicationClass();
}

注:第一步中SpringFactoriesLoader从META-INF/spring.factories配置中找到需要配置的类在SpringBoot应用中非常常见,典型的应用时@EnableAutoConfiguration。也算是重要的扩展,不过绝大多数时候你都不需要在这一步就添加自己的自定义逻辑,同时,因为前期的配置可能是依赖实现的,它也许并没有我们想象地那么方便扩展:

java
//这是对SpringBoot应用的监听器,你可以使用它监听这个应用的整个生命周期,但是必须想下面那样提供构造方法
//因为框架自带的EventPublishingRunListener是这么实现的,而它依赖这个实现。
public class TestSpringApplicationRunListener implements SpringApplicationRunListener {

	private final SpringApplication application;

	private final String[] args;

	private final SimpleApplicationEventMulticaster initialMulticaster;

	public TestSpringApplicationRunListener(SpringApplication application, String[] args) {
		this.application = application;
		this.args = args;
		this.initialMulticaster = new SimpleApplicationEventMulticaster();
		for (ApplicationListener<?> listener : application.getListeners()) {
			this.initialMulticaster.addApplicationListener(listener);
		}
	}
	
	@Override
	public void starting(ConfigurableBootstrapContext bootstrapContext) {
		System.out.println("--------TestSpringApplicationRunListener starting-----------");
		SpringApplicationRunListener.super.starting(bootstrapContext);
	}
}
//META-INF/spring.factories加入配置就可以了,和自定义Starter一样的逻辑。
//使用SpringFactoriesLoader的都可以在spring.factories配置文件中添加自己的类。
org.springframework.boot.SpringApplicationRunListener=\
com.example.demo.test.TestSpringApplicationRunListener
  • 2.调用SpringApplication对象的run()方法准备并启动ApplicationContext:
java
public ConfigurableApplicationContext run(String... args) {
    //停表,用以在开发是计算各步骤启动时间
    StopWatch stopWatch = new StopWatch();
    stopWatch.start();
    //在多个ApplicationContext需要互通的时候可能会用到,不过绝大多时候用不上的。
    DefaultBootstrapContext bootstrapContext = createBootstrapContext();
    ConfigurableApplicationContext context = null;
    //设置java.awt.headless property
    configureHeadlessProperty();
    //发布starting事件
    SpringApplicationRunListeners listeners = getRunListeners(args);
    listeners.starting(bootstrapContext, this.mainApplicationClass);
    try {
        //main参数对象
        ApplicationArguments applicationArguments = new DefaultApplicationArguments(args);
        //准备环境,不同的应用类型其环境实现是不一样的,见getOrCreateEnvironment()
        ConfigurableEnvironment environment = prepareEnvironment(listeners, bootstrapContext, applicationArguments);
        //从根据ConfigurableEnvironment环境对象配置设置spring.beaninfo.ignore
        configureIgnoreBeanInfo(environment);
        /* 就是这个东西,没什么用
 .   ____          _            __ _ _
 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )
  '  |____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot ::                (v2.4.4)
        */
        Banner printedBanner = printBanner(environment);
        //根据应用类型创建ApplicationContext,这一步DefaultListableBeanFactory会准备好
        context = createApplicationContext();
        //在应用程序启动期间使用 ApplicationStartup 来标记步骤,并收集有关执行上下文或其处理时间的数据。                   
        context.setApplicationStartup(this.applicationStartup);
        //为refresh()做准备,包括一些事件发布,将属性与配置设置到ApplicationContext,一些日志等等等等一大堆。
        prepareContext(bootstrapContext, context, environment, listeners, applicationArguments, printedBanner);
        //关键一步,本质是调用refresh()方法,下面会说到,另外它注册了一个ShutdownHook到当前jvm。
        refreshContext(context);
        //空的,没做任何事
        afterRefresh(context, applicationArguments);
        stopWatch.stop();
        //后面是一堆事件,回调,日志,启动失败处理等等。
    return context;
}
  • 3.refresh()刷新ApplicationContext。这是一个模板方法,实现在AbstractApplicationContext,子类需要覆盖onRefresh()实现自己的逻辑。
java
public void refresh() throws BeansException, IllegalStateException {
    synchronized (this.startupShutdownMonitor) {
        //前文提到的步骤记录器
        StartupStep contextRefresh = this.applicationStartup.start("spring.context.refresh");
        //记录开始时间,容器状态,设置property,添加早期ApplicationListeners
        prepareRefresh();
        // beanFactory设置SerializationId,校验refresh状态。GenericApplicationContext是不支持多次refresh()的。
        ConfigurableListableBeanFactory beanFactory = obtainFreshBeanFactory();
        //配置内部使用的beanFactory的标准上下文特性,如ClassLoader和BeanFactoryPostProcessor
        //还有一些默认的environment bean,加载时织入配置等等等等。
        prepareBeanFactory(beanFactory);
        try {
            //添加了一些特殊的BeanPostProcessor,并且Web相关的Scope是在这一步注册的。
            postProcessBeanFactory(beanFactory);
            //略
            StartupStep beanPostProcess = this.applicationStartup.start("spring.context.beans.post-process");
            //注册并执行BeanFactoryPostProcessor。
            //是委托给PostProcessorRegistrationDelegate.invokeBeanFactoryPostProcessors()实现的(是一个静态方法)。
            //先执行BeanDefinitionRegistryPostProcessor,后找出BeanFactoryPostProcessor并执行,之后会在找一遍BeanFactoryPostProcessor再执行一遍。
            //这是为了防止BeanDefinitionRegistryPostProcessor注册了BeanFactoryPostProcessor没被执行到。
            invokeBeanFactoryPostProcessors(beanFactory);
            // 注册beanPostProcessor到容器,委托给PostProcessorRegistrationDelegate.registerBeanPostProcessors()
            registerBeanPostProcessors(beanFactory);
            //略
            beanPostProcess.end();
            // 初始化messageSource将我们自定义的messageSource设置为默认的messageSource的父messageSource。
            //messageSource在获取message的时候会新使用父类方法。类似双亲委派模型。
	    initMessageSource();
            //初始化applicationEventMulticaster(应用事件多播器)。
            //如果没有自定义ApplicationEventMulticaster那么会使用SimpleApplicationEventMulticaster,会将其注册到容器。
	    initApplicationEventMulticaster();
            //初始化其他特殊的bean,由子类实现,Tomcat与ServletContex的创建与初始化就是在这一步完成的。
            //这一步之后基本上所有的单例bean都已经在容器里面了。
            onRefresh();
            //扫描容器内的ApplicationListener并注册到ApplicationEventMulticaster,早期事件将在这一步被广播到早期ApplicationListener。
            registerListeners();
            // 初始化所有的非懒加载的单例bean,典型的有实现LoadTimeWeaverAware接口的bean
            finishBeanFactoryInitialization(beanFactory);
            //清除缓存:如ASM多次加载的类;
            //初始化lifecycleProcessor,如果容器中有了则copy到ApplicationContext,如果没有则使用默认的;
            //发布onRefresh事件
            finishRefresh();
        }catch (BeansException ex) {
            //一堆失败逻辑,清bean,缓存,重设ApplicationContext状态,发布事件。
	}
    }
}

注:为什么以SpringBoot开始?因为目前Java服务端的体系过于复杂,假如从ClassPathXmlApplicationContext开始讲那就是脱离生活了。毕竟理论上目前都应该使用SpringBoot开始我们的应用。

4.Bean生命周期 Spring对一个bean的生命周期做了hook,这使得我们很方便控制它。首先一个bean是先作为一个BeanDefinition注册到容器里面的,在BeanPostProcessor里面可以对bean进行处理,此时bean实例未被注入容器,且未被使用,BeanPostProcessor如下:

java
@Component
public TestBeanPostProcessor implements BeanPostProcessor {
    //初始化后处理
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(bean);
        System.out.println(beanName);
        return BeanPostProcessor.super.postProcessAfterInitialization(bean, beanName);
    }
    //初始化前处理,此时afterPropertiesSet与init-method并被执行,但是其依赖关系已经完成,代理可能已经完成。
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(bean);
        System.out.println(beanName);
        return BeanPostProcessor.super.postProcessBeforeInitialization(bean, beanName);
    }
}

初始化方法与销毁前调用,实现如下:

java
@Component
public class TestClass2 {
	@PostConstruct
	public void init() {
		System.out.println("----------init-----------");
	}
	@PreDestroy
	public void destroy() {
		System.out.println("----------destroy-----------");
	}
}

还有一大堆hook,这里总结一个bean的完整调用顺序为:全套初始化方法及其标准顺序为:

  • 1.BeanNameAware的setBeanName
  • 2.BeanClassLoaderAware的setBeanClassLoader。
  • 3.BeanFactoryAware的setBeanFactory
  • 4.EnvironmentAware 的 setEnvironment
  • 5.EmbeddedValueResolverAware的settingEmbeddedValueResolver
  • 6.ResourceLoaderAware的setResourceLoader(只适用于在应用程序上下文中运行时)
  • 7.ApplicationEventPublisherAware的setApplicationEventPublisher(只适用于在应用程序上下文中运行时)
  • 8.MessageSourceAware的setMessageSource(只适用于在应用程序上下文中运行时)
  • 9.ApplicationContextAware的setApplicationContext(只适用于在应用上下文中运行时)
  • 10.ServletContextAware的setServletContext(仅适用于在Web应用上下文中运行时)
  • 11.BeanPostProcessor的postProcessBeforeInitialization方法。
  • 12.初始化Bean的afterPropertiesSet
  • 13.自定义init-method定义,@PostConstruct
  • 14.BeanPostProcessor方法的postProcessAfterInitialization方法。 销毁调用顺序为:
  • 1.DestructionAwareBeanPostProcessors的postProcessBeforeDestruction方法。
  • 2.DisposableBean的 destroy
  • 3.自定义销毁方法定义,@PreDestroy

5.总结 SpringIOC一般指的是SpringIOC容器,在Spring中IOC容器的功能是委托给DefaultListableBeanFactory实例去处理的,官方定义的容器是ApplicationContext,之所以这么定义是因为我们实际使用的都是ApplicationContext并且ApplicationContext增强了BeanFactory的功能,它更加符合实际生产需要。总的来说,SpringIOC容器会先加载配置扫描并注册BeanDefinition,可以交给BeanFactoryPostProcessor注册,这个过程中也可以处理BeanFactory,之后调用getBean()时会实例化bean,这个过程会调用BeanPostProcessor处理bean,AOP就是在这步实现的,如果这个bean时单例的那它将会缓存到map里面;这在个过程中会产生各种各样的事件与回调。

注:可以看到,上面的绝大部分知识在生产实践中是无用的,但是你必须得会,原因是其他人知道这些知识。 注:Spring源码的质量很高,但是确实它绕来绕去不适合阅读,具体实现需要你自己回头直接查看源码,但是我个人不推荐,我个人认为项目实践中最大的问题是合作与方案的问题而不是技术的问题注:转载请标明出处与作者,有意见或者建议请评论留言。

实践、认识、再实践、再认识,这种形式,循环往复以至无穷,而实践和认识之每一循环的内容,都比较地进到了高一级的程度。