【mini-spring】第一章 IOC与Bean源码及思路解析

GitHub链接:mini-spring
本文仅作学习用,所出现【源码】内容皆为mini-spring中源码。

基本知识

了解IOC和Bean,了解SpringMVC。

源码分析

归根到底,这部分实际上是在逐步的分析bean的生命周期。通过一点一点增加功能和使用单元测试来学习bean生命周期的每一部分。如果你理解了bean的生命周期,简单来说:定义(bean以及对应的IOC容器)-实例化-初始化-使用-销毁,那你就可以理解为什么说IOC是Spring的核心功能:IOC将繁杂的生命周期过程逐步拆解,程序员只需要关注每个部分中需要自定义的内容,将自定义的内容写好,spring会将全部的功能拼接在一起,让你在实际开发中省去大量的时间。 非常建议反复查看源码和自己举例理解。

bean的实例化

Spring中的bean的是使用BeanFactory来产生的,也就是使用工厂类来同一创建。因此对于Bean的内容和创建过程,自然而然有以下几点:

  1. BeanFactory要怎么实现?或者说创建一个Bean需要什么内容?
  2. 创建的流程是怎样的?

这里要说明的是,应用Java复杂的继承和实现机制,最终使用的 BeanFactory 实际是DefaultListableBeanFactory。项目ioc包下有一个测试类如下:

public class BeanDefinitionAndBeanDefinitionRegistryTest {

	@Test
	public void testBeanFactory() throws Exception {
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		BeanDefinition beanDefinition = new BeanDefinition(HelloService.class);
		beanFactory.registerBeanDefinition("helloService", beanDefinition);

		HelloService helloService = (HelloService) beanFactory.getBean("helloService");
		helloService.sayHello(); // 输出为 hello
	}
}
// 对应的hello类
class HelloService {
	public String sayHello() {
		System.out.println("hello");
		return "hello";
	}
}

代码并不复杂,我们分析一下。流程如下

  1. 创建 BeanFactory:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

这一行代码创建了一个 DefaultListableBeanFactory 对象,用于管理 Bean 的生命周期和依赖注入。

  1. 创建 BeanDefinition:
BeanDefinition beanDefinition = new BeanDefinition(HelloService.class); // 使用反射

这一行代码创建了一个 BeanDefinition 对象,用于描述 HelloService 类的信息。BeanDefinition 中包含了 Bean 的类名、构造参数、属性值等信息。显而易见,这里使用了反射来获取信息。

  1. 注册 BeanDefinition:
beanFactory.registerBeanDefinition("helloService", beanDefinition);

// 这个注册的函数如下:
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
		implements ConfigurableListableBeanFactory, BeanDefinitionRegistry {

	private Map<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>(256);

	@Override
	public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) {
		beanDefinitionMap.put(beanName, beanDefinition);
	}
	// 后续代码暂时不需要
}

这一行代码将 HelloService 的 BeanDefinition 注册到 beanFactory 中,并指定 Bean 的名称为 “helloService”。不难看出,BeanFactroy类内部有一个ConcurrentHashMap,注册的Bean都存储到这里,而注册的过程只是put到map中。

  1. 获取 Bean:
    这里比较重要,可以多次阅读,尤其是多个方法的调用关系。这些调用关系在后面仍然会用到
HelloService helloService = (HelloService) beanFactory.getBean("helloService");
//getBean 调用后可以获取bean的实例
@Override
public Object getBean(String name) throws BeansException {
	Object sharedInstance = getSingleton(name); // 先调用这里,方法在下面。
	if (sharedInstance != null) {
		//如果是FactoryBean,从FactoryBean#getObject中创建bean 后面会讲FactoryBean。
		return getObjectForBeanInstance(sharedInstance, name);
	}
	
	// 不是的话,则使用反射获取得到BeanDefinition
	BeanDefinition beanDefinition = getBeanDefinition(name);
	Object bean = createBean(name, beanDefinition);
	return getObjectForBeanInstance(bean, name);
}
// getSingleton 可以自己看代码 源码中是多级缓存的
// 代码首先在多级缓存中查找是否存在这个bean,当然在当前的例子中缓存是什么都不存在的
// 因此最终指向的是return singletonObject的部分,也就是直接返回。
@Override
public Object getSingleton(String beanName) {
	Object singletonObject = singletonObjects.get(beanName);
	if (singletonObject == null) {
		singletonObject = earlySingletonObjects.get(beanName);
		if (singletonObject == null) {
			ObjectFactory<?> singletonFactory = singletonFactories.get(beanName);
			if (singletonFactory != null) {
				singletonObject = singletonFactory.getObject();
				//从三级缓存放进二级缓存
				earlySingletonObjects.put(beanName, singletonObject);
				singletonFactories.remove(beanName);
			}
		}
	}
	return singletonObject;
}
// 获取BeanDefinition,从BeanFactory的Map中获取
@Override
public BeanDefinition getBeanDefinition(String beanName) throws BeansException {
	BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
	if (beanDefinition == null) {
		throw new BeansException("No bean named '" + beanName + "' is defined");
	}

	return beanDefinition;
}
// createBean 如果是代理则返回代理对象,否则调用doCreateBean
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
	//如果bean需要代理,则直接返回代理对象
	Object bean = resolveBeforeInstantiation(beanName, beanDefinition);
	if (bean != null) {
		return bean;
	}

	return doCreateBean(beanName, beanDefinition);
}
// doCreateBean在后面会详细说,因为包含了实例化和postprocessor的内容,只需要知道是创建了一个Bean并且返回即可

这一行代码通过 beanFactory 的 getBean() 方法获取名称为 “helloService” 的 Bean。getBean() 方法内部会根据 BeanDefinition 创建 Bean 实例,并进行依赖注入。getBean方法会先检查是否已经创建过,即是否为单例。多级缓存会在后面解释

  1. 调用 Bean 方法:
helloService.sayHello(); // 输出hello

总结一下,通过反射,可以获取类的所有结构信息,根据这个class可以创建BeanDefinition,这一个BeanDefinition存储的就是 HelloService的beanClass。其他属性(如 initMethodName、scope、propertyValues)默认为空,需要手动设置或通过注解解析(当然源码中的scope是默认为true,因为bean都是默认单例)。

然后根据BeanDefinition注册到 BeanFactory,调用 beanFactory.registerBeanDefinition(“helloService”, beanDefinition) 方法,BeanFactory 会保存 <beanName, BeanDefinition> 的映射(如 “helloService” -> beanDefinition)。此时 BeanFactory 只是记录了配置,并未真正创建 HelloService 实例。

完成了上述的操作,就可以批量生成 Bean 实例。每次调用 beanFactory.getBean(“helloService”) 时,首先检查缓存:如果 helloService 已创建且 scope=“singleton”,直接返回实例。这样,我们就完成了Bean的实例化。注意这里是实例化,也就是创建了一个Bean对象。而后续还可以加入初始化的操作,为Bean赋值和添加内容。

从上面的过程和代码,我们可以回答上面的两个问题:Bean的创建需要使用反射获取到类信息,流程则是先获取到Definition这样的描述信息,再将其注册到BeanFactory的Map中。当我们需要创建对应的Bean,则检测是否已经注册,如果有则使用创建好的Bean即可。

当然,对于SpringMVC中,Bean可以是一个类,这很常见,例如controller层调用service层的代码,我们肯定是将service层标识为Bean(用@service),然后在controller层中调用service层的方法或者修改对应的成员变量。因此Bean可以有属性。那我们是怎么给Bean填充属性的?这里其实在BeanDefinition的构造函数中能发现:

public BeanDefinition(Class beanClass) {
		this(beanClass, null);
	}

public BeanDefinition(Class beanClass, PropertyValues propertyValues) {
	this.beanClass = beanClass;
	this.propertyValues = propertyValues != null ? propertyValues : new PropertyValues();
}

有两种构造函数,首先都需要传入beanClass,这是必要的,因为有BeanClass才能创建BeanDefinition,进而注册和创建Bean。第二种构造方法还需要传入PropertyValues,也就是属性值。这里的propertyValues是一个ArrayList,内部包含的是propertyvalue,是单独的一个类,包含了name和value两个字段。

因此测试代码如下:

@Test
	public void testPopulateBeanWithPropertyValues() throws Exception {
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		PropertyValues propertyValues = new PropertyValues();
		propertyValues.addPropertyValue(new PropertyValue("name", "derek"));
		propertyValues.addPropertyValue(new PropertyValue("age", 18));
		BeanDefinition beanDefinition = new BeanDefinition(Person.class, propertyValues);
		beanFactory.registerBeanDefinition("person", beanDefinition);

		Person person = (Person) beanFactory.getBean("person");
		System.out.println(person);
		assertThat(person.getName()).isEqualTo("derek");
		assertThat(person.getAge()).isEqualTo(18);
	}

首先还是创建factory,之后创建propertyValues(注意,这是列表),再添加两个propertyValue类型的对象。之后再获取得到BeanDefinition,并且进行注册。完成注册则可以进行Bean的实例化。这样操作就可以给Bean的属性赋值。

这种填充方式只是添加值,那如果是bean中注入bean呢?例如service层是一个bean,其中的一个方法也被声明为bean,这种情况要怎么处理?

这里需要增加一个BeanReference类,包装一个bean对另一个bean的引用。上面BeanDefinition的构造方法只有两种,因此对于Bean中有Bean的情况,我们还是使用的第二种构造方法,区别在于value的值是什么。如果value的类型是BeanReference,引用beanB,则先去实例化beanB。 由于不想增加代码的复杂度提高理解难度,暂时不支持循环依赖,后面会在高级篇中解决该问题。

有测试代码如下:

@Test
	public void testPopulateBeanWithBean() throws Exception {
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();

		//注册Car实例
		PropertyValues propertyValuesForCar = new PropertyValues();
		propertyValuesForCar.addPropertyValue(new PropertyValue("brand", "porsche"));
		BeanDefinition carBeanDefinition = new BeanDefinition(Car.class, propertyValuesForCar);
		beanFactory.registerBeanDefinition("car", carBeanDefinition);

		//注册Person实例
		PropertyValues propertyValuesForPerson = new PropertyValues();
		propertyValuesForPerson.addPropertyValue(new PropertyValue("name", "derek"));
		propertyValuesForPerson.addPropertyValue(new PropertyValue("age", 18));
		//Person实例依赖Car实例
		propertyValuesForPerson.addPropertyValue(new PropertyValue("car", new BeanReference("car")));
		BeanDefinition beanDefinition = new BeanDefinition(Person.class, propertyValuesForPerson);
		beanFactory.registerBeanDefinition("person", beanDefinition);

		Person person = (Person) beanFactory.getBean("person");
		System.out.println(person);
		assertThat(person.getName()).isEqualTo("derek");
		assertThat(person.getAge()).isEqualTo(18);
		Car car = person.getCar();
		assertThat(car).isNotNull();
		assertThat(car.getBrand()).isEqualTo("porsche");
	}

这里的操作就是先构造car的BeanDefinition,再构造person的。而person的部分除了自身的属性值之外,还有一个BeanReference类型的value,这样再声明的BeanDefinition和注册的部分就包含了car。

完成注册之后,就可以使用工厂实例化一个名为person的bean,这个bean本身的属性值,也可以通过person获取到car这个bean。类比SpringMVC的架构,controller既可以直接调用service层的属性值,也可以调用service层中被注册为bean的方法,进而再使用。

资源与资源加载器

springboot中,Resource接口是所有资源类的抽象接口,在mini-spring中是这样的:
在这里插入图片描述
有三个实现类,分别为:

  • FileSystemResource,文件系统资源的实现类
  • ClassPathResource,classpath下资源的实现类
  • UrlResource,对java.net.URL进行资源定位的实现类

而ResourceLoader接口,则是对于资源的加载器的抽象接口。在mini-spring中,默认使用DefaultResourceLoader为其实现类。有如下的测试代码。测试代码展示了怎么使用resourceLoader来进行资源的获取。

public class ResourceAndResourceLoaderTest {

	@Test
	public void testResourceLoader() throws Exception {
		DefaultResourceLoader resourceLoader = new DefaultResourceLoader();

		//加载classpath下的资源
		Resource resource = resourceLoader.getResource("classpath:hello.txt");
		InputStream inputStream = resource.getInputStream();
		String content = IoUtil.readUtf8(inputStream);
		System.out.println(content);
		assertThat(content).isEqualTo("hello world");

		//加载文件系统资源
		resource = resourceLoader.getResource("src/test/resources/hello.txt");
		assertThat(resource instanceof FileSystemResource).isTrue();
		inputStream = resource.getInputStream();
		content = IoUtil.readUtf8(inputStream);
		System.out.println(content);
		assertThat(content).isEqualTo("hello world");

		//加载url资源
		resource = resourceLoader.getResource("https://www.baidu.com");
		assertThat(resource instanceof UrlResource).isTrue();
		inputStream = resource.getInputStream();
		content = IoUtil.readUtf8(inputStream);
		System.out.println(content);
	}
}

而可以使用资源加载器进行资源的获取,就可以从xml中获取bean。虽然现在的springboot更希望用户使用注解来定义bean而不是直接在xml中定义。通过资源加载器,就可以在xml格式配置文件中声明式地定义bean的信息,资源加载器读取xml文件,解析出bean的信息,然后往容器中注册BeanDefinition。

BeanDefinitionReader是读取bean定义信息的抽象接口,XmlBeanDefinitionReader是从xml文件中读取的实现类。BeanDefinitionReader需要有获取资源的能力,且读取bean定义信息后需要往容器中注册BeanDefinition,因此BeanDefinitionReader的抽象实现类AbstractBeanDefinitionReader拥有ResourceLoader和BeanDefinitionRegistry两个属性。

测试代码如下:

public class XmlFileDefineBeanTest {

	@Test
	public void testXmlFile() throws Exception {
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");

		Person person = (Person) beanFactory.getBean("person");
		System.out.println(person);
		assertThat(person.getName()).isEqualTo("derek");
		assertThat(person.getCar().getBrand()).isEqualTo("porsche");

		Car car = (Car) beanFactory.getBean("car");
		System.out.println(car);
		assertThat(car.getBrand()).isEqualTo("porsche");
	}
}

这一段的内容仅为从xml中获取,思路就是从xml中读取资源,然后加载BeanDefinition,因此大致相同。

BeanFactoryPostProcessor和BeanPostProcessor

【BeanFactoryPostProcessor和BeanPostProcessor是spring框架中具有重量级地位的两个接口,理解了这两个接口的作用,基本就理解spring的核心原理了】

BeanFactoryPostProcessor是spring提供的容器扩展机制,允许我们在bean实例化之前修改bean的定义信息即BeanDefinition的信息。源码给出的代码如下。首先还是创建BeanFactory,然后从xml中获取beanDefinitionLoader,并且将资源加载器中的真正的definition进行提取。但和之前不同的是,我们需要在使用Definition进行实例化之前进行修改。

public class BeanFactoryProcessorAndBeanPostProcessorTest {

	@Test
	public void testBeanFactoryPostProcessor() throws Exception {
		DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
		XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
		beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");

		//在所有BeanDefintion加载完成后,但在bean实例化之前,修改BeanDefinition的属性值
		CustomBeanFactoryPostProcessor beanFactoryPostProcessor = new CustomBeanFactoryPostProcessor();
		beanFactoryPostProcessor.postProcessBeanFactory(beanFactory);

		Person person = (Person) beanFactory.getBean("person");
		System.out.println(person);
		//name属性在CustomBeanFactoryPostProcessor中被修改为ivy
		assertThat(person.getName()).isEqualTo("ivy"); // 最终执行结果的name就是ivy。
	}
}
// 对应的CustomBeanFactoryPostProcesser,在这里主动修改人名
public class CustomBeanFactoryPostProcessor implements BeanFactoryPostProcessor {

	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("CustomBeanFactoryPostProcessor#postProcessBeanFactory");
		BeanDefinition personBeanDefiniton = beanFactory.getBeanDefinition("person");
		PropertyValues propertyValues = personBeanDefiniton.getPropertyValues();
		//将person的name属性改为ivy
		propertyValues.addPropertyValue(new PropertyValue("name", "ivy"));
	}
}

你可能发现这个和给bean添加属性的操作好像类似,事实确实是这样。但是添加属性是在定义Bean的时候,也就是先准备好属性再使用BeanDefinition的构造函数进行初始化(还记得吗?有两个构造函数,一个是只有class信息,另一个还包含了PropertyValues)。但是BeanFactoryPostProcesser则是在BeanDefinition加载后进行的修改。

因此,由于【这种同样类型的操作,在不同时间进行】,我们可以联想到Bean的生命周期,这个项目关于Bean这一块的思路大致出现:最终我们需要复现出的是Bean完整的声明周期,从定义到赋值,再到初始化,最后是销毁。当然这一过程实际远比这四步要复杂。

回到正题,BeanPostProcessor也是spring提供的容器扩展机制,不同于BeanFactoryPostProcessor的是,BeanPostProcessor在bean实例化后修改bean或替换bean。BeanPostProcessor是后面实现AOP的关键。BeanPostProcessor的两个方法分别在bean执行初始化方法(后面实现)之前和之后执行。

public interface BeanPostProcessor {
	/**
	 * 在bean执行初始化方法之前执行此方法
	 */
	Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException;

	/**
	 * 在bean执行初始化方法之后执行此方法
	 */
	Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException;
}

这里的第二个测试代码如下:

@Test
public void testBeanPostProcessor() throws Exception {
	DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
	XmlBeanDefinitionReader beanDefinitionReader = new XmlBeanDefinitionReader(beanFactory);
	beanDefinitionReader.loadBeanDefinitions("classpath:spring.xml");

	//添加bean实例化后的处理器
	CustomerBeanPostProcessor customerBeanPostProcessor = new CustomerBeanPostProcessor();
	beanFactory.addBeanPostProcessor(customerBeanPostProcessor);

	Car car = (Car) beanFactory.getBean("car"); // 打断点!! 这里包含了初始化和实例化的内容
	System.out.println(car);
	//brand属性在CustomerBeanPostProcessor中被修改为lamborghini
	assertThat(car.getBrand()).isEqualTo("lamborghini");
}

这里可以ctrl+B去看源码,我们查看一下CustomerBeanPostProcessor的代码。其就是分为了两个部分,一个是BeforeInitialization,一个是AfterInitialization。这里的前置处理是将car这个Bean的属性进行修改,后置则单纯是返回这个bean,即不会进行任何的处理。也就是这里提前写好了应该在bean的实例化后,初始化之前进行的前置操作和后置操作。这里的前置和后置是相对于bean的初始化而言。

public class CustomerBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("CustomerBeanPostProcessor#postProcessBeforeInitialization, beanName: " + beanName);
		//换兰博基尼
		if ("car".equals(beanName)) {
			((Car) bean).setBrand("lamborghini");
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("CustomerBeanPostProcessor#postProcessAfterInitialization, beanName: " + beanName);
		return bean;
	}
}

然后我们针对getBean这个方法查看源码。这个方法包含了实例化和初始化的过程。实例化的过程在上面都已经有涉及(BeanDefinition的内容)。

// getBean中会调用createBean。
@Override
public Object getBean(String name) throws BeansException {
	Object sharedInstance = getSingleton(name);
	if (sharedInstance != null) {
		//如果是FactoryBean,从FactoryBean#getObject中创建bean
		return getObjectForBeanInstance(sharedInstance, name);
	}

	BeanDefinition beanDefinition = getBeanDefinition(name);
	Object bean = createBean(name, beanDefinition);
	return getObjectForBeanInstance(bean, name);
}
// 继续查看createBean:
@Override
protected Object createBean(String beanName, BeanDefinition beanDefinition) throws BeansException {
	//如果bean需要代理,则直接返回代理对象
	Object bean = resolveBeforeInstantiation(beanName, beanDefinition);
	if (bean != null) {
		return bean;
	}

	return doCreateBean(beanName, beanDefinition);
}
// 继续查看doCreateBean
protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
	Object bean;
	try {
		bean = createBeanInstance(beanDefinition);

		//为解决循环依赖问题,将实例化后的bean放进缓存中提前暴露
		if (beanDefinition.isSingleton()) {
			Object finalBean = bean;
			addSingletonFactory(beanName, new ObjectFactory<Object>() {
				@Override
				public Object getObject() throws BeansException {
					return getEarlyBeanReference(beanName, beanDefinition, finalBean);
				}
			});
		}

		//实例化bean之后执行
		boolean continueWithPropertyPopulation = applyBeanPostProcessorsAfterInstantiation(beanName, bean);
		if (!continueWithPropertyPopulation) {
			return bean;
		}
		//在设置bean属性之前,允许BeanPostProcessor修改属性值
		applyBeanPostProcessorsBeforeApplyingPropertyValues(beanName, bean, beanDefinition);
		//为bean填充属性
		applyPropertyValues(beanName, bean, beanDefinition);
		//执行bean的初始化方法和BeanPostProcessor的前置和后置处理方法
		bean = initializeBean(beanName, bean, beanDefinition);
	} catch (Exception e) {
		throw new BeansException("Instantiation of bean failed", e);
	}

	//注册有销毁方法的bean
	// 省略,此处是销毁部分

从doCreate中可以看到,这里的initialize Bean就是我们想要的初始化,这行代码之前的部分是实例化。

protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
	if (bean instanceof BeanFactoryAware) {
		((BeanFactoryAware) bean).setBeanFactory(this);
	}

	//执行BeanPostProcessor的前置处理
	Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);

	try {
		invokeInitMethods(beanName, wrappedBean, beanDefinition);
	} catch (Throwable ex) {
		throw new BeansException("Invocation of init method of bean[" + beanName + "] failed", ex);
	}

	//执行BeanPostProcessor的后置处理
	wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
	return wrappedBean;
}

而initializationBean的部分就和我们之前说的是一样的,先进行一个前置处理,然后是初始化,最后是后置处理。

注意!bean的实例化和初始化是两回事。这个概念很基础但容易混淆:实例化类似于new操作,在这里就是使用beanFactory+BeanFactoryPostProcessor进行的实例化,得到了具体的bean,但是初始化则是填充值,初始化的前后包含了这里说的前置操作和后置操作。

经过上面的学习,从bean的角度看,目前的生命周期是这样的。这一套并不完整,但是可以说明除销毁外的大多数流程。
在这里插入图片描述

读者如果比较敏感,应该可有发现上面有一些小问题,即我们是需要手动在代码中声明BeanPostProcessor,能不能将其加入到spring中自主处理呢?应用上下文ApplicationContext,是spring中较之于BeanFactory更为先进的IOC容器,ApplicationContext除了拥有BeanFactory的所有功能外,还支持特殊类型bean如上一节中的BeanFactoryPostProcessor和BeanPostProcessor的自动识别、资源加载、容器事件和监听器、国际化支持、单例bean自动初始化等。

也许有的面试题会问IOC容器有哪些,那除了之前的BeanFactory,还有就是ApplicationContext。 比较重要的功能就是BeanFactoryProcessor和BeanPostProcessor的自动识别,即不需要手动写入而是可以通过配置或者注解的方式来加入。

测试代码如下。跟之前使用BeanFactory相比,就省去了手动添加处理器的过程。

@Test
public void testApplicationContext() throws Exception {
	ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");

	Person person = applicationContext.getBean("person", Person.class);
	System.out.println("111" + person);
	//name属性在CustomBeanFactoryPostProcessor中被修改为ivy
    assertThat(person.getName()).isEqualTo("ivy");

	Car car = applicationContext.getBean("car", Car.class);
	System.out.println(car);
	//brand属性在CustomerBeanPostProcessor中被修改为lamborghini
	assertThat(car.getBrand()).isEqualTo("lamborghini");
}

关于自动装配的代码,主要看的是AbstractApplicationContext#refresh方法。这个方法也很重要,是spring容器启动和刷新的核心逻辑。通过这个方法,spring会在启动的时候自动扫描和装配Bean(除去懒加载的),然后将这些Bean实例化、初始化完成并且放到IOC容器中,等待被调用。

@Override
public void refresh() throws BeansException {
	//创建BeanFactory,并加载BeanDefinition
	refreshBeanFactory();
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();

	//添加ApplicationContextAwareProcessor,让继承自ApplicationContextAware的bean能感知bean
	beanFactory.addBeanPostProcessor(new ApplicationContextAwareProcessor(this));

	//在bean实例化之前,执行BeanFactoryPostProcessor
	invokeBeanFactoryPostProcessors(beanFactory);

	//BeanPostProcessor需要提前与其他bean实例化之前注册
	registerBeanPostProcessors(beanFactory);

	//初始化事件发布者
	initApplicationEventMulticaster();

	//注册事件监听器
	registerListeners();

	//注册类型转换器和提前实例化单例bean
	finishBeanFactoryInitialization(beanFactory);

	//发布容器刷新完成事件
	finishRefresh();
}
// 这里着重看一下finishBeanFactoryInitialization(beanFactory);
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
	//设置类型转换器
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
		Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
		if (conversionService instanceof ConversionService) {
			beanFactory.setConversionService((ConversionService) conversionService);
		}
	}

	//提前实例化单例bean
	beanFactory.preInstantiateSingletons();
}
// preInstantiateSingletons,看注释可以得知是创建一个Bean,创建要满足的条件和我上面写得一样。
@Override
public void preInstantiateSingletons() throws BeansException {
	beanDefinitionMap.forEach((beanName, beanDefinition) -> {
		//只有当bean是单例且不为懒加载才会被创建
		if (beanDefinition.isSingleton() && !beanDefinition.isLazyInit()) {
			getBean(beanName);
		}
	});
}

Bean的初始化和销毁方法

在spring中,定义bean的初始化和销毁方法有三种方法:

  • 在xml文件中制定init-method和destroy-method
  • 继承自InitializingBean和DisposableBean
  • 在方法上加注解PostConstruct和PreDestroy(在springboot中比较常用)
    第三种通过BeanPostProcessor实现,在扩展篇中实现。
第一种:在xml中制定init-method和destroy-method

这种在springboot中并不常用,主要使用的还是注解。

首先我们看一下xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	         http://www.springframework.org/schema/beans/spring-beans.xsd
		 http://www.springframework.org/schema/context
		 http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <bean id="person" class="org.springframework.test.bean.Person" init-method="customInitMethod" destroy-method="customDestroyMethod">
        <property name="name" value="derek"/>
        <property name="car" ref="car"/>
    </bean>

    <bean id="car" class="org.springframework.test.bean.Car">
        <property name="brand" value="porsche"/>
    </bean>

</beans>

然后再对应的person中声明即可。

第二种:继承InitializingBean和DisposableBean
  1. 初始化方法
    这里声明了person的bean,这个bean加入了init和destroy的方法,也就是基于这两个方法进行初始化和销毁。
public class Person implements InitializingBean, DisposableBean {

	private String name;

	private int age;

	private Car car;

	public void customInitMethod() {
		System.out.println("I was born in the method named customInitMethod");
	}

	public void customDestroyMethod() {
		System.out.println("I died in the method named customDestroyMethod");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("I was born in the method named afterPropertiesSet");
	}

	@Override
	public void destroy() throws Exception {
		System.out.println("I died in the method named destroy");
	}

    //setter and getter
}
// 测试代码:
public class InitAndDestoryMethodTest {

	@Test
	public void testInitAndDestroyMethod() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:init-and-destroy-method.xml");
		applicationContext.registerShutdownHook();  //或者手动关闭 applicationContext.close();
	}
}

这个person包含了初始化和销毁的方法。最终的输出结果为:

I was born in the method named afterPropertiesSet
I was born in the method named customInitMethod
I died in the method named destroy
I died in the method named customDestroyMethod

也就说执行顺序是先调用的afterPropertiesSet,这个方法重写了 invokeInitMethods方法,这个方法在initializeBean中被调用(还记得doCreate吗?这里调用的initializeBean,后者的作用是调用BeanPostProcessor的前置和后置方法,以及invokeInitMethods,也就是Bean的初始化方法)。所以说明afterPropertiesSet方法是在Bean初始化的时候被调用的。然后才是customInitMethod,也就是说明,Bean的InitMethod方法是在自定义的初始化方法之前执行的。下面的代码其实就是这个意思

protected void invokeInitMethods(String beanName, Object bean, BeanDefinition beanDefinition) throws Throwable {
	// 先执行InitMethod 
	if (bean instanceof InitializingBean) {
		((InitializingBean) bean).afterPropertiesSet();
	}
	// 再执行自定义的初始化方法,以反射的方式来执行
	String initMethodName = beanDefinition.getInitMethodName();
	if (StrUtil.isNotEmpty(initMethodName) && !(bean instanceof InitializingBean && "afterPropertiesSet".equals(initMethodName))) {
		Method initMethod = ClassUtil.getPublicMethod(beanDefinition.getBeanClass(), initMethodName);
		if (initMethod == null) {
			throw new BeansException("Could not find an init method named '" + initMethodName + "' on bean with name '" + beanName + "'");
		}
		initMethod.invoke(bean);
	}
}
  1. 销毁方法
    在DefaultSingletonBeanRegistry中增加属性disposableBeans保存拥有销毁方法的bean,拥有销毁方法的bean在AbstractAutowireCapableBeanFactory#registerDisposableBeanIfNecessary中注册到disposableBeans中。

也就是说,还是在refresh中会调用finishBeanFactoryInitialization,后者调用了getBean,最终会调用doCreateBean,也就会注册有销毁方法的Beans,这样就可以在JVM关闭之前通过一个单独的关闭线程将Beans都进行销毁。

这里可以看之前的doCreateBean的完整内容了。之前的内容是实例化和初始化,之后才是销毁。

protected Object doCreateBean(String beanName, BeanDefinition beanDefinition) {
// 前面是实例化和初始化
//注册有销毁方法的bean
	registerDisposableBeanIfNecessary(beanName, bean, beanDefinition);

	Object exposedObject = bean;
	if (beanDefinition.isSingleton()) {
		//如果有代理对象,此处获取代理对象
		exposedObject = getSingleton(beanName);
		addSingleton(beanName, exposedObject);
	}
	return exposedObject;
}
// 检测是否满足销毁的要求:是单例,且有销毁方法
protected void registerDisposableBeanIfNecessary(String beanName, Object bean, BeanDefinition beanDefinition) {
	//只有singleton类型bean会执行销毁方法
	if (beanDefinition.isSingleton()) {
		if (bean instanceof DisposableBean || StrUtil.isNotEmpty(beanDefinition.getDestroyMethodName())) {
			registerDisposableBean(beanName, new DisposableBeanAdapter(bean, beanName, beanDefinition));
		}
	}
}
// 其实也就是把需要销毁的Bean放到DisposableBean中,最后统一销毁。
public void registerDisposableBean(String beanName, DisposableBean bean) {
	disposableBeans.put(beanName, bean);
}

测试的代码如下。整个的调用流程是先在refresh中一路调用,调用到了doCreateBean,其中包含了将【有销毁方法】的bean注册到disposableBeans中,然后销毁的时候则会钩子函数进行销毁,销毁的对象为注册到disposableBeans中的Bean。

public class InitAndDestoryMethodTest {

	@Test
	public void testInitAndDestroyMethod() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:init-and-destroy-method.xml");
		applicationContext.registerShutdownHook();  //或者手动关闭 applicationContext.close();
	}
}
// 查看registerShutdownHook,创建一个shutdown线程执行doclose。
// 为了确保销毁方法在虚拟机关闭之前执行,向虚拟机中注册一个钩子方法。
// 当 JVM 接收到关闭信号时(例如用户按下 Ctrl+C 或操作系统发送终止信号),这个钩子线程会被执行。
// 这个线程会调用 doClose() 方法,进而发布关闭事件和销毁单例 Bean。
public void registerShutdownHook() {
	Thread shutdownHook = new Thread() {
		public void run() {
			doClose();
		}
	};
	Runtime.getRuntime().addShutdownHook(shutdownHook);

}

protected void doClose() {
	//发布容器关闭事件
	publishEvent(new ContextClosedEvent(this));

	//执行单例bean的销毁方法
	destroyBeans();
}

protected void destroyBeans() {
	getBeanFactory().destroySingletons();
}

// 销毁disposableBeans中的Beans。
public void destroySingletons() {
	ArrayList<String> beanNames = new ArrayList<>(disposableBeans.keySet());
	for (String beanName : beanNames) {
		DisposableBean disposableBean = disposableBeans.remove(beanName); // remove
		try {
			disposableBean.destroy();
		} catch (Exception e) {
			throw new BeansException("Destroy method on bean with name '" + beanName + "' threw an exception", e);
		}
	}
}

生命周期如下:
在这里插入图片描述

Aware接口

Aware是感知、意识的意思,Aware接口是标记性接口,其实现子类能感知容器相关的对象。常用的Aware接口有BeanFactoryAware和ApplicationContextAware,分别能让其实现者感知所属的BeanFactory和ApplicationContext。

有测试代码如下。这里的helloService是实现了两个接口:

public class AwareInterfaceTest {

	@Test
	public void test() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:spring.xml");
		HelloService helloService = applicationContext.getBean("helloService", HelloService.class);
		assertThat(helloService.getApplicationContext()).isNotNull();
		assertThat(helloService.getBeanFactory()).isNotNull();
	}
}
//HelloService类
public class HelloService implements ApplicationContextAware, BeanFactoryAware {
	private ApplicationContext applicationContext;
	private BeanFactory beanFactory;
	// 剩下的代码省略
}

对于BeanFactory,查看aware的部分就是从getBean一路到doCreateBean,在doCreateBean中有initializeBean的前三行就是。因此你可以得知,这部分在生命周期中是Bean的实例化之后,BeanPostProcessor之前进行的。
通过这三行代码,可以让Bean得知其BeanFactory是什么,也就可以获得对应的BeanFactory中其它Bean的内容。

protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
	if (bean instanceof BeanFactoryAware) { // 当前的bean是否是实现了BeanFactoryAware接口
		((BeanFactoryAware) bean).setBeanFactory(this); // 让创建当前bean的BeanFactory的引用给这个bean
	}

	//执行BeanPostProcessor的前置处理、初始化方法和后置处理。
}

对于ApplicationContext:是在BeanPostProcessor的前置处理中进行的。对于ApplicationContext,会在Spring运行时自动执行refresh() 方法,refresh会包含各项内容,包括实例化和BeanPostProcessor。

protected Object initializeBean(String beanName, Object bean, BeanDefinition beanDefinition) {
	// Aware
	
	//执行BeanPostProcessor的前置处理
	Object wrappedBean = applyBeanPostProcessorsBeforeInitialization(bean, beanName);
	// 初始化和后置处理
}
// 查看前置处理的代码:
// 传入的第一个参数其实就是我们要创建的Bean
@Override
public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
		throws BeansException {
	Object result = existingBean; //将传入的Bean复制一份
	for (BeanPostProcessor processor : getBeanPostProcessors()) {
	// current是增加了前置处理的bean。
		Object current = processor.postProcessBeforeInitialization(result, beanName);
		if (current == null) {
			return result;
		}
		result = current;
	}
	return result;
}
// 查看postProcessBeforeInitialization
// 如果是ApplicationContextAware接口的实现,则会将对于ApplicationContext的引用给当前的bean。最后返回bean
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
	if (bean instanceof ApplicationContextAware) {
		((ApplicationContextAware) bean).setApplicationContext(applicationContext);
	}
	return bean;
}

这个有什么用呢?
实现 Aware 接口(如 ApplicationContextAware)可以让一个普通的 bean 获得对 ApplicationContext 的访问权限,从而能够执行一些普通 bean 通常无法直接执行的操作,比如发布事件。这个后面会提到。

因此现在生命周期如下:
在这里插入图片描述

bean作用域,增加prototype的支持

测试代码如下。这里注册的xml文件的bean的scope发生了变化,这次不是单例(singleton),而是原型(prototype)。也就是说,每次都会新创建一个bean,而不是依赖于IOC容器创建一个单例。使用的时候也是,不会只在缓存中使用缓存好的单例。如果你对之前的代码比较熟,就会知道refresh阶段是只会进行BeanDefinition的注册和BeanFactoryPostProcessor的处理,不会进行实例化以及实例化之后的步骤,这需要手动进行。

public class PrototypeBeanTest {
	@Test
	public void testPrototype() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:prototype-bean.xml");

		Car car1 = applicationContext.getBean("car", Car.class);
		Car car2 = applicationContext.getBean("car", Car.class);
		assertThat(car1 != car2).isTrue(); // 可以通过,这两个不一样
	}
}
// 为了防止忘记,我再写一下
protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
//设置类型转换器
	if (beanFactory.containsBean(CONVERSION_SERVICE_BEAN_NAME)) {
		Object conversionService = beanFactory.getBean(CONVERSION_SERVICE_BEAN_NAME);
		if (conversionService instanceof ConversionService) {
			beanFactory.setConversionService((ConversionService) conversionService);
		}
	}

	//提前实例化单例bean
	beanFactory.preInstantiateSingletons();
}
//查看这个preInstantiateSingleton:
@Override
public void preInstantiateSingletons() throws BeansException {
	beanDefinitionMap.forEach((beanName, beanDefinition) -> {
		//只有当bean是单例且不为懒加载才会被创建,才会调用getbean
		if (beanDefinition.isSingleton() && !beanDefinition.isLazyInit()) {
			getBean(beanName);
		}
	});
}

而怎么判断是否为单例?会在doCreate的地方操作。先判断是否为singleton,如果是则执行addSingleton,加入到单例中。

@Override
publicvoid addSingleton(String beanName, Object singletonObject) {
	singletonObjects.put(beanName, singletonObject); // 1
	earlySingletonObjects.remove(beanName); // 2
	singletonFactories.remove(beanName); // 3
}

现在可以得到bean的生命周期如下:
在这里插入图片描述

FactoryBean

通常情况下,当你从 Spring 容器中通过 getBean(“beanName”) 获取一个 bean 时,你得到的就是名为 beanName 的那个对象本身。但是,如果你获取的 bean 实现了 FactoryBean 接口,那么默认情况下,Spring 会调用该 FactoryBean 实现类的 getObject() 方法,并将该方法返回的对象作为最终的结果给你。

有如下测试代码:

public class FactoryBeanTest {
	@Test
	public void testFactoryBean() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:factory-bean.xml");

		Car car = applicationContext.getBean("car", Car.class);
		assertThat(car.getBrand()).isEqualTo("porsche");
	}
}
// 对应的carFactoryBean 重点关注getObject方法
public class CarFactoryBean implements FactoryBean<Car> {

	private String brand;

	@Override
	public Car getObject() throws Exception {
		Car car = new Car();
		car.setBrand(brand);
		return car;
	}

	@Override
	public boolean isSingleton() {
		return true;
	}

	public void setBrand(String brand) {
		this.brand = brand;
	}
}

重点在于getBean方法。之前都只是分析从缓存获取、获取BeanDefinition,然后创建一个Bean,也包括后面的doCreate的部分(实例化、PostProcessor和初始化),并没有深究最后一句getObjectForBeanInstance。代码如下

@Override
public Object getBean(String name) throws BeansException {
	Object sharedInstance = getSingleton(name);
	if (sharedInstance != null) {
		//如果是FactoryBean,从FactoryBean#getObject中创建bean
		return getObjectForBeanInstance(sharedInstance, name);
	}

	BeanDefinition beanDefinition = getBeanDefinition(name);
	Object bean = createBean(name, beanDefinition);
	return getObjectForBeanInstance(bean, name);
}
// 查看getObjectForBeanInstance
protected Object getObjectForBeanInstance(Object beanInstance, String beanName) {
	Object object = beanInstance;
	// 首先查看是否实现了FactoryBean的接口。
	if (beanInstance instanceof FactoryBean) {
		FactoryBean factoryBean = (FactoryBean) beanInstance;
		// 如果实现了FactoryBean,则看bean的type是单例还是原型
		// 最终获得的结果就是调用getObject方法。
		try {
			if (factoryBean.isSingleton()) {
				//singleton作用域bean,从缓存中获取
				object = this.factoryBeanObjectCache.get(beanName);
				if (object == null) {
					object = factoryBean.getObject();
					this.factoryBeanObjectCache.put(beanName, object);
				}
			} else {
				//prototype作用域bean,新创建bean
				object = factoryBean.getObject();
			}
		} catch (Exception ex) {
			throw new BeansException("FactoryBean threw exception on object[" + beanName + "] creation", ex);
		}
	}

	// 因此最终返回的是factoryBean调用getObject方法后的结果。
	// 当然,如果没有实现factorybean,则返回最初创建的bean
	return object;
}

getObject的代码上面已经有了,其实就是setBrand并返回car。因此这里的FactoryBean实现的并非是返回原始的Bean,而是返回getObject的结果。

因此使用FactoryBean往往是在代理对象中,Spring AOP大量使用了FactoryBean来创建代理对象。当你配置一个切面时,Spring 实际上可能配置了一个实现了 FactoryBean 的 bean,它负责根据切面配置生成并返回代理对象。

容器事件和事件监听器

ApplicationContext容器提供了完善的事件发布和事件监听功能。而BeanFactory并不具备这个能力,所以我们下面使用的是ApplicationContext。ApplicationEventMulticaster接口是注册监听器和发布事件的抽象接口,AbstractApplicationContext包含其实现类实例作为其属性,使得ApplicationContext容器具有注册监听器和发布事件的能力。

在 Spring 中,事件监听通常涉及以下几个组件:

ApplicationEvent:Spring 中的事件基类,自定义事件通常继承这个类。
ApplicationListener:监听器的接口,任何实现了这个接口的 Bean 都可以监听特定类型的事件。
ApplicationEventMulticaster:事件多播器,负责将事件分发给所有注册的监听器。

测试代码如下:

public class EventAndEventListenerTest {

	@Test
	public void testEventListener() throws Exception {
		ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:event-and-event-listener.xml");
		applicationContext.publishEvent(new CustomEvent(applicationContext));

		applicationContext.registerShutdownHook();//或者applicationContext.close()主动关闭容器;
	}
}

其中的xml文件有三个bean:第一个是容器刷新时工作,第二个是自定义的事件监听器,第三个是容器关闭时工作。

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
	         http://www.springframework.org/schema/beans/spring-beans.xsd
		 http://www.springframework.org/schema/context
		 http://www.springframework.org/schema/context/spring-context-4.0.xsd">

    <bean class="org.springframework.test.common.event.ContextRefreshedEventListener"/>

    <bean class="org.springframework.test.common.event.CustomEventListener"/>

    <bean class="org.springframework.test.common.event.ContextClosedEventListener"/>
</beans>

在源码中,可以从refresh进入看一下事件监听器的代码:

@Override
public void refresh() throws BeansException {
	// 之前的操作...

	//初始化事件发布者
	initApplicationEventMulticaster();

	//注册事件监听器
	registerListeners();

	//注册类型转换器和提前实例化单例bean
	finishBeanFactoryInitialization(beanFactory);

	//发布容器刷新完成事件
	finishRefresh();
}
//查看initApplicationEventMulticaster,做的事情也很简单
// 获取容器,并以此为参数创建applicationEventMulicaster的实现类。
// 创建好的Bean是专门为了事件发布使用的bean,因此这个参数调用并未传入IOC容器去操作beans
protected void initApplicationEventMulticaster() {
	ConfigurableListableBeanFactory beanFactory = getBeanFactory();
	applicationEventMulticaster = new SimpleApplicationEventMulticaster(beanFactory);
	beanFactory.addSingleton(APPLICATION_EVENT_MULTICASTER_BEAN_NAME, applicationEventMulticaster);
}

提前说一下:
singletonObjects 是一级缓存,存储完全初始化好的单例 bean。
earlySingletonObjects 是二级缓存,存储早期引用(可能在 bean 完全初始化之前)。
singletonFactories 是三级缓存,存储 ObjectFactory,用于创建 bean 的代理或其他逻辑。

// 加入一级缓存,并从二三级缓存移除。
@Override
public void addSingleton(String beanName, Object singletonObject) {
	singletonObjects.put(beanName, singletonObject); // 1
	earlySingletonObjects.remove(beanName); // 2
	singletonFactories.remove(beanName); // 3
}

然后是注册,即refresh里的registerListeners(),就是将xml中的三个监听相关的bean注册。顺带一提,springboot中是使用注解。

protected void registerListeners() {
// 找到全部实现了ApplicationListener接口的bean,也就是xml中的三个
Collection<ApplicationListener> applicationListeners = getBeansOfType(ApplicationListener.class).values();
	// 对这三个beans进行循环
	for (ApplicationListener applicationListener : applicationListeners) {
		// 添加到applicationEventMulticaster
		// addApplicationListener本质也是添加到Hashset中
		applicationEventMulticaster.addApplicationListener(applicationListener);
	}
}

最后就是refresh中的finishRefresh()

protected void finishRefresh() {
	publishEvent(new ContextRefreshedEvent(this));
}
// 
@Override
public void publishEvent(ApplicationEvent event) {
	applicationEventMulticaster.multicastEvent(event);
}
//循环,把事件分发给所有感兴趣且兼容的监听器。
@Override
public void multicastEvent(ApplicationEvent event) {
	for (ApplicationListener<ApplicationEvent> applicationListener : applicationListeners) {
		if (supportsEvent(applicationListener, event)) {
			applicationListener.onApplicationEvent(event);
		}
	}
}
//进行类型匹配,看event和listener是否能匹配。
protected boolean supportsEvent(ApplicationListener<ApplicationEvent> applicationListener, ApplicationEvent event) {
	Type type = applicationListener.getClass().getGenericInterfaces()[0];
	Type actualTypeArgument = ((ParameterizedType) type).getActualTypeArguments()[0];
	String className = actualTypeArgument.getTypeName();
	Class<?> eventClassName;
	try {
		eventClassName = Class.forName(className);
	} catch (ClassNotFoundException e) {
		throw new BeansException("wrong event class name: " + className);
	}
	return eventClassName.isAssignableFrom(event.getClass());
}

总体流程就是,在refresh中,先初始化事件发布者(多播器),然后注册监听者(从xml或者注解),最后进行匹配,将事件分发给感兴趣的监听者,这样监听者就可以进行监听,等到事件发生做出相应的操作。

帮你理解的一个例子

例如有如下的代码:

// Service 层
@Service
public class MyService {
    private String serviceName;
    private int serviceVersion;

    // 1. 构造器
    public MyService() {
        System.out.println("1. MyService: 调用无参构造器,准备实例化");
    }

    // 2. Setter 方法 (用于依赖注入)
    @Autowired
    public void setServiceName(String serviceName) {
        System.out.println("2. MyService: 通过 setter 注入 serviceName = " + serviceName);
        this.serviceName = serviceName;
    }

    // 3. @PostConstruct 注解的初始化方法
    @PostConstruct
    public void init() {
        System.out.println("6. MyService: 执行 @PostConstruct 注解的初始化方法 init()");
        this.serviceVersion = 1;
    }

    // 业务方法
    public String doSomething() {
        System.out.println("9. MyService: 执行业务方法 doSomething()");
        return "Service " + serviceName + " (v" + serviceVersion + ") is working!";
    }

    // 4. @PreDestroy 注解的销毁方法
    @PreDestroy
    public void cleanup() {
        System.out.println("12. MyService: 执行 @PreDestroy 注解的销毁方法 cleanup()");
    }
}

// Controller 层
@RestController
@RequestMapping("/api")
public class MyController {

    private MyService myService; // 依赖 MyService

    // 5. 构造器注入 (推荐)
    @Autowired
    public MyController(MyService myService) {
        System.out.println("3. MyController: 调用构造器,注入 myService");
        this.myService = myService;
    }

    @GetMapping("/hello")
    public String sayHello() {
        System.out.println("8. MyController: 调用 sayHello 方法");
        // 9. 调用 Service 的方法
        String result = myService.doSomething();
        return "Controller received: " + result;
    }
}

我们结合上面所学来分析一个bean的生命周期:

  1. 程序员定义 Bean:
    你通过添加 @Service, @Controller, @Repository 等注解来标记类,告诉 Spring 你希望将这些类实例化为 Bean。你还可能使用 @Autowired 或 @Resource 等注解来声明依赖关系,或者直接在构造器/Setter 方法上使用 @Autowired 来实现依赖注入。
  2. Spring Boot 的注册和定义:
    这一部分开始和上面所学相关。
    当你的 Spring Boot 应用启动时,SpringApplication.run() 方法会被调用。内部,它会创建一个 ApplicationContext,这是 Spring 的核心容器,负责管理 Bean。容器会扫描你指定的包(通过 @SpringBootApplication 或 @ComponentScan 注解定义的 base packages)。在扫描过程中,容器会识别出带有 @Service, @Controller, @Component 等注解的类。
    而对于每个被识别的类,容器会:
    • 创建 BeanDefinition: 这是一个配置元数据对象,描述了如何创建对应的 Bean,包括类名、作用域(默认是单例 singleton)、是否是懒加载、依赖关系、初始化/销毁方法等。
    • 注册 BeanDefinition : 此时,Bean 还没有被创建,只是定义好了如何创建它。
    • 第一次调用 Bean(例如 Controller 调用 Service):
      假设一个 HTTP 请求到达,Spring MVC 框架(也是 Spring Boot 自动配置的一部分)需要处理这个请求。它会找到匹配的 @Controller 或 @RestController 处理方法。在执行这个 Controller 方法之前,Spring 需要确保 Controller 依赖的 Service Bean 是可用的。
  3. bean的实例化以及初始化:
    如果 Service Bean 还没有被创建(对于一个单例 Bean,通常在应用启动时就已经创建好了,除非它是懒加载的),那么当 Controller 被创建(或者第一次需要其依赖的 Service 时),容器就会:
    • 根据之前注册的 BeanDefinition,找到对应的 Service 类。
    • 调用 BeanFactory.getBean(“serviceName”)(或者更精确地说,是 ApplicationContext.getBean(),它内部委托给 BeanFactory)。 这个 getBean() 调用会触发 Bean 的完整创建和初始化流程。这一部分上面也有源码。
    • 实例化(调用构造器):填充属性(依赖注入,调用 Setter 方法或注入构造器参数)
    • Aware 接口回调 (如果实现):如果 MyService 实现了 BeanNameAware, ApplicationContextAware 等接口,Spring 会在这一步调用 setBeanName(), setApplicationContext() 等方法,让 Bean 获得自身在容器中的名称或容器引用。
    • 应用 BeanPostProcessor 的 postProcessBeforeInitialization
    • 调用 @PostConstruct 方法 或 InitializingBean.afterPropertiesSet() 或自定义的 init-method
      应用 BeanPostProcessor 的 postProcessAfterInitialization
    • 最后,将完全初始化好的 Service Bean 返回给 Controller。
    • 特别说明:对于单例 Bean: 通常在应用启动、容器刷新(也就是refresh方法调用的时候,上面有源码)的过程中,所有单例 Bean 就已经被创建和初始化好了。所以,在 Controller 调用 Service 时,getBean() 很可能只是从容器缓存中获取一个已经存在的 Bean 实例,而不会重新创建。 这就是单例模式的效率优势。想一想mini-spring的代码,是不是在newSingleon的时候是存在多级缓存的?
      对于原型(prototype)Bean: 每次调用 getBean() 都会创建一个新的 Bean 实例。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值