spring-beanFactory三

前两篇简单介绍了XmlBeanFactory如何加载xml以及如何创建bean,这都是完全基于xml配置的,那么注解又是如何处理的呢?以@Component和@Resource为例简单说明。

 

1 XmlBeanFactory factory = new XmlBeanFactory(new ClassPathResource("spring/spring-test.xml"));
2 //BeanFactory不会自动添加BeanPostProcessor(ApplicationContext会),有了CommonAnnotationBeanPostProcessor就可以使用@Resource、@PreDestroy、@AfterConstruct了
3 CommonAnnotationBeanPostProcessor commonAnnotationBeanPostProcessor = new CommonAnnotationBeanPostProcessor();
4 commonAnnotationBeanPostProcessor.setBeanFactory(factory);
5 factory.addBeanPostProcessor(commonAnnotationBeanPostProcessor);
6 MyBean bean = (MyBean) factory.getBean("myBean");
7 System.out.println(bean.name());//my bean

 

1 @Component("myBean")
2 public class MyBean {
3     @Resource
4     private MyBean myBean;
5     private String name = "my bean";
6     public String name() {
7         return myBean.name;
8     }
9 }

 

 1 <beans
 2         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
 3         xmlns="http://www.springframework.org/schema/beans"
 4         xmlns:context="http://www.springframework.org/schema/context"
 5         xsi:schemaLocation="http://www.springframework.org/schema/beans
 6        http://www.springframework.org/schema/beans/spring-beans.xsd
 7        http://www.springframework.org/schema/context
 8        http://www.springframework.org/schema/context/spring-context.xsd">
 9     <context:component-scan base-package="com.zyong.spring.beanfactory" />
10 </beans>

 

之前有提到过,将xml解析成Document后就会注册bean definitions,注册bean definition的过程就是解析Document的过程,之前分析了parseDefaultElement是处理bean标签的主要方法,现在来看delegate.parseCustomElement方法,它会处理一些复杂标签,比如component-scan。

 1 //DefaultBeanDefinitionDocumentReader的parseBeanDefinitions方法,有删减
 2 protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
 3     NodeList nl = root.getChildNodes();
 4     for (int i = 0; i < nl.getLength(); i++) {
 5         Node node = nl.item(i);
 6         if (node instanceof Element) {
 7             Element ele = (Element) node;
 8             if (delegate.isDefaultNamespace(ele)) {
 9                 parseDefaultElement(ele, delegate);
10             }
11             else {
12                 delegate.parseCustomElement(ele);
13             }
14         }
15     }
16 }

 

 1 public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
 2     //得到namespace,这里对于context:component-scan就是http://www.springframework.org/schema/context
 3     String namespaceUri = getNamespaceURI(ele);
 4     //spring会预注册一些NamespaceHandler,此处就会得到ContextNamespaceHandler
 5     NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
 6     if (handler == null) {
 7         error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
 8         return null;
 9     }
10     //使用NamespaceHandler解析该DOM节点
11     return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
12 }

 

 1 public class ContextNamespaceHandler extends NamespaceHandlerSupport {
 2     //init方法会在NamespaceHandler构造完成后回调
 3     @Override
 4     public void init() {
 5         registerBeanDefinitionParser("property-placeholder", new PropertyPlaceholderBeanDefinitionParser());
 6         registerBeanDefinitionParser("property-override", new PropertyOverrideBeanDefinitionParser());
 7         registerBeanDefinitionParser("annotation-config", new AnnotationConfigBeanDefinitionParser());
 8         //NamespaceHandlerSupport中持有BeanDefinitionParser,
 9         //handler.parse会调用findParserForElement(element, parserContext).parse(element, parserContext),
10         //即将parse任务委托给具体的BeanDefinitionParser,这里就是ComponentScanBeanDefinitionParser
11         registerBeanDefinitionParser("component-scan", new ComponentScanBeanDefinitionParser());
12         registerBeanDefinitionParser("load-time-weaver", new LoadTimeWeaverBeanDefinitionParser());
13         registerBeanDefinitionParser("spring-configured", new SpringConfiguredBeanDefinitionParser());
14         registerBeanDefinitionParser("mbean-export", new MBeanExportBeanDefinitionParser());
15         registerBeanDefinitionParser("mbean-server", new MBeanServerBeanDefinitionParser());
16     }
17 }

 

 1 //ComponentScanBeanDefinitionParser的parse方法,该方法与解析bean标签类似,最终都会产生bean definition并注册。
 2 public BeanDefinition parse(Element element, ParserContext parserContext) {
 3     //得到package信息
 4     String basePackage = element.getAttribute(BASE_PACKAGE_ATTRIBUTE);
 5     //进一步分析package路径
 6     basePackage = parserContext.getReaderContext().getEnvironment().resolvePlaceholders(basePackage);
 7     String[] basePackages = StringUtils.tokenizeToStringArray(basePackage,
 8             ConfigurableApplicationContext.CONFIG_LOCATION_DELIMITERS);
 9 
10     // Actually scan for bean definitions and register them.
11     ClassPathBeanDefinitionScanner scanner = configureScanner(parserContext, element);
12     //doScan会遍历package下的类,通过filters检查是否应该将类注册为bean,如果检查通过则注册该bean definition。
13     //filters就会包含AnnotationTypeFilter,其annotationType为org.springframework.stereotype.Component,如果被检查类有@Compenent注解则将其视为bean
14     Set<BeanDefinitionHolder> beanDefinitions = scanner.doScan(basePackages);
15 
16     registerComponents(parserContext.getReaderContext(), beanDefinitions, element);
17 
18     return null;
19 }

 

至此就将使用注解声明的bean注册进beanFactory了(还未实例化),由于此时在bean中使用了注解@Resource进行注入,故与xml注入有所差异。
由下表可知,beanFactory不会自动注册BeanPostProcessor,而通过文档发现注解的注入其实就是通过BeanPostProcessor完成的,所以测试代码中才会显示添加CommonAnnotationBeanPostProcessor,有了CommonAnnotationBeanPostProcessor就可以使用@Resource、@PreDestroy、@AfterConstruct了。

FeatureBeanFactoryApplicationContext

Bean instantiation/wiring

Yes

Yes

Automatic BeanPostProcessor registration

No

Yes

Automatic BeanFactoryPostProcessor registration

No

Yes

Convenient MessageSource access (for i18n)

No

Yes

ApplicationEvent publication

No

Yes

 

CommonAnnotationBeanPostProcessor是一个InstantiationAwareBeanPostProcessor,这里我们只关注其postProcessPropertyValues方法。

 1 //CommonAnnotationBeanPostProcessor的postProcessPropertyValues方法
 2 public PropertyValues postProcessPropertyValues(
 3         PropertyValues pvs, PropertyDescriptor[] pds, Object bean, String beanName) throws BeansException {
 4 
 5     InjectionMetadata metadata = findResourceMetadata(beanName, bean.getClass(), pvs);
 6     try {
 7         //注入,注入逻辑无非就是遍历可注入属性(字段、方法),进行反射调用。
 8         metadata.inject(bean, beanName, pvs);
 9     }
10     catch (Throwable ex) {
11         throw new BeanCreationException(beanName, "Injection of resource dependencies failed", ex);
12     }
13     return pvs;
14 }

 

附:

 

posted @ 2017-08-17 15:04  holoyong  阅读(152)  评论(0编辑  收藏  举报