Spring Bean的注册方式以及相关属性赋值和初始化源码解析

618 阅读6分钟

注册方式

基本POJO

@Component
@Data
public class Student implements BeanNameAware {
    private Address address;
    private String name;
    private Integer age;
}

Xml注册方式

属性/构造器参数

直接在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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--属性/构造器方式-->
    <bean id="parameterAndConstructCreationBean" class="blog.spring.introduction.domain.Student">
        <property name="name" value="layzlittle"/>
        <property name="age" value="200"/>
        <constructor-arg name="address" ref="address"/>
    </bean>
    <bean id="address" class="blog.spring.introduction.domain.Address">
        <property name="addressName" value="hz"/>
    </bean>
</beans>

静态工厂/实例工厂

通过在标签中使用工厂对应标签即可,其中静态工厂需要声明一个类的静态工厂方法,而实例工厂需要引用一个工厂bean,然后指定实例工厂方法即可

    <!--静态工厂-->
    <bean id="staticFactoryCreationBean" class="blog.spring.introduction.domain.Student" factory-method="createStudent"/>

    <!--实例工厂-->
    <bean id="instantiatedFactoryCreationBean" factory-bean="instantiatedStudentFactory" factory-method="createStudent"/>
		<!--实例工厂Bean-->
    <bean id="instantiatedStudentFactory" class="blog.spring.creation.InstantiatedStudentFactory"/>
  • 静态工厂 : 在Student类下面加了一个静态方法创建Student
    public static Student createStudent(){
        return new Student();
    }
  • 实例工厂
public class InstantiatedStudentFactory {
		//工厂方法
    public Student createStudent() {
        return new Student();
    }
}

FactoryBean/ServiceLoaderFactoryBean

  • 普通FactoryBean : Spring提供FactoryBean用来创建复杂Bean , 若想获取FactoryBean本身,可以通过 & + beanName进行依赖查找
public class StudentFactoryBean implements FactoryBean<Student> {

    @Override
    public Student getObject() throws Exception {
        return new Student();
    }

    @Override
    public Class<?> getObjectType() {
        return Student.class;
    }
}

xml添加FactoryBean申明

    <!--FactoryBean-->
    <bean id="studentFactoryBean" class="blog.spring.creation.StudentFactoryBean"/>
  • ServiceLoaderFactoryBean : 通过Java提供的SPI的方式来加载相关实现类并注册到Spring容器中

可以直接在xml中指定ServiceLoaderFactoryBean,并指定相关需要加载的类型 , 然后在META-INF/services/下面创建名称为该类型的文件,里面内容为实现类的全类名,多个用不同的行来区分,比如这里,我们需要创建META-INF/services/blog.spring.introduction.domain.Student文件

    <!--ServiceLoaderFactoryBean-->
    <bean id="serviceLoaderFactoryBean" class="org.springframework.beans.factory.serviceloader.ServiceLoaderFactoryBean">
        <property name="serviceType" value="blog.spring.introduction.domain.Student"/>
    </bean>

SPI文件内容

blog.spring.introduction.domain.SportsStudent

//相关实现类
public class SportsStudent
        extends Student{

    public enum Sports {
        BASKETBALL,FOOTBALL,SWIM
    }
}

Annotation注册方式

@Component派生注解 + @ComponentScan

直接在类上标注@Component或者其派生注解(@Service,@Repository,@Controller,@Configuration..) ,支持的核心类为ClassPathScanningCandidateComponentProvider,在使用默认的配置下,会支持@Component派生,JavaEE @ManagedBean , JSR330的@Named , 我们也可以手动在@ComponentScan中添加自定义的IncludeFilters来添加自定义组件扫描

@Component
@Data
public class Student{
  
}

@ManagedBean
public class ManagedStudentBean extends Student {
}

@Named
public class NamedStudentBean extends Student{
}

@Import/ImportSelector/ImportBeanDefinitionRegistrar/DeferredImportSelector

可以使用@Import来导入相关的Configuration Class 或者ImportSelector 、 ImportBeanDefinitionRegistrar

//导入了ImportSelector /DeferredImportSelector /ImportBeanDefinitionRegsitrar
@Import({BeanCreationDemo.StudentImportSelector.class, BeanCreationDemo.StudentImportBeanDefinitionRegistrar.class, BeanCreationDemo.CustomDeferredImportSelector.class})
public class BeanCreationDemo {
  
  	//DeferredImportSelector , 会在所有的Configuration Class和ImportSelector、@ComponentScan都处理完毕之后进行回调
  	//详细可以看上一节解析ConfigurationClassPostProcessor源码解析,SpringBoot的自动化配置加载就是用的这种方式来确保自动配置需要的资源先加载完毕再开始进行自动配置的条件判断
    public static class CustomDeferredImportSelector implements DeferredImportSelector{
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            return new String[]{DeferredImportSelectStudent.class.getName()};
        }
    }
		//ImportSelector ,会将返回的String[] 中的全类名作为BeanClass注册到IOC中
    public static class StudentImportSelector implements ImportSelector {
        @Override
        public String[] selectImports(AnnotationMetadata importingClassMetadata) {
            //这里特意用ImportSelectStudent,因为这个方式和AutowireCapableBeanFactory#createBean会彼此覆盖
            return new String[]{ImportSelectStudent.class.getName()};
        }
    }
		
  	//ImportBeanDefinitionRegistrar,通过registerBeanDefinition的回调来进行注册Bean
    public static class StudentImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
        @Override
        public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
            registry.registerBeanDefinition("fromImportBeanDefinitionRegistrar", BeanDefinitionBuilder.rootBeanDefinition(Student.class).getBeanDefinition());
        }
    }

    public static class ImportSelectStudent extends Student{}

    public static class DeferredImportSelectStudent extends Student{}
  
}

BeanMethod

直接在工厂方法上面标注@Bean即可

    @Bean
    public static Student beanMethodStudent() {
        return new Student();
    }

API注册

//通过AutowireCapableBeanFactory#createBean来进行注册
applicationContext.getDefaultListableBeanFactory().createBean(Student.class); 
//通过GenericApplicationContext#registerBean进行注册。
applicationContext.registerBean("applicationContextRegisterStudentBean", Student.class);

注册结果输出

  • 创建应用上下文,对Student类型进行依赖查找 ,完整的代码如下
@Import({BeanCreationDemo.StudentImportSelector.class, BeanCreationDemo.StudentImportBeanDefinitionRegistrar.class, BeanCreationDemo.CustomDeferredImportSelector.class})
@ComponentScan(basePackages = "blog.spring.introduction.domain",nameGenerator = BeanCreationDemo.CustomBeanNameGenerator.class) //使用自定义BeanNameGenerator来区分默认的Student
public class BeanCreationDemo {

    public static void main(String[] args) {
        AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
        applicationContext.setAllowBeanDefinitionOverriding(false);
        //1. 注册当前类为Configuration Class
        applicationContext.register(BeanCreationDemo.class);
        //2. 混合Xml方式加载Xml上下文
        XmlBeanDefinitionReader xmlBeanDefinitionReader = new XmlBeanDefinitionReader(applicationContext);
        xmlBeanDefinitionReader.loadBeanDefinitions("META-INF/bean-creation-context.xml");
				
        applicationContext.getDefaultListableBeanFactory().createBean(Student.class);
        applicationContext.registerBean("applicationContextRegisterStudentBean", Student.class);

        //3. 启动应用上下文
        applicationContext.refresh();

        //4. print 所有的Student
        applicationContext.getBeansOfType(Student.class)
                .forEach(new PrintStudentMap());
        //5. ServiceLoaderFactoryBean
        for (Object student : applicationContext.getBean(ServiceLoader.class)) {
            System.out.println(student);
        }

        applicationContext.close();
    }
    
    public static class PrintStudentMap implements BiConsumer<String, Student> {
        @Override
        public void accept(String s, Student student) {
            System.out.println(String.format("k=%s,v=%s", s, student.toString()));
        }
    }
}

//output
//属性+构造
k=parameterAndConstructCreationBean,v=Student(address=Address(addressName=hz), name=layzlittle, age=200, beanName=parameterAndConstructCreationBean, student=null)
//静态工厂
k=staticFactoryCreationBean,v=Student(address=null, name=null, age=null, beanName=staticFactoryCreationBean, student=null)
//实例工厂
k=instantiatedFactoryCreationBean,v=Student(address=null, name=null, age=null, beanName=instantiatedFactoryCreationBean, student=null)
//普通FactoryBean
k=studentFactoryBean,v=Student(address=null, name=null, age=null, beanName=null, student=null)
//Api方式
k=applicationContextRegisterStudentBean,v=Student(address=null, name=null, age=null, beanName=applicationContextRegisterStudentBean, student=null)
//JavaEE @ManagedBean
k=blog.spring.introduction.domain.ManagedStudentBean,v=Student(address=null, name=null, age=null, beanName=blog.spring.introduction.domain.ManagedStudentBean, student=null)
// JSR330 @Named
k=blog.spring.introduction.domain.NamedStudentBean,v=Student(address=null, name=null, age=null, beanName=blog.spring.introduction.domain.NamedStudentBean, student=null)
//@Component派生
k=StudentByCustomGenerator,v=Student(address=null, name=null, age=null, beanName=StudentByCustomGenerator, student=null)
//ImportSelector
k=blog.spring.creation.BeanCreationDemo$ImportSelectStudent,v=Student(address=null, name=null, age=null, beanName=blog.spring.creation.BeanCreationDemo$ImportSelectStudent, student=null)
//@Bean
k=beanMethodStudent,v=Student(address=null, name=null, age=null, beanName=beanMethodStudent, student=null)
//ImportBeanDefinitionRegsitrar
k=fromImportBeanDefinitionRegistrar,v=Student(address=null, name=null, age=null, beanName=fromImportBeanDefinitionRegistrar, student=null)
//DeferredImportSelector
k=blog.spring.creation.BeanCreationDemo$DeferredImportSelectStudent,v=Student(address=null, name=null, age=null, beanName=blog.spring.creation.BeanCreationDemo$DeferredImportSelectStudent, student=null)
//ServiceLoaderFactoryBean
Student(address=null, name=null, age=null, beanName=null, student=null)

属性赋值和初始化源码解析

属性赋值

属性赋值,就是将PropertyValue转换为具体的属性并设置到实例化后的Bean中,对应源码中的populateBean()流程

	protected void populateBean(String beanName, RootBeanDefinition mbd, @Nullable BeanWrapper bw) {
    //1. 若BeanWrapper为null且当前BeanDefinition有PropertyValues抛出异常
		if (bw == null) {
			if (mbd.hasPropertyValues()) {
				throw new BeanCreationException(
						mbd.getResourceDescription(), beanName, "Cannot apply property values to null instance");
			}
			else {
				// Skip property population phase for null instance.
				return;
			}
		}

		// Give any InstantiationAwareBeanPostProcessors the opportunity to modify the
		// state of the bean before properties are set. This can be used, for example,
		// to support styles of field injection.
		//2. 这里官方注释说的很清楚,会回调所有的InstantiationAwareBeanPostProcessor#postProcessAfterInstantiation()方法,若该方法返回false,那么将跳过PropertyValues赋值过程
		if (!mbd.isSynthetic() && hasInstantiationAwareBeanPostProcessors()) {
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				if (!bp.postProcessAfterInstantiation(bw.getWrappedInstance(), beanName)) {
					return;
				}
			}
		}

		PropertyValues pvs = (mbd.hasPropertyValues() ? mbd.getPropertyValues() : null);
		//3. 如果是autowiring模式则进行autowiring处理,默认是不开启的
		int resolvedAutowireMode = mbd.getResolvedAutowireMode();
		if (resolvedAutowireMode == AUTOWIRE_BY_NAME || resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
			MutablePropertyValues newPvs = new MutablePropertyValues(pvs);
			if (resolvedAutowireMode == AUTOWIRE_BY_NAME) {
				autowireByName(beanName, mbd, bw, newPvs);
			}
			if (resolvedAutowireMode == AUTOWIRE_BY_TYPE) {
				autowireByType(beanName, mbd, bw, newPvs);
			}
			pvs = newPvs;
		}
		
		boolean hasInstAwareBpps = hasInstantiationAwareBeanPostProcessors();
		boolean needsDepCheck = (mbd.getDependencyCheck() != AbstractBeanDefinition.DEPENDENCY_CHECK_NONE);
		//4. 下面进行InstantiationAwareBeanPostProcessor的另外一个非常重要的生命周期回调
		PropertyDescriptor[] filteredPds = null;
		if (hasInstAwareBpps) {
			if (pvs == null) {
				pvs = mbd.getPropertyValues();
			}
            //4.1 回调所有InstantiationAwareBeanPostProcessor#postProcessProperties()
                  // 这里会回调到AutowiredAnnotationBeanPostProcessor完成相关的属性注入,这个之前的文章以前解释的很详细了
            // 大概就是通过依赖查找到具体属性对应的候选Bean然后通过反射设置到属性值中
			for (InstantiationAwareBeanPostProcessor bp : getBeanPostProcessorCache().instantiationAware) {
				PropertyValues pvsToUse = bp.postProcessProperties(pvs, bw.getWrappedInstance(), beanName);
				if (pvsToUse == null) {
					if (filteredPds == null) {
						filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
					}
          //这个方法是老版本处理属性注入的入口,这里会跳过
					pvsToUse = bp.postProcessPropertyValues(pvs, filteredPds, bw.getWrappedInstance(), beanName);
					if (pvsToUse == null) {
						return;
					}
				}
				pvs = pvsToUse;
			}
		}
    //5. 进行属性过滤,默认是不开启的。在开启了属性检测的时候,过滤掉一些(ignoredDependencyTypes / ignoreDependencyInterfaces)属性描述符
		if (needsDepCheck) {
			if (filteredPds == null) {
				filteredPds = filterPropertyDescriptorsForDependencyCheck(bw, mbd.allowCaching);
			}
			checkDependencies(beanName, mbd, filteredPds, pvs);
		}
		//6. 进行属性设置 (通过反射)
    // 这里主要就是解析PropertyValue中的Value值,然后通过BeanWrapperImpl反射set方法或者反射调用Field#set()
    //详细逻辑可以自己追一下,基本就是类型转换+属性赋值(当前其中还有嵌套属性的转换等)
		if (pvs != null) {
			applyPropertyValues(beanName, mbd, bw, pvs);
		}
	}

初始化相关方法的回调时机和源码解析

spring中相关Bean的初始化回调有三种

  • @PostConstruct
  • BeanDefinition#initMethod()
  • 实现InitializingBean

那么回调的顺序和时机在什么地方呢?

在Bean属性赋值之后会进行Bean的初始化。详细见AbstracatAutowireCapableBeanFactory#initializeBean

	protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
    //1. 回调Aware相关
		if (System.getSecurityManager() != null) {
			AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
				invokeAwareMethods(beanName, bean);
				return null;
			}, getAccessControlContext());
		}
		else {
			invokeAwareMethods(beanName, bean);
		}
		//应用所有BeanPostProcessor#postProcessorsBeforeInitialization()方法,此时会执行到
    //InitDestroyAnnotationBeanPostProcessor#postProcessorsBeforeInitialization方法
    //会执行@PostConstruct的回调
		Object wrappedBean = bean;
		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
      //执行BeanDefinition#initMethod()
			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;
	}

进入InitDestroyAnnotationBeanPostProcessor

	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    //1. 会将@PostCosntruct构建成LifecycleMetadata
		LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
		try {
			//2. 反射回调initMetdho()
			metadata.invokeInitMethods(bean, beanName);
		}
		return bean;
	}

处理invokeInitMethods

	protected void invokeInitMethods(String beanName, Object bean, @Nullable RootBeanDefinition mbd)
			throws Throwable {

		boolean isInitializingBean = (bean instanceof InitializingBean);
		if (isInitializingBean && (mbd == null || !mbd.isExternallyManagedInitMethod("afterPropertiesSet"))) {
			if (logger.isTraceEnabled()) {
				logger.trace("Invoking afterPropertiesSet() on bean with name '" + beanName + "'");
			}
			if (System.getSecurityManager() != null) {
				try {
          //1. 回调所有的InitializingBean#afterPropertieSet()
					AccessController.doPrivileged((PrivilegedExceptionAction<Object>) () -> {
						((InitializingBean) bean).afterPropertiesSet();
						return null;
					}, getAccessControlContext());
				}
				catch (PrivilegedActionException pae) {
					throw pae.getException();
				}
			}
			else {
				((InitializingBean) bean).afterPropertiesSet();
			}
		}
		//2. 回调所有的BeanDefinition#initMethod()
		if (mbd != null && bean.getClass() != NullBean.class) {
			String initMethodName = mbd.getInitMethodName();
			if (StringUtils.hasLength(initMethodName) &&
					!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
					!mbd.isExternallyManagedInitMethod(initMethodName)) {
				invokeCustomInitMethod(beanName, bean, mbd);
			}
		}
	}

总结,最后初始化调用属性为@PostConsturct > InitializingBean > BeanDefinition#initMethod()