主流框架都有自己的sping标签,比如dubbo
<dubbo:application name="provider" owner="wying">
<dubbo:parameter key="qos.enable" value="true"/>
<dubbo:parameter key="qos.accept.foreign.ip" value="false"/>
<dubbo:parameter key="qos.port" value="55555"/>
</dubbo:application>
为了更深入了解spring 于是查找资料实现了自己的自定义标签
项目结构
首先定义xsd文件,用于校验xml格式
wys.xsd
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<xsd:schema xmlns="http://www.wying.com.cn/schema/wys"
xmlns:xsd="http://www.w3.org/2001/XMLSchema" targetNamespace="http://www.wying.com.cn/schema/wys">
<xsd:element name="ptConfig">
<xsd:annotation>
<xsd:documentation><![CDATA[ The wys config ]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:ID">
<xsd:annotation>
<xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="name" type="xsd:string" use="required">
<xsd:annotation>
<xsd:documentation><![CDATA[ The application name. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="zookeeperUrl" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The zookeeperUrl url. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reserveV1" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The reserve value1]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reserveV2" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The reserve value2]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
<xsd:element name="service">
<xsd:annotation>
<xsd:documentation><![CDATA[ The wys service ]]></xsd:documentation>
</xsd:annotation>
<xsd:complexType>
<xsd:attribute name="id" type="xsd:ID">
<xsd:annotation>
<xsd:documentation><![CDATA[ The unique identifier for a bean. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="myRef" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The ref name. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="myClass" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The class name. ]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reserveV1" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The reserve value1]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
<xsd:attribute name="reserveV2" type="xsd:string">
<xsd:annotation>
<xsd:documentation><![CDATA[ The reserve value2]]></xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
</xsd:element>
</xsd:schema>
2.编写spring.handlers spring.schemas文件并放到项目classes META-INF目录下
spring.handlers配置自定义标签的注册类
http\://www.wying.com.cn/schema/wys=com.wying.spring.parse.WysNamespaceHandler
spring.schemas配置自定义标签xsd文件的路径
http\://www.wying.com.cn/schema/wys/wys.xsd=com/wying/spring/parse/wys.xsd
3.新建javabean存储ptConfig标签数据
PtConfigBean.java
package com.wying.spring.parse;
/**
* description:PtConfigBean
* date: 2020/7/24
* author: gaom
* version: 1.0
*/
public class PtConfigBean {
private static String id;
private static String name;
private static String zookeeperUrl;
private static String reserveV1;
private static String reserveV2;
public static String getId() {
return id;
}
public static void setId(String id) {
PtConfigBean.id = id;
}
public static String getName() {
return name;
}
public static void setName(String name) {
PtConfigBean.name = name;
}
public static String getZookeeperUrl() {
return zookeeperUrl;
}
public static void setZookeeperUrl(String zookeeperUrl) {
PtConfigBean.zookeeperUrl = zookeeperUrl;
}
public static String getReserveV1() {
return reserveV1;
}
public static void setReserveV1(String reserveV1) {
PtConfigBean.reserveV1 = reserveV1;
}
public static String getReserveV2() {
return reserveV2;
}
public static void setReserveV2(String reserveV2) {
PtConfigBean.reserveV2 = reserveV2;
}
public static void printPtConfig() {
System.out.println("PtConfigBean-->id:"+id+" name:"+ name+" zookeeperUrl:"+zookeeperUrl+" reserveV1:"+reserveV1+" reserveV2:"+reserveV2);
}
}
解析类PtConfigBeanDefinitionParser.java用于解析ptConfig标签数据
package com.wying.spring.parse;
import com.wying.dispatcher.exception.DispatcherException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
import java.util.concurrent.atomic.AtomicBoolean;
/**
* description:wys:ptConfig 标签解析
* date: 2020/7/24
* author: gaom
* version: 1.0
*/
public class PtConfigBeanDefinitionParser implements BeanDefinitionParser {
//配置标签只需要加载一次
private static AtomicBoolean isInitPtConfigBean = new AtomicBoolean(false);
private static final Logger logger= LoggerFactory.getLogger(PtConfigBeanDefinitionParser.class);
@Override
public BeanDefinition parse(Element element, ParserContext parserContext){
if(isInitPtConfigBean.get()){
logger.error ("Duplicate definition PtConfig at <wys:PtConfig, it allows appear once only.");
return null;
}
isInitPtConfigBean.set(true);
String id=element.getAttribute("id");
String name=element.getAttribute("name");
String zookeeperUrl=element.getAttribute("zookeeperUrl");
String reserveV1=element.getAttribute("reserveV1");
String reserveV2=element.getAttribute("reserveV2");
RootBeanDefinition def = new RootBeanDefinition();
def.setBeanClass(PtConfigBean.class);
PtConfigBean.setId(id);
PtConfigBean.setName(name);
PtConfigBean.setZookeeperUrl(zookeeperUrl);
PtConfigBean.setReserveV1(reserveV1);
PtConfigBean.setReserveV2(reserveV2);
parserContext.getRegistry().registerBeanDefinition("$ptConfig",def);
return def;
}
}
注册标签类WysNamespaceHandler.java 注册ptConfig
package com.wying.spring.parse;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* description:wys 自定义spring 标签
* date: 2020/7/24
* author: gaom
* version: 1.0
*/
public class WysNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("ptConfig",
new PtConfigBeanDefinitionParser());
}
}
4.spring配置文件application.xml使用自定义标签
beans标签引入wys
xmlns:wys="http://www.wying.com.cn/schema/wys"
http://www.wying.com.cn/schema/wys
http://www.wying.com.cn/schema/wys/wys.xsd
使用wys:ptConfig 设置属性
<wys:ptConfig id='wysConfigId' name="wysConfigName" zookeeperUrl="zookeeper://localhost:2181" reserveV1="reserveV1_testmessage" reserveV2="reserveV2_testmessage"/>
<?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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:wys="http://www.wying.com.cn/schema/wys"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.0.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.wying.com.cn/schema/wys
http://www.wying.com.cn/schema/wys/wys.xsd
">
<context:annotation-config/>
<context:component-scan base-package="com.wying"/>
<wys:ptConfig id='wysConfigId' name="wysConfigName" zookeeperUrl="zookeeper://localhost:2181" reserveV1="reserveV1_testmessage" reserveV2="reserveV2_testmessage"/>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="/WEB-INF/classes/property/PtConfig.properties" />
</bean>
<bean id="applicationContext"
class="org.apache.axis2.extensions.spring.receivers.ApplicationContextHolder" />
<bean id="ptWebSwevice" class="com.wying.ws.PtWebSwevice" />
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
<property name="url" value="${dataSource.url}" />
<property name="username" value="${dataSource.userName}" />
<property name="password" value="${dataSource.password}" />
<property name="filters" value="stat" />
<property name="maxActive" value="500" />
<property name="initialSize" value="10" />
<property name="maxWait" value="60000" />
<property name="minIdle" value="10" />
<property name="timeBetweenEvictionRunsMillis" value="60000" />
<property name="minEvictableIdleTimeMillis" value="300000" />
<property name="validationQuery" value="SELECT 'x' " />
<property name="testWhileIdle" value="true" />
<property name="testOnBorrow" value="false" />
<property name="testOnReturn" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="maxPoolPreparedStatementPerConnectionSize" value="100" />
<property name="removeAbandoned" value="true" />
<property name="removeAbandonedTimeout" value="1800" />
<property name="logAbandoned" value="true" />
</bean>
<!-- 配置session工厂 -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource"/>
</property>
<!-- <property name="mappingLocations">
<value>classpath:/work/com/bsoft/entity/*.hbm.xml</value>
</property> -->
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
</props>
</property>
</bean>
<!--2017/11/29 高盟 调用接口工具类 -->
<bean id="PtUtils" class="com.wying.utils.PtUtils">
</bean>
<!-- 事物管理配置 -->
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory"/>
</property>
</bean>
<bean id="transactionProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean" abstract="true">
<property name="transactionManager" ref="transactionManager"/>
<property name="transactionAttributes">
<props>
<prop key="add*">PROPAGATION_REQUIRED,-Exception</prop>
<prop key="modify*">PROPAGATION_REQUIRED,+MyException</prop>
<prop key="del*">PROPAGATION_REQUIRED</prop>
<prop key="*">READONLY</prop>
</props>
</property>
</bean>
</beans>
5.启动程序测试PtConfigBean是否有xml标签配置的属性
2种方式都获取到,可以根据自己的业务使用自定义标签设置的属性了
上述使用自定义标签实现了为我们的框架定义配置信息
类似于duboo的
我们想定义自己的service了?例如dubbo服务发布配置
1.xsd文件 service节点加好,
2.新建 ServiceBeanDefinitionParser 自定义service解析类
package com.wying.spring.parse;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.support.RootBeanDefinition;
import org.springframework.beans.factory.xml.BeanDefinitionParser;
import org.springframework.beans.factory.xml.ParserContext;
import org.w3c.dom.Element;
/**
* description:自定义service解析类
* date: 2020/8/21
* author: gaom
* version: 1.0
*/
public class ServiceBeanDefinitionParser implements BeanDefinitionParser {
private static final Logger logger= LoggerFactory.getLogger(ServiceBeanDefinitionParser.class);
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
//解析<wys:service>标签
String id = element.getAttribute("id");
String myRef = element.getAttribute("myRef");
String myClass = element.getAttribute("myClass");
String reserveV1 = element.getAttribute("reserveV1");
String reserveV2 = element.getAttribute("reserveV2");
logger.info("BeanDefinition id:"+id+" myRef:"+myRef+" myClass:"+myClass);
if(StringUtils.isEmpty(id)){
logger.error("<wys:service> id must not null");
return null;
}
if(StringUtils.isEmpty(myRef)&&StringUtils.isEmpty(myClass)){
//无效配置
logger.error("<wys:service> id:"+id+" --> myRef or myClass one must not be empty");
}
if(!StringUtils.isEmpty(myClass)){
//bean对应的类
RootBeanDefinition def = new RootBeanDefinition();
def.setBeanClassName(myClass);
parserContext.getRegistry().registerBeanDefinition(id, def);
}
if(!StringUtils.isEmpty(myRef)){
//引用其他bean 暂未实现
/* RootBeanDefinition def = new RootBeanDefinition();
def.setBeanClassName("");
parserContext.getRegistry().registerBeanDefinition(id, def);
RuntimeBeanReference reference = new RuntimeBeanReference(id);*/
}
return null;
}
}
3.WysNamespaceHandler注册解析类
package com.wying.spring.parse;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
/**
* description:wys 自定义spring 标签
* date: 2020/7/24
* author: gaom
* version: 1.0
*/
public class WysNamespaceHandler extends NamespaceHandlerSupport {
@Override
public void init() {
registerBeanDefinitionParser("ptConfig",
new PtConfigBeanDefinitionParser());
registerBeanDefinitionParser("service",
new ServiceBeanDefinitionParser());
}
}
4.新建测试service
WysHelloService
package com.wying.service;
import com.wying.dispatcher.exception.DispatcherException;
import com.wying.dispatcher.service.BaseService;
import org.hibernate.Session;
import java.util.Map;
/**
* description:
* date: 2020/8/21
* author: gaom
* version: 1.0
*/
public class WysHelloService implements BaseService {
public void sayHello(){
System.out.println("=========hello world!=========");
}
@Override
public void execute(Map<String, Object> reqData, Map<String, Object> resData, Session session) throws DispatcherException {
System.out.println("=========自定义spring bean success =========");
}
}
spring配置文件引用
<wys:ptConfig id='wysConfigId' name="wysConfigName" zookeeperUrl="zookeeper://localhost:2181" reserveV1="reserveV1_testmessage" reserveV2="reserveV2_testmessage"/>
<wys:service id='wysHelloService' myClass="com.wying.service.WysHelloService" myRef="" reserveV1="" reserveV2=""></wys:service>
5.启动程序
获取wysHelloService,调用sayHello方法测试成功
现在我封装的框架可以使用自己的标签配置bean使用了,不过使用spring默认的bean可以使用注解,也支持xml
我这个还没实现,必须通过xml配置bean
<wys:service id='wysHelloService' myClass="com.wying.service.WysHelloService" myRef="" reserveV1="" reserveV2=""></wys:service>