【spring源码学习】spring的IOC容器之自定义xml配置标签扩展namspaceHandler向IOC容器中注册bean

本文涉及的产品
容器镜像服务 ACR,镜像仓库100个 不限时长
简介: 【spring以及第三方jar的案例】在spring中的aop相关配置的标签,线程池相关配置的标签,都是基于该种方式实现的。包括dubbo的配置标签都是基于该方式实现的。【一】原理===>spring在解析xml标签,一旦不是以开头的元素,就会走org.springframework.beans.factory.xml.BeanDefinitionParserDelegate的parseCustomElement(Element ele)方法解析自定义的标签===>在该方法里会根据xml中的命名空间去查询该标签对应的NamespaceHandler接口的实现类去解析该配置标签。

【spring以及第三方jar的案例】在spring中的aop相关配置的标签,线程池相关配置的标签,都是基于该种方式实现的。包括dubbo的配置标签都是基于该方式实现的。
【一】原理

===>spring在解析xml标签,一旦不是以<bean>开头的元素,就会走org.springframework.beans.factory.xml.BeanDefinitionParserDelegate的parseCustomElement(Element ele)方法解析自定义的标签

===>在该方法里会根据xml中的命名空间去查询该标签对应的NamespaceHandler接口的实现类去解析该配置标签。该接口解析该配置标签,并形成BeanDefinition注册到IOC容器中。

===>该扩展需要做的内容:

(1)建立spring.handlers文件,这是在解析xml配置文件的时候,spring会通过xml文件头的命名空间,去找该配置文件中的NamespaceHandler的实现类。

(2)建立spring.schemas文件,这是在xml文件中配置自定义标签的标签合法验证,也是合法检验。如果随意填写配置标签,spring将无法解析。

(3)在所扩展的项目的resources目录下,建立META-INF目录,并将两个文件放置在目录下。

(4)将spring.schemas中的xsd文件配置在随意的类路径下。关于xsd文件,可以了解:http://www.w3school.com.cn/schema/index.asp

(5)建立NamespaceHandler接口的实现类,建立BeanDefinitionParser的实现类。用于解析自已定义标签的内容。

 

【二】实现例子:定义一个自定义标签,实现一个类ZKClient的bean通过NamespaceHandler注册IOC容器。本例子已经通过测试。不写测试方法,只写实现过程。

(1)spring.handlers文件内容

http\://localhost.com/sxf=com.mobile.thinks.manages.namespaceHandler.SxfNameSpaceHandler
View Code

(2)spring.schemas文件内容

http\://localhost.com/sxf.xsd=com/mobile/thinks/manages/namespaceHandler/sxf.xsd
View Code

(3)xsd文件内容

<xsd:schema  xmlns:xsd="http://www.w3.org/2001/XMLSchema" 
targetNamespace="http://localhost.com/sxf"
xmlns="http://www.w3school.com.cn"
elementFormDefault="qualified">

<xsd:element name="zk">
  <xsd:complexType>
    <xsd:attribute name="host"  use="required" >
            <xsd:simpleType>
                <xsd:restriction base="xsd:string"/>
            </xsd:simpleType>
    </xsd:attribute>
    <xsd:attribute name="port"  use="required" >
            <xsd:simpleType>
                <xsd:restriction base="xsd:integer"/>
            </xsd:simpleType>
    </xsd:attribute>
    <xsd:attribute name="user"  use="required" >
            <xsd:simpleType>
                <xsd:restriction base="xsd:string"/>
            </xsd:simpleType>
    </xsd:attribute>
     <xsd:attribute name="pwd"  use="required" >
            <xsd:simpleType>
                <xsd:restriction base="xsd:string"/>
            </xsd:simpleType>
    </xsd:attribute>
  </xsd:complexType>
</xsd:element>
</xsd:schema>
View Code

(4)spring的xml配置文件内容

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:jpa="http://www.springframework.org/schema/data/jpa"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:task="http://www.springframework.org/schema/task"
       xmlns:sxf="http://localhost.com/sxf"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
           http://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/tx
              http://www.springframework.org/schema/tx/spring-tx.xsd
              http://www.springframework.org/schema/aop 
              http://www.springframework.org/schema/aop/spring-aop.xsd
              http://www.springframework.org/schema/task
              http://www.springframework.org/schema/task/spring-task.xsd
              http://www.springframework.org/schema/data/jpa
           http://www.springframework.org/schema/data/jpa/spring-jpa.xsd 
           http://www.springframework.org/schema/context 
           http://www.springframework.org/schema/context/spring-context.xsd
           http://localhost.com/sxf
           http://localhost.com/sxf.xsd
           
           ">

    <sxf:zk host="127.0.0.1" port="2181" user="shangxiaofei"  pwd="smxcyx"/>

   <!-- <context:property-placeholder location="classpath:resources.properties"/> -->

    <!-- 扫描注解Bean -->
    <context:component-scan base-package="com.mobile.thinks.**">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
        <context:include-filter type="annotation" expression="org.springframework.beans.factory.annotation.Autowired"/>
    </context:component-scan>
    
   
    
</beans>
View Code

(5)NamespaceHandler接口实现类的内容

package com.mobile.thinks.manages.namespaceHandler;

import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
 * 自定义标签的注解解释器
 * @author sxf
 *
 */
public class SxfNameSpaceHandler extends NamespaceHandlerSupport {

    /**
     * 初始化zk元素的具体解析器
     */
    @Override
    public void init() {
        registerBeanDefinitionParser("zk", new ZkBeanDefinitionParser());
    }
    

}
View Code

(6)BeanDefinitionParser接口实现类的内容

package com.mobile.thinks.manages.namespaceHandler;

import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;

public class ZkBeanDefinitionParser  implements BeanDefinitionParser{

    private static final String HOST ="host";
    private static final String PORT="port";
    private static final String USER="user";
    private static final String PWD="pwd";
    
    /**
     * 解析标签,形成特定的beanDefinition加入到ioc容器中
     */
    @Override
    public BeanDefinition parse(Element element, ParserContext parserContext) {
        BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(ZkClient.class);
        String host=element.getAttribute("host");
        String port=element.getAttribute("port");
        String user=element.getAttribute("user");
        String pwd=element.getAttribute("pwd");
        builder.addPropertyValue("host",host);
        builder.addPropertyValue("port", Integer.valueOf(port));
        builder.addPropertyValue("user", user);
        builder.addPropertyValue("pwd", pwd);
        parserContext.getRegistry().registerBeanDefinition("zkClient", builder.getBeanDefinition());
        return builder.getBeanDefinition();
    }
    
    

}
View Code

(7)Zkclient类的内容,将来在项目中用一下方式直接使用该类

 @Autowired
    private ZkClient zkClient;

package com.mobile.thinks.manages.namespaceHandler;
/**
 * 该类用自定义的NameSpaceHandler类解析配置文件向IOC容器中注册
 * @author sxf
 *
 */
public class ZkClient {

    private String host;
    private int port;
    private String user;
    private String pwd;
    
    public String getHost() {
        return host;
    }
    public void setHost(String host) {
        this.host = host;
    }
    public int getPort() {
        return port;
    }
    public void setPort(int port) {
        this.port = port;
    }
    public String getUser() {
        return user;
    }
    public void setUser(String user) {
        this.user = user;
    }
    public String getPwd() {
        return pwd;
    }
    public void setPwd(String pwd) {
        this.pwd = pwd;
    }
    
}
View Code

 

【三】项目结构图

 

【&&】需要注意的点,当maven打包的时候,默认不会将sxf.xsd文件打包进jar包,将来项目用到的时候就不会从本地读取到该sxf.xsd文件,则需要在pom.xml文件配置如下,才可以将文件打包到相应的位置。也可以将其他格式的文件,打包到jar包相应的位置,只需要修改相应文件的后缀。

<build>    
          <!-- 打成jar包的名字 -->
        <finalName>test</finalName>    
        <!--  这样也可以把所有的readme文件,打包到相应位置。其他的比如XX.xml文件,也是同样配置  -->  
        <resources>    
            <resource>    
                <directory>src/main/resources</directory>    
                <includes>    
                    <include>**/*.txt</include>    
                    <include>**/*.xml</include>  
                </includes>    
            </resource>    
            <resource>    
                <directory>src/main/java</directory>    
                <includes>    
                    <include>**/*.xsd</include>  
                </includes>     
            </resource>    
        </resources>    
    </build>    
View Code

该项目的jar完整的pom.xml文件

<?xml version="1.0"?>
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd" xmlns="http://maven.apache.org/POM/4.0.0"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
  <modelVersion>4.0.0</modelVersion>
  <parent>
    <groupId>com.mobile</groupId>
    <artifactId>thinks</artifactId>
    <version>0.0.1-SNAPSHOT</version>
  </parent>
  <groupId>com.mobile</groupId>
  <artifactId>thinks-manages</artifactId>
  <version>1.0.0</version>
  <name>thinks-manages</name>
  <url>http://maven.apache.org</url>
  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>
      <build>    
        <!--  <finalName>test</finalName> 打包成默认名字 -->   
        <!--  这样也可以把所有的readme文件,打包到相应位置。其他的比如XX.xml文件,也是同样配置  -->  
        <resources>    
            <resource>    
                <directory>src/main/resources</directory>    
                <includes>    
                    <include>**/*.txt</include>    
                    <include>**/*.xml</include>
                    <include>**/*.handlers</include>
                    <include>**/*.schemas</include>
                    <include>**/*.drl</include>  
                </includes>    
            </resource>    
            <resource>    
                <directory>src/main/java</directory>    
                <includes>    
                    <include>**/*.xsd</include>  
                </includes>     
            </resource>    
        </resources>    
    </build>    
  <dependencies>
      <dependency>
          <groupId>com.mobile</groupId>
          <artifactId>thinks-service</artifactId>
          <version>${thinks.service.version}</version>
      </dependency>
      <dependency>
          <groupId>com.mobile</groupId>
          <artifactId>thinks-core</artifactId>
          <version>${thinks.core.version}</version>
      </dependency>
      <dependency>
          <groupId>com.mobile</groupId>
          <artifactId>thinks-commons</artifactId>
          <version>${thinks.commons.version}</version>
      </dependency>
  
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
    <!-- drools规则引擎 -->
    <dependency>
                <groupId>org.drools</groupId>
                <artifactId>drools-core</artifactId>
            </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-compiler</artifactId>
        </dependency>
        <dependency>
          <groupId>org.drools</groupId>
          <artifactId>knowledge-api</artifactId>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-decisiontables</artifactId>
        </dependency>
        <dependency>
            <groupId>org.drools</groupId>
            <artifactId>drools-jsr94</artifactId>
            <version>${drools.version}</version><!--$NO-MVN-MAN-VER$-->
        </dependency>
          <!-- drools升级6.5.0.final版本依赖 -->
        <dependency>
                <groupId>org.eclipse.jdt.core.compiler</groupId>
                <artifactId>ecj</artifactId>
        </dependency>
  </dependencies>
</project>
View Code

 

目录
打赏
0
0
0
0
11
分享
相关文章
微服务——SpringBoot使用归纳——为什么学习Spring Boot
本文主要探讨为什么学习Spring Boot。从Spring官方定位来看,Spring Boot旨在快速启动和运行项目,简化配置与编码。其优点包括:1) 良好的基因,继承了Spring框架的优点;2) 简化编码,通过starter依赖减少手动配置;3) 简化配置,采用Java Config方式替代繁琐的XML配置;4) 简化部署,内嵌Tomcat支持一键式启动;5) 简化监控,提供运行期性能参数获取功能。此外,从未来发展趋势看,微服务架构逐渐成为主流,而Spring Boot作为官方推荐技术,与Spring Cloud配合使用,将成为未来发展的重要方向。
25 0
微服务——SpringBoot使用归纳——为什么学习Spring Boot
Spring IOC—基于注解配置和管理Bean 万字详解(通俗易懂)
Spring 第三节 IOC——基于注解配置和管理Bean 万字详解!
175 26
什么是Spring IOC 和DI ?
IOC : 控制翻转 , 它把传统上由程序代码直接操控的对象的调用权交给容 器,通过容器来实现对象组件的装配和管理。所谓的“控制反转”概念就是对组件对象控制权的转 移,从程序代码本身转移到了外部容器。 DI : 依赖注入,在我们创建对象的过程中,把对象依赖的属性注入到我们的类中。
【SpringFramework】Spring IoC-基于XML的实现
本文主要讲解SpringFramework中IoC和DI相关概念,及基于XML的实现方式。
130 69
【SpringFramework】Spring IoC-基于注解的实现
本文主要记录基于Spring注解实现IoC容器和DI相关知识。
76 21
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
本文详细介绍了Spring框架的核心功能,并通过手写自定义Spring框架的方式,深入理解了Spring的IOC(控制反转)和DI(依赖注入)功能,并且学会实际运用设计模式到真实开发中。
【23种设计模式·全精解析 | 自定义Spring框架篇】Spring核心源码分析+自定义Spring的IOC功能,依赖注入功能
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
本文介绍了在使用Spring框架时,如何通过创建`applicationContext.xml`配置文件来管理对象。首先,在resources目录下新建XML配置文件,并通过IDEA自动生成部分配置。为完善配置,特别是添加AOP支持,可以通过IDEA的Live Templates功能自定义XML模板。具体步骤包括:连续按两次Shift搜索Live Templates,配置模板内容,输入特定前缀(如spring)并按Tab键即可快速生成完整的Spring配置文件。这样可以大大提高开发效率,减少重复工作。
使用idea中的Live Templates自定义自动生成Spring所需的XML配置文件格式
【Spring】IoC和DI,控制反转,Bean对象的获取方式
IoC,DI,控制反转容器,Bean的基本常识,类注解@Controller,获取Bean对象的常用三种方式
Spring面试必问:手写Spring IoC 循环依赖底层源码剖析
在Spring框架中,IoC(Inversion of Control,控制反转)是一个核心概念,它允许容器管理对象的生命周期和依赖关系。然而,在实际应用中,我们可能会遇到对象间的循环依赖问题。本文将深入探讨Spring如何解决IoC中的循环依赖问题,并通过手写源码的方式,让你对其底层原理有一个全新的认识。
98 2
Spring生态学习路径与源码深度探讨
【11月更文挑战第13天】Spring框架作为Java企业级开发中的核心框架,其丰富的生态系统和强大的功能吸引了无数开发者的关注。学习Spring生态不仅仅是掌握Spring Framework本身,更需要深入理解其周边组件和工具,以及源码的底层实现逻辑。本文将从Spring生态的学习路径入手,详细探讨如何系统地学习Spring,并深入解析各个重点的底层实现逻辑。
116 9
AI助理

你好,我是AI助理

可以解答问题、推荐解决方案等