• 4.Spring系列之Bean的配置1


    一、配置Bean的两种方式之使用XML配置Bean


    1.基于XML配置Bean-属性注入

    创建一个Bean,该Bean提供了有参构造器

    public class Person {
    
        private String name;public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + "]";
        }
    
    }

    在IOC容器内配置属性注入:

    <?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.xsd">
    
        <!-- 
            class:bean的全类名,通过反射创建该bean的实例,要求Bean中必须有无参构造器,否则会报:No default constructor found
            id:IOC容器对象引用该bean的标志,例如:ctx.getBean(hello);返回的就是一个Hello对象,即标识容器中的bean,并且id唯一
            注意:若没有定义id,那么自动使用类名首字母小写为id名称
        -->
        <bean id="person" class="com.spring.model.Person">
         <!-- 注意:这里的name必须和Bean属性的setXXX方法中的XXX同名,否则属性无法赋值 --> <property name="name" value="loose"></property> </bean> </beans>

    测试属性注入:

    public class Main {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = (Person) ctx.getBean("person");
            System.out.println(person);
            System.out.println(person.getName());
            /**
             * 运行后输出:
             * Person [name=loose]
             * loose
             */
        }
    }

    说明:

    属性注入即通过 setter 方法注入Bean 的属性值或依赖的对象
    属性注入使用 <property> 元素, 使用 name 属性指定 Bean 的属性名称,value 属性或 <value> 子节点指定属性值
    属性注入是实际应用中最常用的注入方式

    2.构造器注入,使用构造器初始化不必提供get和set方法

    通过构造方法注入Bean 的属性值或依赖的对象,它保证了 Bean 实例在实例化后就可以使用,构造器注入在 <constructor-arg> 元素里声明属性, <constructor-arg> 中没有 name 属性
    以上方的Bean类为例,去掉属性的set和get方法,同时创建一个Bean的带参构造器:
    public class Person {
    
        private String name;
        private int age;
    
        public Person() {
            super();
        }
    
        public Person(String name,int age) {
            super();
            this.name = name;
            this.age = age;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + "]";
        }
    
    }

    在IOC容器内配置构造器注入:

    <?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.xsd">
    
        <bean id="person" class="com.spring.model.Person">
            <constructor-arg value="loose" index="0"></constructor-arg>
            <constructor-arg value="20" index="1"></constructor-arg>
        </bean>
    </beans>

    测试构造器注入:

    public class Main {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = (Person) ctx.getBean("person");
            System.out.println(person);
            /**
             * 运行后输出:
             * Person [name=loose, age=20]
             */
        }
    }

    同时,我们也可以指定构造器参数类型的匹配入参:

    <?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.xsd">
    
        <bean id="person" class="com.spring.model.Person">
            <constructor-arg value="loose" type="java.lang.String"></constructor-arg>
            <constructor-arg value="20" type="int"></constructor-arg>
        </bean>
    </beans>

    3.工厂方法注入这里就省略,用的很少,有兴趣的自己去找下资料

    4.属性注入的细节

    ①.字面值

    字面值:可用字符串表示的值,可以通过<value>元素标签或value属性进行注入
    <bean id="person" class="com.spring.model.Person">
        <property name="name">
            <value>spring</value>
        </property>
    </bean>

    说明:基本数据类型和封装类、String等类型都可以采用字面值注入的方式。

    ②.若字面值包含特殊符号,可以使用<![CDATA[]]>把字面值包裹起来

    <bean id="person" class="com.spring.model.Person">
       <property name="name">
            <value><![CDATA[<spring]]></value>
       </property>
    </bean>

    这里获取到属性值后,输出的是<string,包含了特殊符号<

    ③.引用其它的Bean

    组成应用程序的 Bean 经常需要相互协作以完成应用程序的功能. 要使 Bean 能够相互访问, 就必须在 Bean 配置文件中指定对 Bean 的引用;在 Bean 的配置文件中, 可以通过 <ref> 元素或 ref  属性为 Bean 的属性或构造器参数指定对 Bean 的引用:
    在这里我们首先创建两个Bean,一个是Person代表人,一个是Mobile代表手机:
    public class Person {
    
        private String name;
        private int age;
    
        private Mobile mobile;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Mobile getMobile() {
            return mobile;
        }
    
        public void setMobile(Mobile mobile) {
            this.mobile = mobile;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + ", mobile=" + mobile + "]";
        }
    
    }
    public class Mobile {
    
        private String brand;
        private double price;
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Mobile [brand=" + brand + ", price=" + price + "]";
        }
    
    }

    在IOC容器中配置这两个Bean,并使Person引用Mobile:

    <?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.xsd">
    
        <bean id="mobile" class="com.spring.model.Mobile">
            <property name="brand" value="iphone"></property>
            <property name="price" value="5000"></property>
        </bean>
    
        <bean id="person" class="com.spring.model.Person">
            <property name="name" value="loose"></property>
            <property name="age" value="20"></property>
    //这里ref中的mobile为上方配置的Mobile这个Bean的id <property name="mobile" ref="mobile"></property> </bean> </beans>

    测试引用其它的Bean:

    public class Main {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = (Person) ctx.getBean("person");
            System.out.println(person);
            // 执行后输出:Person [name=loose, age=20, mobile=Mobile [brand=iphone, price=5000.0]]
        }
    }

    IOC容器中也可以这么配置:

    <?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.xsd">
    
        <bean id="mobile" class="com.spring.model.Mobile">
            <property name="brand" value="iphone"></property>
            <property name="price" value="5000"></property>
        </bean>
    
        <bean id="person" class="com.spring.model.Person">
            <property name="name" value="loose"></property>
            <property name="age" value="20"></property>
            <property name="mobile">
                <ref bean="mobile"/> //使用ref标签引用Bean
            </property>
        </bean>
    </beans>

    也可以在属性或构造器里包含 Bean 的声明, 这样的 Bean 称为内部 Bean:

    <?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.xsd">
    
        <!-- 无需再配置跟内部Bean一样类型的Bean进行引用 -->
        <!-- <bean id="mobile" class="com.spring.model.Mobile">
            <property name="brand" value="iphone"></property>
            <property name="price" value="5000"></property>
        </bean> -->
    
        <bean id="person" class="com.spring.model.Person">
            <property name="name" value="loose"></property>
            <property name="age" value="20"></property>
            <property name="mobile">
                <bean class="com.spring.model.Mobile">
                    <property name="brand" value="iphone"></property>
                    <property name="price" value="5000"></property>
                  </bean>
            </property>
        </bean>
    </beans>

    注意:

    当 Bean 实例仅仅给一个特定的属性使用时, 可以将其声明为内部 Bean. 内部 Bean 声明直接包含在 <property> 或 <constructor-arg> 元素里, 不需要设置任何 id 或 name 属性;

    内部 Bean 不能使用在任何其他地方

    ④.注入参数详解null 值和级联属性

    可以使用专用的 <null/> 元素标签为 Bean 的字符串或其它对象类型的属性注入 null 值:

    <bean id="person" class="com.spring.model.Person">
       <property name="name">
         <null></null>
       </property>
      <property name="age" value="20"></property>
    </bean>

    同时,Spring 支持级联属性的配置,为了方便查看,这里再次给出两个Bean,分别是Person和Mobile:

    public class Person {
    
        private String name;
        private int age;
    
        private Mobile mobile;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    
        public Mobile getMobile() {
            return mobile;
        }
    
        public void setMobile(Mobile mobile) {
            this.mobile = mobile;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", age=" + age + ", mobile=" + mobile + "]";
        }
    
    }
    public class Mobile {
    
        private String brand;
        private double price;
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Mobile [brand=" + brand + ", price=" + price + "]";
        }
    
    }

    在IOC容器配置级联Bean:

    <?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.xsd">
    
        <bean id="mobile" class="com.spring.model.Mobile">
            <!-- 这里不配置mobile的属性值 -->
        </bean>
    
        <bean id="person" class="com.spring.model.Person">
            <property name="name" value="loose"></property>
            <property name="age" value="20"></property>
            <property name="mobile" ref="mobile"></property>
            <!-- 以级联的形式注入Bean值 -->
            <property name="mobile.brand" value="nokia"></property>
            <property name="mobile.price" value="2000"></property>
        </bean>
    </beans>

    测试级联程序:

    public class Main {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = (Person) ctx.getBean("person");
            System.out.println(person);
            // 执行后输出:Person [name=loose, age=20, mobile=Mobile [brand=nokia, price=2000.0]]
        }
    }

    ⑤.引用集合属性

    在 Spring中可以通过一组内置的 xml 标签(例如: <list>, <set> 或 <map>) 来配置集合属性,配置 java.util.List 类型的属性, 需要指定 <list>  标签, 在标签里包含一些元素. 这些标签可以通过 <value> 指定简单的常量值, 通过 <ref> 指定对其他 Bean 的引用. 通过<bean> 指定内置 Bean 定义. 通过 <null/> 指定空元素. 甚至可以内嵌其他集合,数组的定义和 List 一样, 都使用 <list>,配置 java.util.Set 需要使用 <set> 标签, 定义元素的方法与 List 一样:

    ===>配置List集合属性,以上方的Person和Mobile为例,不同的是Person里面的Mobile变成了List<Mobile>,代表一个人可以多部手机:

    public class Person {
    
        private String name;
    
        private List<Mobile> mobiles;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public List<Mobile> getMobiles() {
            return mobiles;
        }
    
        public void setMobiles(List<Mobile> mobiles) {
            this.mobiles = mobiles;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", mobiles=" + mobiles + "]";
        }
    
    }
    public class Mobile {
    
        private String brand;
        private double price;
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Mobile [brand=" + brand + ", price=" + price + "]";
        }
    
    }

    在IOC容器中配置两个的引用关系:

    <?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.xsd">
    
        <!-- 这里配置多个Mobile Bean,然后被person一个个引用 -->
        <bean id="mobile1" class="com.spring.model.Mobile">
            <property name="brand" value="nokia"></property>
            <property name="price" value="2000"></property>
        </bean>
        
        <bean id="mobile2" class="com.spring.model.Mobile">
            <property name="brand" value="iphone"></property>
            <property name="price" value="5000"></property>
        </bean>
    
        <bean id="person" class="com.spring.model.Person">
            <property name="name" value="loose"></property>
            <property name="mobiles">
                <!-- 使用list标签 -->
                <list>
                    <!-- 分别引入多个Bean -->
                    <ref bean="mobile1"/>
                    <ref bean="mobile2"/>
                </list>
            </property>
        </bean>
    </beans>

    测试Bean中引用List集合属性:

    public class Main {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = (Person) ctx.getBean("person");
            System.out.println(person);
            // 执行后输出:Person [name=loose, mobiles=[Mobile [brand=nokia, price=2000.0], Mobile [brand=iphone, price=5000.0]]]
        }
    }

    ===>配置Map集合属性,Java.util.Map 通过 <map> 标签定义, <map> 标签里可以使用多个 <entry> 作为子标签.,每个条目包含一个键和一个值

    仍然是以上面的Bean威力,不同的是集合类型变更为Map,请看下方两个Bean的定义:

    public class Person {
    
        private String name;
    
        private Map<String,Mobile> mobiles;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Map<String, Mobile> getMobiles() {
            return mobiles;
        }
    
        public void setMobiles(Map<String, Mobile> mobiles) {
            this.mobiles = mobiles;
        }
    
        @Override
        public String toString() {
            return "Person [name=" + name + ", mobiles=" + mobiles + "]";
        }
    
    }
    public class Mobile {
    
        private String brand;
        private double price;
    
        public String getBrand() {
            return brand;
        }
    
        public void setBrand(String brand) {
            this.brand = brand;
        }
    
        public double getPrice() {
            return price;
        }
    
        public void setPrice(double price) {
            this.price = price;
        }
    
        @Override
        public String toString() {
            return "Mobile [brand=" + brand + ", price=" + price + "]";
        }
    
    }

    在IOC容器中配置两个Bean的引用关系:

    <?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.xsd">
    
        <!-- 这里配置多个Mobile Bean,然后被person一个个引用 -->
        <bean id="mobile1" class="com.spring.model.Mobile">
            <property name="brand" value="nokia"></property>
            <property name="price" value="2000"></property>
        </bean>
        
        <bean id="mobile2" class="com.spring.model.Mobile">
            <property name="brand" value="iphone"></property>
            <property name="price" value="5000"></property>
        </bean>
    
        <bean id="person" class="com.spring.model.Person">
            <property name="name" value="loose"></property>
            <property name="mobiles">
                <!-- 使用map标签 -->
                <map>
                    <entry key="nokia" value-ref="mobile1"></entry>
                    <entry key="iphone" value-ref="mobile2"></entry>
                </map>
            </property>
        </bean>
    </beans>

    测试Bean中引用Map集合属性:

    public class Main {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            Person person = (Person) ctx.getBean("person");
            System.out.println(person);
            // 执行后输出:son [name=loose, mobiles={nokia=Mobile [brand=nokia, price=2000.0], iphone=Mobile [brand=iphone, price=5000.0]}]
        }
    }

    ===><props> 定义 java.util.Properties, 该标签使用多个 <prop> 作为子标签.,每个 <prop> 标签必须定义 key 属性:

    我们新建一个Bean,用于模拟从配置文件中读取数据库连接信息:

    public class DataSource {
    
        private Properties properties;
    
        public Properties getProperties() {
            return properties;
        }
    
        public void setProperties(Properties properties) {
            this.properties = properties;
        }
    
    }

    将Bean交给IOC容器管理:

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xmlns:context="http://www.springframework.org/schema/context"
        xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
            http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd">
    
        <bean id="dataSource" class="com.spring.model.DataSource">
             <property name="properties">
                  <props>
                     <prop key="user">root</prop>
                     <prop key="password">1234</prop>
                     <prop key="jdbcUrl">jdbc:mysql:///test</prop>
                     <prop key="driver">com.mysql.jdbc.Driver</prop>
                  </props>
           </property>
        </bean>
    </beans>

    测试程序:

    public class Main {
    
        public static void main(String[] args) {
            ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
            DataSource ds = (DataSource) ctx.getBean("dataSource");
            System.out.println(ds.getProperties());
            //执行后输出:{user=root, password=1234, driver=com.mysql.jdbc.Driver, jdbcUrl=jdbc:mysql:///test}
        }
    }

    注意:

    引用集合属性都存在一个问题,不能将集合作为独立的 Bean 定义, 导致其他 Bean 无法引用该集合, 所以无法在不同 Bean 之间共享集合,但是可以使用 util schema 里的集合标签定义独立的集合 Bean;

    需要注意的是,必须在 <beans> 根元素里添加 util schema 定义:导入util命名空间:xmlns:util="http://www.springframework.org/schema/util"

    配置独立的外部list:

    <util:list id="mobiles">
      <ref bean="mobile1"/>
      <ref bean="mobile2"/>
    </util:list>

    引用独立的外部list:

    <bean id="person" class="com.sring.model.Person">
        <property name="name" value="loose"></property>
        <property name="mobiles" ref="mobiles"></property>
    </bean>

    为了简化 XML 文件的配置,越来越多的 XML 文件采用属性而非子元素配置信息,Spring 从 2.5 版本开始引入了一个新的 p 命名空间,可以通过 <bean> 元素属性的方式配置 Bean 的属性,使用 p 命名空间后,基于 XML 的配置方式将进一步简化:

    <bean id="person" class="com.spring.model.Person"
    p:mobile-ref="mobiles" p:name="loose"></bean>
  • 相关阅读:
    20210304. 3. 通讯协议及事件处理机制
    20210304. 2. 数据类型与底层数据结构
    20210304. 1. 缓存原理 & 设计
    20210304. 0.3. Redis Cluster 搭建
    20210304. 0.2. Redis 哨兵模式搭建
    20210304. 0.1. Redis 安装
    20210208. Neo4j
    20210207. MongoDB
    20210203 8. 运维和第三方工具
    Global Brain Dynamics Embed the Motor Command Sequence of Caenorhabditis elegans
  • 原文地址:https://www.cnblogs.com/Json1208/p/8726951.html
Copyright © 2020-2023  润新知