常见的定义Bean的方式有:java
<bean id="dictionaryRelMap" class="java.util.HashMap"/>
@Component public class xxxServicer{ .... }
@Configuration public class xxxConfiguration{ @Bean public myBean myBean(){ return new myBean(); } }
虽然这三种定义Bean的方式不同,对应的处理细节也不同,可是从大的逻辑上来看,都是同样。主要的流程以下图: 最关键的就是问题就是这么去找到定义Bean的方式,而后生成BeanDefinition后注册到Spring上下文中,由Spring自动建立Bean的实例。
spring
BeanDefinition是一个接口,用来描述一个Bean实例,例如是SINGLETON仍是PROTOTYPE,属性的值是什么,构造函数的参数是什么等。简单来讲,经过一个BeanDefinition咱们就能够完成一个Bean实例化。 BeanDefinition及其主要的子类:app
下面简单说一下各个子类:ide
经过xml定义Bean是最先的Spring定义Bean的方式。所以,怎么把xml标签解析为BeanDefinition(), 入口是在org.springframework.beans.factory.xml.XmlBeanDefinitionReader
这个类,可是实际干活的是在org.springframework.beans.factory.xml.BeanDefinitionParserDelegate
。代码不少,但实际逻辑很简单,就是解析Spring定义的<bean> <property> 等标签 。 以前写过一篇文章介绍过如何自定义Spring标签 ,并解析后注册到Spring中——传送门函数
若是要使用@Component
等注解定义Bean,一个前提条件是:有<context:component-scan/>
或者@ComponentScan
注解。但这2个方式仍是有一点点区别:post
因为<context:component-scan/>
是一个xml标签,所以是在解析xml,生成的类org.springframework.context.annotation.ComponentScanBeanDefinitionParser
,关键代码:编码
@Override public BeanDefinition parse(Element element, ParserContext parserContext) { //获取base-package标签 String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE); basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage); String[] basePackages = StringUtils.tokenizeToStringArray(basePackage, ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS); // 实际处理类是ClassPathBeanDefinitionScanner ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element); //扫描basePackage下全部的类,若是有@Component等标签就是注册到Spring中 Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages); registerComponents(parserContext.getReaderContext(), beanDefinitions, element); return null; }
注解对应生成的类是org.springframework.context.annotation.ComponentScanAnnotationParser
其实最后实际干活的仍是ClassPathBeanDefinitionScanner
这个。ComponentScanAnnotationParser
类的生成是伴随着@Configuration
这个注解处理过程当中(意思说@ComponentScan
必须和@Configuration
一块儿使用)。而处理@Configuration
实际上是org.springframework.context.annotation.ConfigurationClassPostProcessor
。是否是感受有点绕。
其实简单来讲,在处理@Configuration
的时候发现有@ComponentScan
注解,就会生成ComponentScanAnnotationParser
去扫描@Component注解lua
上面说到了,不管注解仍是标签的方式,最后都会交给ClassPathBeanDefinitionScanner
这个类来处理,这个类作的就是1.扫描basePackage下全部class,若是有@Component等注解,读取@Component相关属性,生成ScannedGenericBeanDefinition
,注册到Spring中。.net
前面说了@ComponentScan是在@Configuration处理过程当中的一环,既然@Bean注解也是必须和@Configuration一块儿使用,那么说明@Bean的处理也是在@Configuration中,其实最后是交给ConfigurationClassBeanDefinitionReader
这个类来处理的,关键代码:code
private void loadBeanDefinitionsForConfigurationClass(ConfigurationClass configClass, TrackedConditionEvaluator trackedConditionEvaluator) { //若是本身是经过@Import注解定义的,那么须要把本身注册到Spring中 if (configClass.isImported()) { registerBeanDefinitionForImportedConfigurationClass(configClass); } //这里就是处理方法上的@Bean for (BeanMethod beanMethod : configClass.getBeanMethods()) { loadBeanDefinitionsForBeanMethod(beanMethod); } //处理@ImportResource,里面解析xml就是上面说到的解析xml的XmlBeanDefinitionReader loadBeanDefinitionsFromImportedResources(configClass.getImportedResources()); loadBeanDefinitionsFromRegistrars(configClass.getImportBeanDefinitionRegistrars()); }
为了保证org.springframework.context.annotation.ConfigurationClassPostProcessor
前面分别说了怎么把不一样定义Bean的方式转换为BeanDefinition加入到Spring中去(确切来讲是保持在BeanFactory的BeanDefinitionMap中),实例是在ApplicationContext最后阶段,关键代码在DefaultListableBeanFactory中
@Override public void preInstantiateSingletons() throws BeansException { for (String beanName : beanNames) { RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName); if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) { if (isFactoryBean(beanName)) { final FactoryBean<?> factory = (FactoryBean<?>) getBean(FACTORY_BEAN_PREFIX + beanName); boolean isEagerInit; if (System.getSecurityManager() != null && factory instanceof SmartFactoryBean) { isEagerInit = AccessController.doPrivileged(new PrivilegedAction<Boolean>() { @Override public Boolean run() { return ((SmartFactoryBean<?>) factory).isEagerInit(); } }, getAccessControlContext()); } else { isEagerInit = (factory instanceof SmartFactoryBean && ((SmartFactoryBean<?>) factory).isEagerInit()); } if (isEagerInit) { getBean(beanName); } } else { getBean(beanName); } } }
经过getBean最后最后实例的代码,在AbstractAutowireCapableBeanFactory中
protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) { //处理xxAware接口 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()) { // 调用BeanPostProcessors#postProcessBeforeInitialization wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName); } try { //初始化,先判断是不是InitializingBean, 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()) { // 调用BeanPostProcessors#postProcessAfterInitialization wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName); } return wrappedBean; }
从上面初始化能够看出,InitializeBean和BeanPostProcessors的调用顺序
综上分析,Spring加载Bean其实大的思想都是同样的,先读取相关信息生成BeanDefinition,而后经过BeanDefinition初始化Bean。若是知道了上面了套路之后,就能够清楚怎么自定义Xml标签或者自定义注解向Spring中注入Bean。