spring 源码解读之标签解析与bean的注册
http://www.springframework.org/schema/p,获取到这个命名空间的处理类NamespaceHandler
命名空间的处理类特点都实现了NamespaceHandler接口
NamespaceHandler接口有三个方法:
init 完成标签元素解析类的注册
parse 解析
decorate 装饰BeanDefinitionHolder
4.在spring.handlers文件中,发现p标签和c标签的实现类
http://www.springframework.org/schema/c=org.springframework.beans.factory.xml.SimpleConstructorNamespaceHandler
http://www.springframework.org/schema/p=org.springframework.beans.factory.xml.SimplePropertyNamespaceHandler
5.看p标签处理,实现类SimplePropertyNamespaceHandler
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
String propertyName = parserContext.getDelegate().getLocalName(attr);
String propertyValue = attr.getValue();
MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();
if (pvs.contains(propertyName)) {
parserContext.getReaderContext().error("Property '" + propertyName + "' is already defined using " +
"both and inline syntax. Only one approach may be used per property.", attr);
}
if (propertyName.endsWith(REF_SUFFIX)) {
propertyName = propertyName.substring(0, propertyName.length() - REF_SUFFIX.length());
pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue));
}
else {
pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue);
}
}
return definition;
}
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
String propertyName = parserContext.getDelegate().getLocalName(attr);
String propertyValue = attr.getValue();
MutablePropertyValues pvs = definition.getBeanDefinition().getPropertyValues();
if (pvs.contains(propertyName)) {
parserContext.getReaderContext().error("Property '" + propertyName + "' is already defined using " +
"both and inline syntax. Only one approach may be used per property.", attr);
}
if (propertyName.endsWith(REF_SUFFIX)) {
propertyName = propertyName.substring(0, propertyName.length() - REF_SUFFIX.length());
pvs.add(Conventions.attributeNameToPropertyName(propertyName), new RuntimeBeanReference(propertyValue));
}
else {
pvs.add(Conventions.attributeNameToPropertyName(propertyName), propertyValue);
}
}
return definition;
} 可以看出解析出propertyName与propertyValue 然后封装成PropertyValue,添加到MutablePropertyValues中
6.看c标签解析,实现类SimpleConstructorNamespaceHandler
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
if (node instanceof Attr) {
Attr attr = (Attr) node;
String argName = StringUtils.trimWhitespace(parserContext.getDelegate().getLocalName(attr));
String argValue = StringUtils.trimWhitespace(attr.getValue());
ConstructorArgumentValues cvs = definition.getBeanDefinition().getConstructorArgumentValues();
boolean ref = false;
// handle -ref arguments
if (argName.endsWith(REF_SUFFIX)) {
ref = true;
argName = argName.substring(0, argName.length() - REF_SUFFIX.length());
}
ValueHolder valueHolder = new ValueHolder(ref ? new RuntimeBeanReference(argValue) : argValue);
valueHolder.setSource(parserContext.getReaderContext().extractSource(attr));
// handle "escaped"/"_" arguments
if (argName.startsWith(DELIMITER_PREFIX)) {
String arg = argName.substring(1).trim();
// fast default check
if (!StringUtils.hasText(arg)) {
cvs.addGenericArgumentValue(valueHolder);
}
// assume an index otherwise
else {
int index = -1;
try {
index = Integer.parseInt(arg);
}
catch (NumberFormatException ex) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' specifies an invalid integer", attr);
}
if (index < 0) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' specifies a negative index", attr);
}
if (cvs.hasIndexedArgumentValue(index)) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' with index "+ index+" already defined using ." +
" Only one approach may be used per argument.", attr);
}
cvs.addIndexedArgumentValue(index, valueHolder);
}
}
// no escaping -> ctr name
else {
String name = Conventions.attributeNameToPropertyName(argName);
if (containsArgWithName(name, cvs)) {
parserContext.getReaderContext().error(
"Constructor argument '" + argName + "' already defined using ." +
" Only one approach may be used per argument.", attr);
}
valueHolder.setName(Conventions.attributeNameToPropertyName(argName));
cvs.addGenericArgumentValue(valueHolder);
}
}
return definition;
}
同样它的实现逻辑与constructor-arg标签的解析类似
http://www.springframework.org/schema/context=org.springframework.context.config.ContextNamespaceHandler
http://www.test.com/schema/mytags.xsd=META-INF/mytags.xsd
2.
<?xml version="1.0" encoding="UTF-8"?>
2.
<?xml version="1.0" encoding="UTF-8"?>
3.spring.handlers定义标签解析类
http://www.test.com/schema/mytags=com.test.tag.TagsNamespaceHandler
4.
public class TagsNamespaceHandler extends NamespaceHandlerSupport {
public void init() {
this.registerBeanDefinitionParser("redis",
new RedisBeanDifinitionParser());
}
@Override
public BeanDefinitionHolder decorate(Node node, BeanDefinitionHolder definition, ParserContext parserContext) {
return super.decorate(node, definition, parserContext);
}
}
public class RedisBeanDifinitionParser extends
AbstractSingleBeanDefinitionParser {
protected Class<?> getBeanClass(Element element) {
return Jedis.class;
}
protected void doParse(Element element, BeanDefinitionBuilder builder) {
String ip = element.getAttribute("ip");
String port = element.getAttribute("port");
builder.addConstructorArgValue(ip);
builder.addConstructorArgValue(Integer.parseInt(port));
}
}
总结
1.spring标签解析分为默认标签解析与自定义标签解析
2.默认标签解析最常见的就是bean标签,次之为import标签等
3.bean标签解析先构建GenericBeanDefinition,然后将标签上的元素与子标签解析出来,为GenericBeanDefinition里的属性赋值
bean标签常见的元素有id,class,init-method,factory-bean,factory-method,lazy-init,depends-on,destroy-method,scope,primary等等
子标签有constructor-arg,property,lookup-method,replaced-method
4.GenericBeanDefinition中MutablePropertyValues,MethodOverrides,ConstructorArgumentValues,attributes三个重要的属性对应着property标签,lookup-method与replaced-method标签,constructor-arg标签,meta标签的解析与封装
5.创建完GenericBeanDefinition后,接着就是注册,注册时2个比较重要的容器是beanDefinitionMap,beanDefinitionNames
6.自定义标签解析首先是通过spring.handlers文件找到namespaceUri对应的解析类NameSpaceHandler
7.该解析类中有3个重要的方法
init 完成标签元素解析类的注册
parse 解析
decorate 装饰BeanDefinitionHolder
8.解析首先是创建注解扫描器
9.注解扫描器默认扫描的是类上包含@Component,@Service注解的类,并对其一些注解的支持,一并封装到ScannedGenericBeanDefinition中
10.完成@Component,@Service注解类的注册
11.完成默认标签与自定义标签解析后,spring注册了几个常见的BeanPostProcessor,如下
ConfigurationClassPostProcessor,AutowiredAnnotationBeanPostProcessor,CommonAnnotationBeanPostProcessor,
PersistenceAnnotationBeanPostProcessor
ConfigurationClassPostProcessor对@Configuration,@Component,@ComponentScan,@Import,@ImportResource,@Bean注解的支撑
AutowiredAnnotationBeanPostProcessor对@Autowired,@Value注解的支撑
CommonAnnotationBeanPostProcessor对@PostConstruct,@PreDestroy,@Resource注解的支撑
PersistenceAnnotationBeanPostProcessor对JPA的支撑