linux怎么查看本机内存大小
272
2022-12-05
spring拓展之如何定义自己的namespace
目录spring拓展 定义自己的namespace1.查看源码认识spring是怎么加载xml配置的2.定义自己的namespacespring-namespace实现自定义标签类1.配置java Bean2.编写xsd文件3.编写BeanDefinationParse标签解析类4.编写调用标签解析类的NamespaceHandler类5.编写spring.handlers和spring.schemas以供spring读取6.打包7.在其他项目中使用
spring拓展 定义自己的namespace
1.查看源码认识spring是怎么加载xml配置的
1.1 spring是怎么创建对象的?
查看spring beanFactory的继承关系
通过查看源码可以得知,BeanFactory 中的对象创建是实际是根据RootBeanDefinition创建的, 在AbstractAutowireCapableBeanFactory中有具体的实现,包括创建实例,
利用Spring拓展
java的内省实现BeanWrapperImpl,创建对象的包装类,使用反射给对象填充属性,并实现依赖注入DI 。具体可以自行参阅源码。
public abstract class AbstractBeanFactory extends FactoryBeanRegistrySupport implements ConfigurableBeanFactory {
.....
protected abstract Object createBean(String beanName, RootBeanDefinition mbd, Object[] args)
throws BeanCreationException;
}
而RootBeanDefination定义的是什么呢?查看AbstractBeanDefination类。
可以看到这里就是Spring对对象属性的封装,包括类名,属性,加载策略等等,其实也就是我们在xml里 配置的对象。
1.2 spring是怎么将xml里配置的对象读到BeanFactory中的?
在查看spring容器的源码时,得知spring 是使用 org.springframework.beans.factory.xml.XmlBeanDefinitionReader 进行xml解析的
public class XmlBeanDefinitionReader extends AbstractBeanDefinitionReader {
.....
protected int doLoadBeanDefinitions(InputSIgZBlOHource inputSource, Resource resource)
throws BeanDefinitionStoreException {
try {
//读取xml
Document doc = doLoadDocument(inputSource, resource);
//解析并注册xml中定义的BeanDefination
return registerBeanDefinitions(doc, resource);
}
catch (BeanDefinitionStoreException ex) {
xxx
}
}
.....
}
接下来查看对dom 解析部分的源码
public class DefaultBeanDefinitionDocumentReader implements BeanDefinitionDocumentReader {
@Override
public void registerBeanDefinitions(Document doc, XmlReaderContext readerContext) {
this.readerContext = readerContext;
logger.debug("Loading bean definitions");
Element root = doc.getDocumentElement();
doRegisterBeanDefinitions(root);
}
protected void doRegisterBeanDefinitions(Element root) {
//为了实现进行递归解析
BeanDefinitionParserDelegate parent = this.delegate;
this.delegate = createDelegate(getReaderContext(), root, parent);
if (this.delegate.isDefaultNamespace(root)) {
//对profile的支持
String profileSpec = root.getAttribute(PROFILE_ATTRIBUTE);
if (StringUtils.hasText(profileSpec)) {
String[] specifiedProfiles = StringUtils.tokenizeToStringArray(
profileSpec, BeanDefinitionParserDelegate.MULTI_VALUE_ATTRIBUTE_DELIMITERS);
if (!getReaderContext().getEnvironment().acceptsProfiles(specifiedProfiles)) {
return;
}
}
}
preProcessXml(root);
//开始解析dom树
parseBeanDefinitions(root, this.delegate);
postProcessXml(root);
this.delegate = parent;
}
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)) {
//spring的基础命名元素解析(import、bean、beans、alias)其中在
//beans嵌套时会进行递归解析
parseDefaultElement(ele, delegate);
}
else {
//拓展元素解析
delegate.parseCustomElement(ele);
}
}
}
}
else {
delegate.parseCustomElement(root);
}
}
}
查看spring是怎么实现拓展元素的解析的
public class BeanDefinitionParserDelegate {
public BeanDefinition parseCustomElement(Element ele) {
return parseCustomElement(ele, null);
}
public BeanDefinition parseCustomElement(Element ele, BeanDefinition containingBd) {
//获取当前节点命名空间URI
String namespaceUri = getNamespaceURI(ele);
//根据命名空间解析到自定义的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;
}
//使用拓展的Handler对当前节点进行解析
return handler.parse(ele, new ParserContext(this.readerContext, this, containingBd));
}
}
其中NamespaceHandlerResolver 会去查找当前项目中classpath 下的META-INF目录下所有文件名为 spring.handlers配置文件,定位到自定义namespace的解析器实现类。
其中在namespace 的处理器中可以通过进行BeanDefination的注册,注册过的BeanDefination会用来给BeanFactory创建对象使用,将解析好的BeanDefination注册到parserContext.getRegistry()中即可。其实DefaultListableBeanFhttp://actory 就是一个BeanDefinitionRegistry。
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
....
parserContext.getRegistry().registerBeanDefinition(beanName, mbd);
}
2.定义自己的namespace
2.1 定义schema约束xsd文件
将自定义的xsd文件放到项目的 META-INF 目录下。
xmlns:xsd="http://w3.org/2001/XMLSchema" xmlns:beans="http://springframework.org/schema/beans" xmlns:tool="http://springframework.org/schema/tool" targetNamespace="http://xxx.xxx.com/schema/myns">
xmlns:xsd="http://w3.org/2001/XMLSchema"
xmlns:beans="http://springframework.org/schema/beans"
xmlns:tool="http://springframework.org/schema/tool"
targetNamespace="http://xxx.xxx.com/schema/myns">
更多xsd写法可以参阅xml的相关资料。
2.2创建自定义namespace的NamespaceHandler
使用NamespaceHandlerSupport来实现我们定义的NamespaceHandler。在init时去提供具体的标签的 解析器。
BeanDefinitionParser
public class MybeanParser implements BeanDefinitionParser {
@Override
public BeanDefinition parse(Element element, ParserContext parserContext) {
RootBeanDefinition mbd = new RootBeanDefinition();
mbd.setBeanClassName(element.getAttribute("class"));
String beanName = element.getAttribute("id");
MutablePropertyValues mutablePropertyValues = new MutablePropertyValues();
mutablePropertyValues.add("name", element.getAttribute("name"));
mbd.setPropertyValues(mutablePropertyValues);
parserContext.getRegistry().registerBeanDefinition(beanName, mbd);
return mbd;
}
}
实现自定义的NamespaceHandler
public class MynsNameSpaceHandler extends NamespaceHandlerSupport{
@Override
public void init() {
registerBeanDefinitionParser("mybean", new MybeanParser());
}
}
这里的mybean是myns namespace下的元素标签的具体的解析实现
如:
2.3配置自定义的NamespaceHandler映射
在META-INF下创建文件 spring.handlers
http\://xxx.xxx.com/schema/myns=com.xxx.MynsNameSpaceHandler
2.4使用自定义的Namespace
xmlns:xsi="http://w3.org/2001/XMLSchema-instance" xmlns:myns="http://xxx.xxx.com/schema/myns" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://xxx.xxx.com/schema/myns http://xxx.xxx.com/schema/myns.xsd ">
xmlns:xsi="http://w3.org/2001/XMLSchema-instance"
xmlns:myns="http://xxx.xxx.com/schema/myns"
xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd
http://xxx.xxx.com/schema/myns http://xxx.xxx.com/schema/myns.xsd
">
2.5测试
public class MybeanNamespaceTestCase {
@SuppressWarnings("resource")
@Test
public void testGetBean(){
ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"myapp.xml"},false);
ac.setValidating(false);
ac.refresh();
People bean = ac.getBean("mybean123",People.class);
System.out.println(bean.getName());
}
}
这里设置ac.setValidating(false); 是因为如果开启xml约束检查,需要配置schema的位置,
也是在META-INF 下新建spring.schemas
并加入:
http\://xxx.xxx.com/schema/myns.xsd=META-INF/myns.xsd
这样spring 在xml解析时会调用org.springframework.beans.factory.xml.PluggableSchemaResolver
进行获取schema文件进行约束检查,
这样配置完毕后就可以ac.setValidating(true);啦,如果文件内容不符合规范,会启动时抛出异常。
此外,如果想要在使用过程开发工具能够像使用spring 自身的一些配置时有提升功能,可以将schema文件
上传到文件服务器上,能够通过http 访问到xsi:schemaLocation的地方,或者配置开发工具中的xml 约束映射,将地址映射到本 地磁盘中,这样就能
spring-namespace实现自定义标签类
介绍如何通过spring namespace的方式进行bean的配置
最终要达到的目的如下:
xmlns:xsi="http://w3.org/2001/XMLSchema-instance" xmlns:user="http://wuxueyou.cn/schema/user" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://wuxueyou.cn/schema/user http://wuxueyou.cn/schema/user.xsd">
xmlns:xsi="http://w3.org/2001/XMLSchema-instance"
xmlns:user="http://wuxueyou.cn/schema/user"
xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd
http://wuxueyou.cn/schema/user http://wuxueyou.cn/schema/user.xsd">
好,下面上货。
1.配置java bean
2.编写xsd文件
3.编写BeanDefinationParse标签解析类
4.编写调用标签解析类的NamespaceHandler类
5.编写spring.handlers和spring.schemas供spring读取
6.在spring中使用
目录结构
1.配置java Bean
package com.xueyou;
public class User {
private int userId;
private String name;
public User() {
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "User{" +
"userId='" + userId + '\'' +
", name='" + name + '\'' +
'}';
}
}
2.编写xsd文件
xmlns:xsd="http://w3.org/2001/XMLSchema" xmlns:beans="http://springframework.org/schema/beans" targetNamespace="http://wuxueyou.cn/schema/user" elementFormDefault="qualified"> schemaLocation="http://springframework.org/schema/beans/spring-beans.xsd"/>
xmlns:xsd="http://w3.org/2001/XMLSchema"
xmlns:beans="http://springframework.org/schema/beans"
targetNamespace="http://wuxueyou.cn/schema/user"
elementFormDefault="qualified">
schemaLocation="http://springframework.org/schema/beans/spring-beans.xsd"/>
schemaLocation="http://springframework.org/schema/beans/spring-beans.xsd"/>
3.编写BeanDefinationParse标签解析类
package com.xueyou.parser;
import com.xueyou.User;
import org.springframework.beans.factory.support.BeanDefinitionBuilder;
import org.springframework.beans.factory.xml.AbstractSimpleBeanDefinitionParser;
import org.w3c.dom.Element;
public class UserDefinationParser extends AbstractSimpleBeanDefinitionParser {
@Override
protected Class> getBeanClass(Element element) {
return User.class;
}
@Override
protected void doParse(Element element, BeanDefinitionBuilder builder) {
int userId = Integer.valueOf(element.getAttribute("userId"), 0);
String name = element.getAttribute("name");
builder.addPropertyValue("userId", userId);
builder.addPropertyValue("name", name);
}
}
4.编写调用标签解析类的NamespaceHandler类
package com.xueyou.handler;
import com.xueyou.parser.UserDefinationParser;
import org.springframework.beans.factory.xml.NamespaceHandlerSupport;
public class UserNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
registerBeanDefinitionParser("self-user", new UserDefinationParser());
}
}
5.编写spring.handlers和spring.schemas以供spring读取
spring.handlers
http\://wuxueyou.cn/schema/user=com.xueyou.handler.UserNamespaceHandler
spring.schemas
http\://wuxueyou.cn/schema/user.xsd=namespace/user.xsd
6.打包
首先把刚才的打成一个jar包,需要注意在maven的plugin中添加如下内容, 这个shade插件能够合并指定的内容,比如spring.schema等等
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
implementation="org.apache.maven.plugins.shade.resource.AppendingTransformer">
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
implementation="org.apache.maven.plugins.shade.resource.ManifestResourceTransformer">
7.在其他项目中使用
在一个web项目中使用这个类
xmlns:xsi="http://w3.org/2001/XMLSchema-instance" xmlns:user="http://wuxueyou.cn/schema/user" xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd http://wuxueyou.cn/schema/user http://wuxueyou.cn/schema/user.xsd">
xmlns:xsi="http://w3.org/2001/XMLSchema-instance"
xmlns:user="http://wuxueyou.cn/schema/user"
xsi:schemaLocation="http://springframework.org/schema/beans http://springframework.org/schema/beans/spring-beans.xsd
http://wuxueyou.cn/schema/user http://wuxueyou.cn/schema/user.xsd">
在controller中进行测试
package com.example.demo.controller;
import com.xueyou.User;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
@RestController
@RequestMapping("/namespacetest")
public class NamespaceController {
@Resource(name = "user2")
private User user;
@RequestMapping("/user")
public User namespacetest() {
return user;
}
}
运行结果:
运行结果
最终,我们可以使用spring-namespace对bean进行配置了。这样比
版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。
发表评论
暂时没有评论,来抢沙发吧~