解析bean标签子元素一
完成bean
标签属性解析后,会进行子元素的解析。
本篇先看meta
、lookup-metod
、replace-method
三个子元素是如何解析的。
meta :元数据。当需要使用里面的信息时可以通过 key 获取。
meta 所声明的 key 并不会在 Bean 中体现,只是一个额外的声明,当我们需要使用里面的信息时,通过调用 BeanDefinition 的 getAttribute(String name)
方法来获取。
通过BeanDefinitionParserDelegate.parseMetaElements()
来完成对meta子元素的解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public void parseMetaElements(Element ele, BeanMetadataAttributeAccessor attributeAccessor) { NodeList nl = ele.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, META_ELEMENT)) { Element metaElement = (Element) node; String key = metaElement.getAttribute(KEY_ATTRIBUTE); String value = metaElement.getAttribute(VALUE_ATTRIBUTE); BeanMetadataAttribute attribute = new BeanMetadataAttribute(key, value); attribute.setSource(extractSource(metaElement)); attributeAccessor.addMetadataAttribute(attribute); } } }
|
解析过程:获取相应的 key - value 构建BeanMetadataAttribute
对象,然后调用 BeanMetadataAttributeAccessor.addMetadataAttribute(BeanMetadataAttribute)
方法,添加 BeanMetadataAttribute
加入到AbstractBeanDefinition
中。
AbstractBeanDefinition
继承BeanMetadataAttributeAccessor
类。调用parseMetaElements()上送的就是AbstractBeanDefinition。
调用 BeanMetadataAttributeAccessor.addMetadataAttribute(BeanMetadataAttribute)
方法,添加 BeanMetadataAttribute
加入到AbstractBeanDefinition
中。
1 2 3
| public void addMetadataAttribute(BeanMetadataAttribute attribute) { super.setAttribute(attribute.getName(), attribute); }
|
BeanMetadataAttributeAccessor
继承AttributeAccessorSupport
类。AttributeAccessorSupport
类实现了AttributeAccessor
接口,如上篇提到,该接口提供了对属性的获取、设置、删除。
1 2 3 4 5 6 7 8 9 10
| @Override public void setAttribute(String name, @Nullable Object value) { Assert.notNull(name, "Name must not be null"); if (value != null) { this.attributes.put(name, value); } else { removeAttribute(name); } }
|
getAttribute()
方法
设置元数据后,则可以通过调用 BeanDefinition 的 .getAttribute(String name)
方法来获取属性。
AbstractBeanDefinition
继承BeanMetadataAttributeAccessor
类。BeanMetadataAttributeAccessor
继承AttributeAccessorSupport
类。
1 2 3 4 5 6 7 8 9
|
private final Map<String, Object> attributes = new LinkedHashMap<>(); @Override @Nullable public Object getAttribute(String name) { Assert.notNull(name, "Name must not be null"); return this.attributes.get(name); }
|
lookup-method
子元素
依赖注入-方法注入,使用标签。和类似,一个注入bean,一个替代原有方法。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47
| public class Fruit { public Fruit() { System.out.println("I got Fruit"); } }
public class Apple extends Fruit { public Apple() { System.out.println("I got a fresh apple"); } }
public class Bananer extends Fruit { public Bananer () { System.out.println("I got a fresh bananer"); } }
public abstract class FruitPlate{ protected abstract Fruit getFruit(); }
<bean id="apple" class="com.jievhaha.test.Apple" scope="prototype"/> <bean id="bananer" class="com.jievhaha.test.Bananer " scope="prototype"/> <bean id="fruitPlate1" class="com.jievhaha.test.FruitPlate"> <lookup-method name="getFruit" bean="apple"/> </bean> <bean id="fruitPlate2" class="com.jievhaha.test.FruitPlate"> <lookup-method name="getFruit" bean="bananer"/> </bean> public static void main(String[] args) { ApplicationContext app = new ClassPathXmlApplicationContext("classpath:resource/applicationContext.xml");
FruitPlate fp1= (FruitPlate)app.getBean("fruitPlate1"); FruitPlate fp2 = (FruitPlate)app.getBean("fruitPlate2");
fp1.getFruit(); fp2.getFruit(); }
|
lookup-method为抽象方法指定返回类型,应用了CGLIB(动态代理)类库。
parseLookupOverrideSubElements()
方法
通过BeanDefinitionParserDelegate.parseLookupOverrideSubElements()
来完成对lookup-method子元素的解析。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| public void parseLookupOverrideSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, LOOKUP_METHOD_ELEMENT)) { Element ele = (Element) node; String methodName = ele.getAttribute(NAME_ATTRIBUTE); String beanRef = ele.getAttribute(BEAN_ELEMENT); LookupOverride override = new LookupOverride(methodName, beanRef); override.setSource(extractSource(ele)); overrides.addOverride(override); } } }
|
解析过程和 meta
子元素没有多大区别,同样是解析 methodName、beanRef 构造一个 LookupOverride 对象,然后记录到 AbstractBeanDefinition 中的 methodOverrides
属性中。
replace-method()
方法
replaced-method :可以在运行时调用新的方法替换现有的方法,还能动态的更新原有方法的逻辑。
该标签使用方法和lookup-method
标签大同小异,不过替代原有方法的类需要实现org.springframework.beans.factory.support.MethodReplacer
接口,一个注入bean,一个替代原有方法。
实例
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public class Method { public void display(){ System.out.println("我是原始方法"); } }
public class MethodReplace implements MethodReplacer { @Override public Object reimplement(Object obj, Method method, Object[] args) throws Throwable { System.out.println("我是替换方法"); return null; } }
<bean id="methodReplace" class="com.jievhaha.test.MethodReplace"/> <bean id="method" class="com.jievhaha.test.Method"> <replaced-method name="display" replacer="methodReplace"/> </bean>
public static void main(String[] args) { ApplicationContext context = new ClassPathXmlApplicationContext("classpath:spring.xml"); Method method = (Method) context.getBean("method"); method.display(); }
|
parseReplacedMethodSubElements()
方法
通过 BeanDefinitionParserDelegate.parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides)
来解析replace-method标签:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| public void parseReplacedMethodSubElements(Element beanEle, MethodOverrides overrides) { NodeList nl = beanEle.getChildNodes(); for (int i = 0; i < nl.getLength(); i++) { Node node = nl.item(i); if (isCandidateElement(node) && nodeNameEquals(node, REPLACED_METHOD_ELEMENT)) { Element replacedMethodEle = (Element) node; String name = replacedMethodEle.getAttribute(NAME_ATTRIBUTE); String callback = replacedMethodEle.getAttribute(REPLACER_ATTRIBUTE); ReplaceOverride replaceOverride = new ReplaceOverride(name, callback); List<Element> argTypeEles = DomUtils.getChildElementsByTagName(replacedMethodEle, ARG_TYPE_ELEMENT); for (Element argTypeEle : argTypeEles) { String match = argTypeEle.getAttribute(ARG_TYPE_MATCH_ATTRIBUTE); match = (StringUtils.hasText(match) ? match : DomUtils.getTextValue(argTypeEle)); if (StringUtils.hasText(match)) { replaceOverride.addTypeIdentifier(match); } } replaceOverride.setSource(extractSource(replacedMethodEle)); overrides.addOverride(replaceOverride); } } }
|