关于spring自定义属性(schema)

在开发Dubbo应用的时候,我们会在xml中做以下类似的配置:

<dubbo:application name="dubbo_service_provider" />
<dubbo:registry address="zookeeper://127.0.0.1:2181" />
<dubbo:protocol name="dubbo" port="20880" />

spring启动后,Dubbo的本地运行时环境就会获取到这些信息,根据这些信息完成注册服务,今天我们实战的内容就是开发一个类似的自定义属性,然后在spring项目中使用这个属性;

全文概览

整个实战过程分为以下几步:

  1. 创建web工程;
  2. 创建配置属性的bean;
  3. 创建XSD文件;
  4. 创建自定义BeanDefinitionParser,制定配置信息的解析规则;
  5. 创建自定义NamespaceHandler,规定配置信息的解析器;
  6. 添加spring.handlers文件;
  7. 添加spring.schemas文件;
  8. 在工程中配置一个这样的属性;
  9. 启动web工程,验证配置;

源码下载

如果您不打算编码,也可以在GitHub下载本次实战的源码,地址是:https://github.com/zq2599/blog_demos ,里面有多个工程,本次用到的是springschemademo,如下图红框所示:

接下来开始实战:

创建web工程

创建一个maven工程,pom.xml的内容如下,主要是把spring相关的依赖引入:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.bolingcavalry</groupId>
<artifactId>springschemademo</artifactId>
<packaging>war</packaging>
<version>0.0.1-SNAPSHOT</version>
<name>app Maven Webapp</name>
<url>http://maven.apache.org</url>
<properties>
<!-- spring版本号 -->
<spring.version>4.0.2.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<!-- 表示开发的时候引入,发布的时候不会加载此包 -->
<scope>test</scope>
</dependency>
<!-- spring核心包 -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-oxm</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<!-- 导入java ee jar 包 -->
<dependency>
<groupId>javax</groupId>
<artifactId>javaee-api</artifactId>
<version>7.0</version>
</dependency>
<!-- JSTL标签类 -->
<dependency>
<groupId>jstl</groupId>
<artifactId>jstl</artifactId>
<version>1.2</version>
</dependency>
<!-- 映入JSON -->
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
<!-- 上传组件包 -->
<dependency>
<groupId>commons-fileupload</groupId>
<artifactId>commons-fileupload</artifactId>
<version>1.3.1</version>
</dependency>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.9</version>
</dependency>
</dependencies>
<build>
<finalName>${project.artifactId}</finalName> <resources>
<resource>
<directory>src/main/java</directory>
<includes>
<include>**/*.properties</include>
<include>**/*.xml</include>
</includes>
<!-- 是否替换资源中的属性-->
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/resources</directory>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.tomcat.maven</groupId>
<artifactId>tomcat7-maven-plugin</artifactId>
<version>2.2</version>
<configuration>
<url>http://localhost:8080/manager/text</url>
<server>tomcat7</server>
<path>/${project.artifactId}</path>
<update>true</update>
</configuration>
</plugin>
</plugins>
</build>
</project>

web.xml中加上spring mvc的配置:

<servlet>
<servlet-name>SpringMVC</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring-mvc.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
<servlet-mapping>
<servlet-name>SpringMVC</servlet-name>
<!-- 此处可以可以配置成*.do,对应struts的后缀习惯 -->
<url-pattern>/</url-pattern>
</servlet-mapping>

还有spring的配置文件,加上注解相关的配置:

<!-- 启动SpringMVC的注解功能,完成请求和注解POJO的映射 -->
<bean
class="org.springframework.web.servlet.mvc.annotation.AnnotationMethodHandlerAdapter">
<property name="messageConverters">
<list>
<!-- JSON转换器 -->
<ref bean="mappingJacksonHttpMessageConverter" />
</list>
</property>
</bean>

其余的配置可以自行设置,或者参考我上传到git上的源码;

创建配置属性的bean

本次实战的示例,以"电脑"为例,有两个属性:操作系统和内存大小,如下:

package com.bolingcavalry;

/**
* Description:
*
* @author willzhao
* @email zq2599@gmail.com
* @date 2017/7/1 22:15
*/
public class Computer { /**
* 操作系统
*/
private String os; /**
* 内存大小
*/
private int ram; public String getOs() {
return os;
} public void setOs(String os) {
this.os = os;
} public int getRam() {
return ram;
} public void setRam(int ram) {
this.ram = ram;
}
}

创建XSD文件

在工程的src\main\resources\META-INF\computer.xsd目录下创建computer.xsd文件,内容如下:

<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
xmlns="http://blog.csdn.net/boling_cavalry/schema/computer"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:beans="http://www.springframework.org/schema/beans"
targetNamespace="http://blog.csdn.net/boling_cavalry/schema/computer"
elementFormDefault="qualified"
attributeFormDefault="unqualified">
<xsd:import namespace="http://www.springframework.org/schema/beans"/>
<xsd:element name="computer">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="os" type="xsd:string"/>
<xsd:attribute name="ram" type="xsd:int"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>

注意xmlns和targetNamespace的内容,在外部使用时也会用到,还有就是xsd:element节点,里面对computer的两个属性做了约束;

创建自定义BeanDefinitionParser,制定配置信息的解析规则

接下来要写个BeanDefinitionParser,作用是拿到xml中的computer节点后,该如何从这个节点中取得有效的信息给spring环境,源码如下:

public class ComputerBeanDefinitionParser extends AbstractSingleBeanDefinitionParser {
@Override
protected Class<?> getBeanClass(Element element) {
return Computer.class;
} @Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String os = element.getAttribute("os");
String ramStr = element.getAttribute("ram"); if(StringUtils.hasText(os)){
builder.addPropertyValue("os", os);
}
if(StringUtils.hasText(ramStr)){
builder.addPropertyValue("ram", Integer.valueOf(ramStr));
}
}
}

getBeanClass方法决定了解析节点后返回的bean的类型;

doParse方法的入参中收到了computer节点,在方法中解析"os"和"ram"两个节点,然后调用builder.addPropertyValue可以把解析结果传入builder中;

创建自定义NamespaceHandler,规定配置信息的解析器

自定义的NamespaceHandler,可以告诉spring环境,遇到computer的配置信息后,应该用ComputerBeanDefinitionParser去解析,代码很少,如下:

public class ComputerNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("computer", new ComputerBeanDefinitionParser());
}
}

添加spring.handlers文件

在src\main\resources\META-INF\目录下,添加spring.handlers文件,内容只有一行,如下:

http\://blog.csdn.net/boling_cavalry/schema/computer=com.bolingcavalry.ComputerNamespaceHandler

添加spring.schemas文件

在src\main\resources\META-INF\目录下,添加spring.schemas文件,内容只有一行,如下:

http\://blog.csdn.net/boling_cavalry/schema/computer.xsd=META-INF/computer.xsd

在工程中配置一个这样的属性

准备得差不多了,可以验证一下啦,在spring的配置文件中,如果要用到这个属性,可以按照如下方式来写:

<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:bolingcavalry="http://blog.csdn.net/boling_cavalry/schema/computer"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.0.xsd
http://blog.csdn.net/boling_cavalry/schema/computer
http://blog.csdn.net/boling_cavalry/schema/computer.xsd"> <bolingcavalry:computer id="computer" os="centos" ram="8" />
</beans>

除了bolingcavalry:computer的配置,还要注意xmlns:bolingcavalry的配置,还有xsi:schemaLocation中“http://blog.csdn.net/boling_cavalry/schema/computer"和

"http://blog.csdn.net/boling_cavalry/schema/computer.xsd” 也不要遗漏。

启动web工程,验证配置

为了验证配置是生效的,我们写一个controller在浏览器中显示配置信息,代码如下:

@Controller
public class HelloController { private static SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); @Autowired
Computer computer; @RequestMapping("/hello")
@ResponseBody
public String toIndex(HttpServletRequest request, Model model) {
return "hello 001 [" + sdf.format(new Date()) + "], computer os [" + computer.getOs() + "], ram [" + computer.getRam() + "]";
}
}

computer提供autowire注入,在web响应的时候会输出它的两个属性,现在启动tomcat并部署这个webapp,在浏览器中输入http://localhost:8080/springschemademo/hello, 就能看到如下输出:

以上就是spring自定义schema的实战内容,这里只是为了快速体验这个功能,实际的应用中应该是把这种能力封装到库中,然后提供给应用方来使用。

欢迎关注我的公众号:程序员欣宸

实战spring自定义属性(schema)的更多相关文章

  1. spring自定义schema学习

    [转载请注明作者和原文链接,欢迎讨论,相互学习.] 一.前言 1. 最近在学习dubbo,里边很多如provider.consumer.registry的配置都是通过spring自定义Schema来实 ...

  2. Spring AOP Schema aop:config、tx:advice

    Spring AOP Schema  aop:config.tx:advice 一.      利用aop:config标签实现AOP 首先看个例子,如下 接口代码: package com.lei. ...

  3. (spring-第2回【IoC基础篇】)Spring的Schema,基于XML的配置

    要深入了解Spring机制,首先需要知道Spring是怎样在IoC容器中装配Bean的.而了解这一点的前提是,要搞清楚Spring基于Schema的Xml配置方案. 在深入了解之前,必须要先明白几个标 ...

  4. 缘起 Dubbo ,讲讲 Spring XML Schema 扩展机制

    背景 在 Dubbo 中,可以使用 XML 配置相关信息,也可以用来引入服务或者导出服务.配置完成,启动工程,Spring 会读取配置文件,生成注入 相关 Bean.那 Dubbo 如何实现自定义 X ...

  5. spring 自定义schema

    扩展schema,定义自己的bean属性..不错! 主要: 1,定义META-INF下.xsd文件,这里是people.xsd;定义spring.handlers;定义spring.schemas 2 ...

  6. Spring AOP schema找不到报错 原

    转自:https://my.oschina.net/zetaplusae/blog/144821 使用jersey+spring构建RESTful服务,并将应用部署在不能连接外网的服务器上.部署时,报 ...

  7. spring 自定义schema 加载异常 White spaces are required between publicId and systemId.

    spring 项目启动报错 报错日志如下: Caused by: org.springframework.beans.factory.xml.XmlBeanDefinitionStoreExcepti ...

  8. Spring——自定义属性编辑器+Bean的生存范围+Bean的生命周期

    一.自定义属性编辑器(一个类): 步骤: 1.写一个类,这个类继承PropertyEditorSupport. 2.重写setAsText()方法. 3.在bean.xml文件中添加属性编辑器的bea ...

  9. Spring3.x企业应用开发实战-Spring+Hibernat架构分析

    1: 持久层设计 采用Spring注解方式省略了大量Hibernate ORM配置文件: BaseDAO减少DAO层代码量,只需要编写非通用型的持久层方法: 持久层提供分页支持: Hibernate ...

随机推荐

  1. (十二)c#Winform自定义控件-分页控件

    前提 入行已经7,8年了,一直想做一套漂亮点的自定义控件,于是就有了本系列文章. 开源地址:https://gitee.com/kwwwvagaa/net_winform_custom_control ...

  2. lumen错误 NotFoundHttpException in RoutesRequests.php line 442:

    解决:进入 public/index.PHP 将 $app->run(); 修改成下面的: $request = Illuminate\Http\Request::capture(); $app ...

  3. java多线程----悲观锁与乐观锁

    java多线程中悲观锁与乐观锁思想 一.悲观锁 总是假设最坏的情况,每次去拿数据的时候都认为别人会修改,所以每次在拿数据的时候都会上锁,这样别人想拿这个数据就会阻塞直到它拿到锁(共享资源每次只给一个线 ...

  4. PythonI/O进阶学习笔记_2.魔法函数

    前言: 本文一切观点和测试代码是在python3的基础上. Content: 1.什么是魔法函数,魔法函数__getitem__在python中应用. 2.python的数据模型和数据模型这种设计对p ...

  5. Postman系列五:Postman中电商网站cookie、token检验与参数传递实战

    一:Postman中电商网站cookie实战 Postman接口请求使用cookie两种方式: 1.直接在header(头域)中添加cookie,适用于已知请求cookie头域的情况 2.使用Post ...

  6. python 18 re模块

    目录 re 模块 1. 正则表达式 2. 匹配模式 3. 常用方法 re 模块 1. 正则表达式 \w 匹配字母(包含中文)或数字或下划线 \W 匹配非字母(包含中文)或数字或下划线 \s 匹配任意的 ...

  7. 移动端 rem单位做适配的 媒体查询节点

    @media screen and (min-width:300px){html,body,input{font-size:15px}}@media screen and (min-width:320 ...

  8. Java集合框架之List接口浅析

    Java集合框架之List接口浅析 一.List综述: 毫无疑问List接口位于java.util包下,继承自 Collection接口 存储元素的特点: 有序可重复(有序:即存进去是什么顺序,取出来 ...

  9. 【JVM从小白学成大佬】6.创建对象及对象的访问定位

    <JVM从小白学成大佬>系列推出到现在,收到了很多小伙伴的好评,也收到了一些小伙伴的建议,在此表示感谢. 有几个小伙伴提出了希望出一篇介绍对象的创建及访问,猿人谷向来是没有原则的,小伙们要 ...

  10. MySql优化相关概念的理解笔记

    MySQL架构 查询执行流程 查询执行的流程是怎样的: 连接1.1客户端发起一条Query请求,监听客户端的‘连接管理模块’接收请求1.2将请求转发到‘连接进/线程模块’1.3调用‘用户模块’来进行授 ...