解析bean标签子元素一
完成bean标签属性解析后,会进行子元素的解析。
本篇先看meta、lookup-metod、replace-method三个子元素是如何解析的。
meta :元数据。当需要使用里面的信息时可以通过 key 获取。
meta 所声明的 key 并不会在 Bean 中体现,只是一个额外的声明,当我们需要使用里面的信息时,通过调用 BeanDefinition 的 getAttribute(String name) 方法来获取。
通过BeanDefinitionParserDelegate.parseMetaElements()来完成对meta子元素的解析。
| 12
 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中。
| 12
 3
 
 | public void addMetadataAttribute(BeanMetadataAttribute attribute) {super.setAttribute(attribute.getName(), attribute);
 }
 
 | 
BeanMetadataAttributeAccessor 继承AttributeAccessorSupport类。AttributeAccessorSupport类实现了AttributeAccessor接口,如上篇提到,该接口提供了对属性的获取、设置、删除。
| 12
 3
 4
 5
 6
 7
 8
 9
 10
 
 | @Overridepublic 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类。
| 12
 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,一个替代原有方法。
实例
| 12
 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子元素的解析。
| 12
 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,一个替代原有方法。
实例
| 12
 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标签:
| 12
 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);
 }
 }
 }
 
 |