博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
spring-beanFactory三
阅读量:4321 次
发布时间:2019-06-06

本文共 6015 字,大约阅读时间需要 20 分钟。

前两篇简单介绍了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     @Resource4     private MyBean myBean;5     private String name = "my bean";6     public String name() {7         return myBean.name;8     }9 }

 

1 
9
10

 

之前有提到过,将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,这里就是ComponentScanBeanDefinitionParser11         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注解则将其视为bean14     Set
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了。

Feature BeanFactory ApplicationContext

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 }

 

附:

 

转载于:https://www.cnblogs.com/holoyong/p/7366583.html

你可能感兴趣的文章
第一次作业
查看>>
“==”运算符与equals()
查看>>
单工、半双工和全双工的定义
查看>>
Hdu【线段树】基础题.cpp
查看>>
时钟系统
查看>>
BiTree
查看>>
5个基于HTML5的加载动画推荐
查看>>
水平权限漏洞的修复方案
查看>>
静态链接与动态链接的区别
查看>>
Android 关于悬浮窗权限的问题
查看>>
如何使用mysql
查看>>
linux下wc命令详解
查看>>
敏捷开发中软件测试团队的职责和产出是什么?
查看>>
在mvc3中使用ffmpeg对上传视频进行截图和转换格式
查看>>
python的字符串内建函数
查看>>
Spring - DI
查看>>
微软自己的官网介绍 SSL 参数相关
查看>>
Composite UI Application Block (CAB) 概念和术语
查看>>
64位MATLAB和C混合编程以及联合调试
查看>>
原生js大总结二
查看>>