zoukankan      html  css  js  c++  java
  • spring成神之路第十三篇:使用继承简化bean配置(abstract & parent)

    先来看一个案例

    ServiceA.java

    package com.javacode2018.lesson001.demo12;
    
    public class ServiceA {
    }

    ServiceB.java

    package com.javacode2018.lesson001.demo12;
    
    public class ServiceB {
        private String name;
        private ServiceA serviceA;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public ServiceA getServiceA() {
            return serviceA;
        }
    
        public void setServiceA(ServiceA serviceA) {
            this.serviceA = serviceA;
        }
    
        @Override
        public String toString() {
            return "ServiceB{" +
                    "name='" + name + '\'' +
                    ", serviceA=" + serviceA +
                    '}';
        }
    }

    上面类中有2个属性,下面我们再创建一个ServiceC类,和ServiceB中的内容一样。

    ServiceC.java

    package com.javacode2018.lesson001.demo12;
    
    public class ServiceC {
        private String name;
        private ServiceA serviceA;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public ServiceA getServiceA() {
            return serviceA;
        }
    
        public void setServiceA(ServiceA serviceA) {
            this.serviceA = serviceA;
        }
    
        @Override
        public String toString() {
            return "ServiceC{" +
                    "name='" + name + '\'' +
                    ", serviceA=" + serviceA +
                    '}';
        }
    }

    下面我们使用spring来创建上面3个类对应的bean。

    beanExtend.xml

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
    
        <bean id="serviceA" class="com.javacode2018.lesson001.demo12.ServiceA"/>
    
        <bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB">
            <property name="name" value="路人甲Java"/>
            <property name="serviceA" ref="serviceA"/>
        </bean>
    
        <bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceB">
            <property name="name" value="路人甲Java"/>
            <property name="serviceA" ref="serviceA"/>
        </bean>
    
    </beans>

    创建测试用例。

    BeanExtendTest.java

    package com.javacode2018.lesson001.demo12;
    
    import org.junit.Test;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    /**
     * 公众号:路人甲Java,工作10年的前阿里P7分享Java、算法、数据库方面的技术干货!坚信用技术改变命运,让家人过上更体面的生活!
     * bean定义继承案例
     */
    public class BeanExtendTest {
        @Test
        public void normalBean() {
            String beanXml = "classpath:/com/javacode2018/lesson001/demo12/normalBean.xml";
            ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
            System.out.println("serviceB:" + context.getBean(ServiceB.class));
            System.out.println("serviceC:" + context.getBean(ServiceC.class));
        }
    }

    运行输出

    serviceB:ServiceB{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
    serviceC:ServiceC{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}

    通过继承优化代码

    我们再回头去看一下上面xml中,serviceB和serviceC两个bean的定义如下:

    <bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB">
        <property name="name" value="路人甲Java"/>
        <property name="serviceA" ref="serviceA"/>
    </bean>
    
    <bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC">
        <property name="name" value="路人甲Java"/>
        <property name="serviceA" ref="serviceA"/>
    </bean>

    这2个bean需要注入的属性的值是一样的,都需要注入name和serviceA两个属性,并且2个属性的值也是一样的,我们可以将上面的公共的代码抽取出来,通过spring中继承的方式来做到代码重用。

    可以将上面xml调整一下,我们来新建一个extendBean.xml,内容如下:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
           xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
           xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.3.xsd">
    
        <bean id="serviceA" class="com.javacode2018.lesson001.demo12.ServiceA"/>
    
        <bean id="baseService" abstract="true">
            <property name="name" value="路人甲Java"/>
            <property name="serviceA" ref="serviceA"/>
        </bean>
    
        <bean id="serviceB" class="com.javacode2018.lesson001.demo12.ServiceB" parent="baseService"/>
    
        <bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC" parent="baseService"/>
    
    </beans>

    上面多了一个baseService的bean,这个bean没有指定class对象,但是多了一个abstract="true"的属性,表示这个bean是抽象的,abstract为true的bean在spring容器中不会被创建,只是会将其当做bean定义的模板,而serviceB和serviceC的定义中多了一个属性parent,用来指定当前bean的父bean名称,此处是baseService,此时serviceB和serviceC会继承baseService中定义的配置信息。

    来个测试用例看一下效果:

    @Test
    public void extendBean() {
        String beanXml = "classpath:/com/javacode2018/lesson001/demo12/extendBean.xml";
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(beanXml);
        System.out.println("serviceB:" + context.getBean(ServiceB.class));
        System.out.println("serviceC:" + context.getBean(ServiceC.class));
    }

    运行输出:

    serviceB:ServiceB{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
    serviceC:ServiceC{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}

    输出和上面案例的输出基本一致。

    但是这次bean xml中bean的定义简化了很多,将公共的bean配置提取出来了,通过parent属性来配置需要继承的bean。

    子bean中也可以重新定义父bean中已经定义好的配置,这样子配置会覆盖父bean中的配置信息,我们将extendBean.xmlserviceC的定义改一下:

    <bean id="serviceC" class="com.javacode2018.lesson001.demo12.ServiceC" parent="baseService">
        <property name="name" value="欢迎和【路人甲Java】一起学些spring!"/>
    </bean>

    运行extendBean输出:

    serviceB:ServiceB{name='路人甲Java', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}
    serviceC:ServiceC{name='欢迎和【路人甲Java】一起学些spring!', serviceA=com.javacode2018.lesson001.demo12.ServiceA@222114ba}

    从输出中可以看出serviceC中的name对父bean中name的值进行了覆盖。

    我们再来从容器中获取一下baseService,如下:

    System.out.println(context.getBean("baseService"));

    运行输出:

    org.springframework.beans.factory.BeanIsAbstractException: Error creating bean with name 'baseService': Bean definition is abstract
    
        at org.springframework.beans.factory.support.AbstractBeanFactory.checkMergedBeanDefinition(AbstractBeanFactory.java:1412)

    会报BeanIsAbstractException异常,因为baseService是抽象的,不能够创建这个bean实例。

    总结

    1. bean元素的abstract属性为true的时候可以定义某个bean为一个抽象的bean,相当于定义了一个bean模板,spring容器并不会创建这个bean,从容器中查找abstract为true的bean的时候,会报错BeanIsAbstractException异常

    2. bean元素的parent属性可以指定当前bean的父bean,子bean可以继承父bean中配置信息,也可以自定义配置信息,这样可以覆盖父bean中的配置

    案例源码

    链接:https://pan.baidu.com/s/1p6rcfKOeWQIVkuhVybzZmQ 
    提取码:zr99

    来源:https://mp.weixin.qq.com/s?__biz=MzA5MTkxMDQ4MQ==&mid=2648934063&idx=1&sn=d529258a955ed5b53c9081219c8391e7&chksm=88621e91bf159787351880d2217b9f3fb7b06d251caa32995657cd2ca9613765bf87ff7e04a0&token=1656183666&lang=zh_CN&scene=21#wechat_redirect

  • 相关阅读:
    git学习——<二>git配置文件
    使用Python打造一款间谍程序
    Flutter gradle采坑
    逆向破解之160个CrackMe —— 031
    逆向破解之160个CrackMe —— 030
    逆向破解之160个CrackMe —— 029
    逆向破解之160个CrackMe —— 028
    逆向破解之160个CrackMe —— 027
    逆向破解之160个CrackMe —— 026
    逆向破解之160个CrackMe —— 025
  • 原文地址:https://www.cnblogs.com/konglxblog/p/15422987.html
Copyright © 2011-2022 走看看