1.前言

        在工作的开发中我们常使用spring来进行对象生命周期的管理,因为对象生命周期的管理是一件烦琐的事情,当你的对象越多,这个问题就越显得明显,负责初始化销毁就很让人头疼,所以我们把这些繁琐的工作交给spring管理,spring容器在初始化是会对所有管理的对象进行初始化,管理这些bean是否是无状态的、多例的,这样我们开发的工作量就大大减少了。我们来探索下Spring是如何初始化一个对象的呢。

2.本篇文章涉及到的几个接口

BeanPostProcessor:
public interface BeanPostProcessor {
    @Nullable
    default Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Nullable
    default Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }
}

        这个接口实现了两个方法,分别在bean初始化前和初始化后执行,参数中的bean就是回调这个方法的对象,参数中的beanName就是回调这个方法的对象的beanName,这两个方法这两个方法针对spring管理的所有bean都生效,每个bean初始化前后都会对实现了这个接口放类进行方法的回调。再者需要注意这两个方法的返回值都不能为空 如果为空下面的回调都不会进行,并且有可能抛出NullPointerException。方法的返回值会把返回的对象放入调用这个方法的类中,所以用户可以对bean进行修改,封装修改属于自己的bean。

        下面是Spring初始化时候的源码部分

Protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged(new PrivilegedAction<Object>() {
				@Override
				public Object run() {
					invokeAwareMethods(beanName, bean);
					return null;
				}
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}

		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}

		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
		return wrappedBean;
	}

        spring初始化时候先执行所有实现的Aware接口的方法invokeAwareMethods(beanName, bean);,如(BeanFactoryAware,ApplicationContextAware,BeanNameAware),然后执行BeanPostProcessor接口的postProcessBeforeInitialization方法,见源码applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);postProcessBeforeInitialization方法返回的bean在这里被接收到后进行后续的回调,这里可以看出接口方法的返回值是用来干嘛的了。然后执行bean的初始化方法,定义在InitializingBean接口中的初始化方法,见源码invokeInitMethods(beanName, wrappedBean, mbd);这里已经是初始化后的bean了,然后会接着执行回调。回调BeanPostProcessor 接口的初始化后置方法,依然得到一个用户定制修改后的bean,最后return wrappedBean;会将经过初始化和修改后的bean放回容器托管。

InitializingBean:
public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}
DisposableBean:
public interface DisposableBean {
    void destroy() throws Exception;
}

        这两个接口分别只实现了一个方法,一个在bean初始化时触发,一个在bean销毁时触发,这两个接口不是针对所有被spring托管的对象,这两个接口只对实现了这两个接口的类生效,在他们初始化和销毁时调用接口的方法。可自定义实现,用于申请或者回收资源居多,

        在上面springbean初始化执行流程invokeInitMethods(beanName, wrappedBean, mbd);时调用,这两个方法还可以通过使用注解的方式进行指定@Bean(initMethod = "afterPropertiesSet")或者@Bean(destroyMethod = "destroy")

BeanNameAware:
public interface BeanNameAware extends Aware {
    void setBeanName(String var1);
}
BeanFactoryAware:
public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory var1) throws BeansException;
}
ApplicationContextAware:
public interface ApplicationContextAware extends Aware {
    void setApplicationContext(ApplicationContext var1) throws BeansException;
}

        这三个都是Aware接口的子接口,都是为了让bean感知到自己的beanFactory、beanName等,在初始化时第一个执行。用于给bean的属性赋值。在上面springbean初始化执行流程invokeAwareMethods(beanName, bean);执行该系列接口的方法实现。

        注意:scope为prototype的bean,容器会将创建好的对象实例返回给请求方,之后,容器就不再拥有其引用,请求方需要自己负责当前对象后继生命周期的管理工作,包括该对象的销毁。所以scope为singleton的bean的destroy方法则是在容器关闭时执行,而scope为prototype的bean是不会执行destroy方法的。

Bean在实例化的过程中:Constructor > @PostConstruct >InitializingBean > init-method

Bean在销毁的过程中:@PreDestroy > DisposableBean > destroy-method

 

3.编写代码验证

        FactoryBean实现类

package com.corgi.demo.demo_one.model;


import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.factory.FactoryBean;
/*
* 实现FactoryBean需要实现的三个方法  泛型中写实现这个接口的类名
* corgi
* 二〇一八年三月十七日 16:17:30
* */
@AllArgsConstructor
@Data
public class Car implements FactoryBean<Car>{
    private String speed;
    private String name;
    /*
    * 对应从上下文中获取bean时候返回对象的方法,
    * */
    @Override
    public Car getObject() throws Exception {
        return new Car("20Km\\1H","道奇挑战者");
    }
    /*
    * 方法返回该类的运行时类
    * */
    @Override
    public Class<?> getObjectType() {
        return Car.class;
    }
    /*
    *  对应该类在Spring工厂中是否生命状态是否为单例模式
    * */
    @Override
    public boolean isSingleton() {
        return true;
    }

    public Car() {
    }
}

        验证初始化顺序测试类

package com.corgi.demo.demo_one.model;

import lombok.AllArgsConstructor;
import lombok.Data;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.*;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/*
* 验证Spring在装载类时加载顺序 生命周期
* corgi
* 二〇一八年三月十七日 16:20:35
* */
@Data
public class Cat implements BeanPostProcessor,InitializingBean,DisposableBean,BeanNameAware,BeanFactoryAware,ApplicationContextAware{
    private String beanName;
    private ApplicationContext context;
    private BeanFactory beanFactory;
    /*
    * bean加载时触发这个方法让类感知到自己的工厂对象
    * */
    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
    /*
    * bean加载时触发这个方法让类感知到自己在工厂中的ID 也就是beanName;
    * */
    @Override
    public void setBeanName(String beanName) {
        this.beanName = beanName;
    }
 /*
    * 一般用于bean销毁时触发该方法进行资源的回首  可通过@Bean指定
    * */
    @Override
    public void destroy() throws Exception {
        System.out.println("触发了DisposableBean接口的destroy方法 对象被销毁了");
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("触发了InitializingBean接口的afterPropertiesSet方法");
    }
    /*
    * 用于得到spring上下文对象
    * */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("触发了ApplicationContextAware接口的setApplicationContext方法");
        this.context = applicationContext;
    }
    /*
    * bean初始化后触发的方法
    * */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName+"触发了beanPostProcessor接口的postProcessBeforeInitialization方法");
        return bean;
    }
    /*
    * bean预初始化方法
    * */
    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println(beanName+"触发了beanPostProcessor接口的postProcessAfterInitialization方法");
        return bean;
    }

    public void init(){

    }
}

        Spring-boot配置类:

package com.corgi.demo.demo_one.config;

import com.corgi.demo.demo_one.model.Car;
import com.corgi.demo.demo_one.model.Cat;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/*
* Spring配置类
* corgi
* 二〇一八年三月十七日 19:42:09
* */
@Configuration
public class SpringConfig {
    /*
    * 创建一个FactoryBean
    * */
    @Bean
    public Car car(){
        return new Car();
    }
    /*
    * 测试SpringBean的生命周期
    * */
    //@Bean(initMethod = "afterPropertiesSet")
    //@Bean(destroyMethod = "destroy")
    @Bean//默认单例
    public Cat cat(){
        return new Cat();
    }
}

        Spring-boot入口方法,测试代码

package com.corgi.demo.demo_one;

import com.corgi.demo.demo_one.model.Car;
import com.corgi.demo.demo_one.model.Cat;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.ComponentScan;
/*
* Springboot入口
* corgi
* 二〇一八年三月十七日 19:42:34
* */
@SpringBootApplication
@ComponentScan
public class DemoOneApplication{
	@Autowired
	private ApplicationContext context;

	public static void main(String[] args) {
		//得到上下文
		ConfigurableApplicationContext context = SpringApplication.run(DemoOneApplication.class, args);
		//验证factoryBean是否为单例
		Car car1 = context.getBean(Car.class);
		Car car2 = context.getBean(Car.class);
		System.out.println(car1 == car2);
		//验证factoryBean的运行时类
		Class<?> car = context.getType("car");
		Cat cat = context.getBean(Cat.class);
		context.close();
	}

	/*@Override
	public void run(String... args) throws Exception {
		Car car = context.getBean(Car.class);
		Cat cat = context.getBean(Cat.class);

	}*/
}

4.验证结果

        这里验证结果说下实际程序中接口方法的初始化调用顺序

在bean初始化的时候首先调用Aware系列的子接口何其对应的实现方法,BeanNameAware接口方法--->BeanFactoryAware接口方法--->ApplicationContextAware接口方法--->InitializingBean接口方法--->初始化完毕--->所有的bean依次执行beanPostProcessor接口的before和after方法每个bean成对执行这两个方法。---->上下文关闭context.close();---->DisposableBean接口方法。

        下面贴出测试代码运行的控制台打印结果:

Connected to the target VM, address: '127.0.0.1:55067', transport: 'socket'

  .   ____          _            __ _ _

 /\\ / ___'_ __ _ _(_)_ __  __ _ \ \ \ \

( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \

 \\/  ___)| |_)| | | | | || (_| |  ) ) ) )

  '  |____| .__|_| |_|_| |_\__, | / / / /

 =========|_|==============|___/=/_/_/_/

 :: Spring Boot ::        (v2.0.0.RELEASE)

2018-03-17 20:18:26.719  INFO 25732 --- [           main] c.c.demo.demo_one.DemoOneApplication     : Starting DemoOneApplication on DESKTOP-DJBBJ5S with PID 25732 (G:\dev_work_space\demo_1\target\classes started by Alienware in G:\dev_work_space\demo_1)

2018-03-17 20:18:26.722  INFO 25732 --- [           main] c.c.demo.demo_one.DemoOneApplication     : No active profile set, falling back to default profiles: default//根据启用的profile判断那些bean会被创建

2018-03-17 20:18:26.768  INFO 25732 --- [           main] ConfigServletWebServerApplicationContext : Refreshing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6853425f: startup date [Sat Mar 17 20:18:26 CST 2018]; root of context hierarchy

2018-03-17 20:18:27.373  INFO 25732 --- [           main] trationDelegate$BeanPostProcessorChecker : Bean 'springConfig' of type [com.corgi.demo.demo_one.config.SpringConfig$$EnhancerBySpringCGLIB$$db033f38] is not eligible for getting processed by all BeanPostProcessors (for example: not eligible for auto-proxying)

触发了BeanNameAware接口的setBeanName方法 对象被销毁了

触发了BeanFactoryAware接口的setBeanFactory方法

触发了ApplicationContextAware接口的setApplicationContext方法

触发了InitializingBean接口的afterPropertiesSet方法

org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat触发了beanPostProcessor接口的postProcessBeforeInitialization方法

org.springframework.boot.autoconfigure.web.servlet.ServletWebServerFactoryConfiguration$EmbeddedTomcat触发了beanPostProcessor接口的postProcessAfterInitialization方法

//////此处省略一万行相似的Spring组建调用beanPostProcessor接口

car触发了beanPostProcessor接口的postProcessBeforeInitialization方法

car触发了beanPostProcessor接口的postProcessAfterInitialization方法

/////这里不清楚这次调用是如何产生的本来应该是成对出现的方法只出现了一次

car触发了beanPostProcessor接口的postProcessAfterInitialization方法

true

2018-03-17 20:27:08.868  INFO 25732 --- [           main] ConfigServletWebServerApplicationContext : Closing org.springframework.boot.web.servlet.context.AnnotationConfigServletWebServerApplicationContext@6853425f: startup date [Sat Mar 17 20:18:26 CST 2018]; root of context hierarchy

2018-03-17 20:27:08.871  INFO 25732 --- [           main] o.s.j.e.a.AnnotationMBeanExporter        : Unregistering JMX-exposed beans on shutdown

触发了DisposableBean接口的destroy方法 对象被销毁了

Disconnected from the target VM, address: '127.0.0.1:55067', transport: 'socket'

Process finished with exit code 0

5.验证日志中出现的单次接口调用

        根据DEBUG观察源码

protected Object getObjectFromFactoryBean(FactoryBean<?> factory, String beanName, boolean shouldPostProcess) {
        if (factory.isSingleton() && this.containsSingleton(beanName)) {
            synchronized(this.getSingletonMutex()) {
                Object object = this.factoryBeanObjectCache.get(beanName);
                if (object == null) {
                    object = this.doGetObjectFromFactoryBean(factory, beanName);//从工厂中得到Bean
                    Object alreadyThere = this.factoryBeanObjectCache.get(beanName);
//从工厂缓存中得到Bean
                    if (alreadyThere != null) {
//如果是从缓存中得到的就说明已经执行过beanPostProcessor接口
//的postProcessAfterInitialization方法就不会调用了
                        object = alreadyThere;
                    } else {
                        if (shouldPostProcess) {
                            try {
//调用beanPostProcessor接口的postProcessAfterInitialization方法处理bean
                                object = this.postProcessObjectFromFactoryBean(object, beanName);
                            } catch (Throwable var9) {
                                throw new BeanCreationException(beanName, "Post-processing of FactoryBean's singleton object failed", var9);
                            }
                        }
//把得到的对象放入FactoryBean缓存
                        this.factoryBeanObjectCache.put(beanName, object);
                    }
                }

                return object;
            }
        } else {
            Object object = this.doGetObjectFromFactoryBean(factory, beanName);
            if (shouldPostProcess) {
                try {
                    object = this.postProcessObjectFromFactoryBean(object, beanName);
                } catch (Throwable var11) {
                    throw new BeanCreationException(beanName, "Post-processing of FactoryBean's object failed", var11);
                }
            }

            return object;
        }
    }