擴充 Spring XML 配置,支援自定義命名空間 std,讓開發者能寫:
<std:annotation-endpoint package="com.example.ws"/>
自動掃描 @Endpoint 註解並發布 WebService(基於 CXF)。
src/main/resources/
├── META-INF/
│ ├── spring.schemas
│ ├── spring.handlers
│ └── schema/
│ └── stdws-1.0.xsd
└── com/codestd/spring/cxf/annotation/
├── Endpoint.java
└── config/
├── StdNamespaceHandler.java
└── AnnotationEndpointBeanDefinitionParser.java
src/main/resources/META-INF/schema/stdws-1.0.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns="https://www.codestd.com/schema/std/ws"
xmlns:xsd="https://www.w3.org/2001/XMLSchema"
xmlns:beans="https://www.springframework.org/schema/beans"
targetNamespace="https://www.codestd.com/schema/std/ws"
elementFormDefault="qualified" attributeFormDefault="unqualified">
<xsd:import namespace="https://www.springframework.org/schema/beans"/>
<xsd:element name="annotation-endpoint">
<xsd:complexType>
<xsd:complexContent>
<xsd:extension base="beans:identifiedType">
<xsd:attribute name="name" type="xsd:string" use="optional"/>
<xsd:attribute name="package" type="xsd:string" use="optional"/>
</xsd:extension>
</xsd:complexContent>
</xsd:complexType>
</xsd:element>
</xsd:schema>
spring.schemas(關鍵:讓 Spring 解析 XML 時離線載入 XSD,避免網路請求)
http\://www.codestd.com/schema/std/ws/stdws-1.0.xsd=META-INF/schema/stdws-1.0.xsd
spring.handlers
http\://www.codestd.com/schema/std/ws=com.codestd.spring.cxf.config.StdNamespaceHandler
public class StdNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("annotation-endpoint", new AnnotationEndpointBeanDefinitionParser());
}
}
public class AnnotationEndpointBeanDefinitionParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
String packageToScan = element.getAttribute("package");
String beanName = element.getAttribute("name");
// 1. 註冊 ComponentScanBeanDefinitionParser 掃描 @Endpoint
RootBeanDefinition scanDef = new RootBeanDefinition(ClassPathBeanDefinitionScanner.class);
scanDef.getConstructorArgumentValues().addGenericArgumentValue(packageToScan);
// 設定 includeFilters 只掃描 @Endpoint
// ... 省略細節
// 2. 註冊 CXF Endpoint 發布邏輯(簡化示意)
RootBeanDefinition endpointDef = new RootBeanDefinition(EndpointPublisher.class);
endpointDef.getPropertyValues().add("packageToScan", packageToScan);
parserContext.getRegistry().registerBeanDefinition(beanName, endpointDef);
return null;
}
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Endpoint {
String id(); // Spring Bean ID
String address(); // 發布位址,如 /services/MyService
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="https://www.springframework.org/schema/beans"
xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
xmlns:std="https://www.codestd.com/schema/std/ws"
xsi:schemaLocation="
https://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans-4.0.xsd
https://www.codestd.com/schema/std/ws https://www.codestd.com/schema/std/ws/stdws-1.0.xsd">
<std:annotation-endpoint package="com.codestd.spring.cxf.ws"/>
</beans>
stdws-1.0.xsdhttps://www.codestd.com/schema/std/ws/stdws-1.0.xsd即可享有 XML 內容提示與驗證。
| 檔案 | 作用 |
|---|---|
| XSD | 定義元素結構、屬性、約束 |
| spring.schemas | 命名空間 URI → 本地 XSD 路徑映射 |
| spring.handlers | 命名空間 URI → NamespaceHandler 類別映射 |
| NamespaceHandler | 註冊各元素的 BeanDefinitionParser |
| BeanDefinitionParser | 解析 XML 元素,轉換為 Spring BeanDefinition |
Spring 自定義 Schema 擴充讓 XML 配置具備領域語言(DSL)表達力,封裝複雜的 Bean 組裝邏輯。本文示範的「註解掃描 + CXF 發布」僅是冰山一角;實務中可擴充至資料源配置、快取註解、安全規則等任何重複性基礎設施配置,顯著提升團隊開發效率與配置可讀性。