zoukankan      html  css  js  c++  java
  • 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 }

    附:

  • 相关阅读:
    [题解] LuoguP1587 [NOI2016]循环之美
    [题解] LuoguP3705 [SDOI2017]新生舞会
    [题解] LuoguP3702 [SDOI2017]序列计数
    [题解] LuoguP6476 [NOI Online 2 提高组]涂色游戏
    [题解] LuoguP4240 毒瘤之神的考验
    [题解] LuoguP6156简单题
    [题解] LuoguP6055 [RC-02] GCD
    [题解] LuoguP5050 【模板】多项式多点求值
    AtCoder Grand Contest 028题解
    Codeforces Round #421 (Div. 1) 题解
  • 原文地址:https://www.cnblogs.com/holoyong/p/7366583.html
Copyright © 2011-2022 走看看