spring自定义标签原理

    在了解自定义标签原理前,先看下如何使用自定义标签:http://blog.csdn.net/humanmonkey/article/details/72790150

   

    在如何使用自定义标签中可以关注到,最重要的是NamespaceHandlerSupport、AbstractSingleBeanDefinitionParser、spring.handlers和spring.schemas这四个东东。怎么通过NamespaceHandlerSupport.init()、AbstractSingleBeanDefinitionParser.doParse、spring.handlers和spring.schemas来实现的呢?spring对标签的解析流程如下:



Step 1: 将 xml 文件解析成 Dom 树。将 xml 文件解析成 dom 树的时候,需要 xml 标签定义 schema 来验证文件的语法结构。 Spring 约定将所有的 shema 的虚拟路径和真实文件路径映射定义在 classpath 的在 META-INF/spring.schemas 下面。在容器启动时 Spring 会扫描所有的 META-INF/spring.schemas 并将映射维护到一个 map 里。



Step 2: 将 dom 树解析成 BeanDifinition ,将定义 bean 的标签和 xml 定义解析成 BeanDefinition 的过程。如果是默认的 bean 标签, spring 会直接进行解析。而如果不是默认的 bean 标签,包括自定义和 spring 扩展的 <aop> 、 <p> 、 <util> 等标签,则需要提供专门的 xmlparser 来处理。 parser由自己定义和编写,并通过handler注册到容器。Spring 约定了 META-INF/spring.handlers 文件,在这里面定义了标签命名空间和handler 的映射。容器起来的时候会加载 handler , handler 会向容器注册该命名空间下的标签和解析器。在解析的自定义标签的时候, spring 会根据标签的命名空间和标签名找到一个解析器。由该解析器来完成对该标签内容的解析,并返回一个 BeanDefinition 。


以下是源码的实现:


1、 加载 spring.shemas: 在PluggableSchemaResolver.Java里实现,解析namespace后放入map中

public class PluggableSchemaResolver implements EntityResolver {

    /***定义schema location的映射文件路径***/  

   public static final String DEFAULT_SCHEMA_MAPPINGS_LOCATION = "META-INF/spring.schemas";


   private static final Log logger = LogFactory.getLog(PluggableSchemaResolver.class);

   private final ClassLoader classLoader;

   private final String schemaMappingsLocation;

   /** 存储schema*/
   private volatile Map<String, String> schemaMappings;


     public PluggableSchemaResolver(ClassLoader classLoader) {
      this.classLoader = classLoader;
      this.schemaMappingsLocation = DEFAULT_SCHEMA_MAPPINGS_LOCATION;
   }

  
   public PluggableSchemaResolver(ClassLoader classLoader, String schemaMappingsLocation) {
      Assert.hasText(schemaMappingsLocation, "'schemaMappingsLocation' must not be empty");
      this.classLoader = classLoader;
      this.schemaMappingsLocation = schemaMappingsLocation;
   }

   @Override
   public InputSource resolveEntity(String publicId, String systemId) throws IOException {
      if (logger.isTraceEnabled()) {
         logger.trace("Trying to resolve XML entity with public id [" + publicId +
               "] and system id [" + systemId + "]");
      }

      if (systemId != null) {
         String resourceLocation = getSchemaMappings().get(systemId);
         if (resourceLocation != null) {
            Resource resource = new ClassPathResource(resourceLocation, this.classLoader);
            try {
               InputSource source = new InputSource(resource.getInputStream());
               source.setPublicId(publicId);
               source.setSystemId(systemId);
               if (logger.isDebugEnabled()) {
                  logger.debug("Found XML schema [" + systemId + "] in classpath: " + resourceLocation);
               }
               return source;
            }
            catch (FileNotFoundException ex) {
               if (logger.isDebugEnabled()) {
                  logger.debug("Couldn't find XML schema [" + systemId + "]: " + resource, ex);
               }
            }
         }
      }
      return null;
   }

  
   /**完成schema的解析存储*/
   private Map<String, String> getSchemaMappings() {
      if (this.schemaMappings == null) {
         synchronized (this) {
            if (this.schemaMappings == null) {
               if (logger.isDebugEnabled()) {
                  logger.debug("Loading schema mappings from [" + this.schemaMappingsLocation + "]");
               }
               try {
                  Properties mappings =
                        PropertiesLoaderUtils.loadAllProperties(this.schemaMappingsLocation, this.classLoader);
                  if (logger.isDebugEnabled()) {
                     logger.debug("Loaded schema mappings: " + mappings);
                  }
                  Map<String, String> schemaMappings = new ConcurrentHashMap<String, String>(mappings.size());
                  CollectionUtils.mergePropertiesIntoMap(mappings, schemaMappings);
                  this.schemaMappings = schemaMappings;
               }
               catch (IOException ex) {
                  throw new IllegalStateException(
                        "Unable to load schema mappings from location [" + this.schemaMappingsLocation + "]", ex);
               }
            }
         }
      }
      return this.schemaMappings;
   }

}

2、是否选择默认handler:通过delegate.isDefaultNamespace(root)来判断是否是默认的namespaceuri,默认是http://www.springframework.org/schema/beans

public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {

   protected void parseBeanDefinitions(Element root, BeanDefinitionParserDelegate delegate) {
   if (delegate.isDefaultNamespace(root)) {
      NodeList nl = root.getChildNodes();
      for (int i = 0; i < nl.getLength(); i++) {
         Node node = nl.item(i);
         if (node instanceof Element) {
            Element ele = (Element) node;
            if (delegate.isDefaultNamespace(ele)) {
               //解析默认命名空间,通过判断namespace 是否等于http://www.springframework.org/schema/beans来判断

               parseDefaultElement(ele, delegate);
            }
            else {
               //解析自定义命名空间
               delegate.parseCustomElement(ele);
            }
         }
      }
   }
   else {
      delegate.parseCustomElement(root);
   }
}

}
 


3、选择自定义handler:调用自定义handler的init方法

 
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
   String namespaceUri = getNamespaceURI(ele);
 
 
   /**通过namespace中选择NamespaceHandler*/
   NamespaceHandler handler = this.readerContext.getNamespaceHandlerResolver().resolve(namespaceUri);
   if (handler == null) {
      error("Unable to locate Spring NamespaceHandler for XML schema namespace [" + namespaceUri + "]", ele);
      return null;
   }
   return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
 
 
 
 
public class DefaultNamespaceHandlerResolver implements NamespaceHandlerResolver {

public NamespaceHandler resolve(String namespaceUri) {	
   Map<String, Object> handlerMappings = getHandlerMappings();
   Object handlerOrClassName = handlerMappings.get(namespaceUri);
   if (handlerOrClassName == null) {
     return null;
   }else if (handlerOrClassName instanceof NamespaceHandler) {
     return (NamespaceHandler) handlerOrClassName;
   }else {
     String className = (String) handlerOrClassName;
     try {
       Class<?> handlerClass = ClassUtils.forName(className, this.classLoader);
       if (!NamespaceHandler.class.isAssignableFrom(handlerClass)) {
         throw new FatalBeanException("Class [" + className + "] for namespace [" + namespaceUri +
               "] does not implement the [" + NamespaceHandler.class.getName() + "] interface");
       }
       NamespaceHandler namespaceHandler = (NamespaceHandler) BeanUtils.instantiateClass(handlerClass);
       //调用自定义handler的init方法
       namespaceHandler.init();
       handlerMappings.put(namespaceUri, namespaceHandler);
       return namespaceHandler;
   }catch (ClassNotFoundException ex) {
      throw new FatalBeanException("NamespaceHandler class [" + className + "] for namespace [" +
            namespaceUri + "] not found", ex);
   }catch (LinkageError err) {
      throw new FatalBeanException("Invalid NamespaceHandler class [" + className + "] for namespace [" +
            namespaceUri + "]: problem with handler class file or dependent class", err);
   }
}

}
 
 
 
 
4、调用自定义parser
 
 
public abstract class AbstractBeanDefinitionParser implements BeanDefinitionParser {

@Override
public final BeanDefinition parse(Element element, ParserContext parserContext) {
  //解析过程
   AbstractBeanDefinition definition = parseInternal(element, parserContext); 
   if (definition != null && !parserContext.isNested()) {
      try {
         String id = resolveId(element, definition, parserContext);
         if (!StringUtils.hasText(id)) {
            parserContext.getReaderContext().error(
                  "Id is required for element '" + parserContext.getDelegate().getLocalName(element)
                        + "' when used as a top-level tag", element);
         }
         String[] aliases = null;
         if (shouldParseNameAsAliases()) {
            String name = element.getAttribute(NAME_ATTRIBUTE);
            if (StringUtils.hasLength(name)) {
               aliases = StringUtils.trimArrayElements(StringUtils.commaDelimitedListToStringArray(name));
            }
         }
 
       //进行bean注册
         BeanDefinitionHolder holder = new BeanDefinitionHolder(definition, id, aliases);
         registerBeanDefinition(holder, parserContext.getRegistry());
         if (shouldFireEvents()) {
            BeanComponentDefinition componentDefinition = new BeanComponentDefinition(holder);
            postProcessComponentDefinition(componentDefinition);
            parserContext.registerComponent(componentDefinition);
         }
      }
      catch (BeanDefinitionStoreException ex) {
         parserContext.getReaderContext().error(ex.getMessage(), element);
         return null;
      }
   }
   return definition;
}
}



public abstract class AbstractSingleBeanDefinitionParser extends AbstractBeanDefinitionParser {

@Override
protected final AbstractBeanDefinition parseInternal(Element element, ParserContext parserContext) {
   BeanDefinitionBuilder builder = BeanDefinitionBuilder.genericBeanDefinition();
   String parentName = getParentName(element);
   if (parentName != null) {
      builder.getRawBeanDefinition().setParentName(parentName);
   }
   Class<?> beanClass = getBeanClass(element);
   if (beanClass != null) {
      builder.getRawBeanDefinition().setBeanClass(beanClass);
   }
   else {
      String beanClassName = getBeanClassName(element);
      if (beanClassName != null) {
         builder.getRawBeanDefinition().setBeanClassName(beanClassName);
      }
   }
   builder.getRawBeanDefinition().setSource(parserContext.extractSource(element));
   if (parserContext.isNested()) {
      // Inner bean definition must receive same scope as containing bean.
      builder.setScope(parserContext.getContainingBeanDefinition().getScope());
   }
   if (parserContext.isDefaultLazyInit()) {
      // Default-lazy-init applies to custom bean definitions as well.
      builder.setLazyInit(true);
   }
   //调用自定义parser的doparse方法进行解析标签
   doParse(element, parserContext, builder);
   return builder.getBeanDefinition();
}

}


5、bean注册

请看4中注释


ok,通过以上就可以清楚知道spring底层是如何运行的,从xml解析到调用NamespaceHandlerSupport中init方法,紧接着调用AbstractSingleBeanDefinitionParser中的doParse方法进行解析,到最后如何注册成bean

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Spring框架允许我们自定义注解,用于标记特定的类、方法或属性,并通过反射来获取或处理这些注解。下面是创建自定义注解的步骤: 1. 创建一个新的Java类,用于定义自定义注解。注解需要使用`@interface`关键字进行声明。例如: ```java package com.example.annotations; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.TYPE) public @interface CustomAnnotation { // 在这里定义注解的属性 String value() default ""; } ``` 在上面的例子中,我们创建了一个名为`CustomAnnotation`的自定义注解,该注解被定义为在运行时可见,并且可以应用于类级别。 2. 在类中使用自定义注解。例如: ```java package com.example; import com.example.annotations.CustomAnnotation; @CustomAnnotation("Hello, world!") public class MyClass { // 类的具体实现 } ``` 在上面的例子中,我们在`MyClass`类上使用了自定义注解`CustomAnnotation`,并传递了一个字符串参数作为注解的值。 3. 使用反射获取自定义注解信息。例如: ```java package com.example; import com.example.annotations.CustomAnnotation; public class Main { public static void main(String[] args) { Class<?> clazz = MyClass.class; CustomAnnotation annotation = clazz.getAnnotation(CustomAnnotation.class); if (annotation != null) { String value = annotation.value(); System.out.println("Annotation value: " + value); } } } ``` 在上面的例子中,我们使用反射获取`MyClass`类上的`CustomAnnotation`注解,并获取注解的值。 这就是使用Spring框架自定义注解的基本步骤。你可以根据实际需求在注解中定义不同的属性,并根据需要在应用程序中使用这些自定义注解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值