一、集合属性
场景:对象的属性是集合类型的,那么就需要注入一个集合
实现方式:在Spring中可以通过一组内置的XML标签来配置几个属性,例如:<list>,<set>或<map>
1、list集合、set集合、数组属性赋值
案例:
1)创建一个PersonList类,有name和list<Car> 两个私有属性
2)IOC容器给属性赋值
<!--list集合、set集合、数组--> <bean id="personlist" class="com.wufq.spring.PersonList"> <property name="name" value="韦小宝"></property> <property name="car"> <!--构造集合--> <list> <!--两中方式赋值:内部bean、ref--> <ref bean="car"></ref> <ref bean="car1"></ref> <ref bean="car2"></ref> <!--数组对象有自己特有的标签,但是可以直接用list(建议用)--> <!--<array></array>--> <!--set集合可以直接用set标签--> <!--<set></set>--> </list> </property> </bean>
3)调用测试
@Test public void testList(){ PersonList list = context.getBean("personlist", PersonList.class); System.out.println(list); }
=====执行结果====
PersonList{name='韦小宝', car=[Car{brand='奔驰', crop='一汽', price='400000.0',speed='500'}, Car{brand='奥迪', crop='一汽', price='450000.0',speed='null'}, Car{brand='宝马', crop='华晨', price='0.0',speed='200'}]}
2、map集合属性赋值
<!--map集合--> <bean id="personMap" class="com.wufq.spring.PersonMap"> <property name="name" value="小昭"></property> <property name="map"> <!--构造map--> <map> <entry key="AA" value-ref="car"></entry> <entry key="BB" value-ref="car1"></entry> <entry key="CC" value-ref="car2"></entry> </map> </property> </bean>
注意点:给map集合属性的值赋值,用到<map></map>标签,map集合是无法直接取值的,所以需要转换成set集合,这时候就用到了entry,同样在map集合属性赋值也用到<entry>
以及通过entry内部的key和value进行赋值
3、集合类型的bean (主要解决没有可引用的bean)
就是把集合设置成共有的,供其他所有的bean使用。
-->前提:配置集合类型的bean需要引入util名称空间
1)idea需要引入spring的命名空间(无法像eclipse一样勾选Namespaces),需要手动添加util的空间名称
#在xml文件的首部添加
xmlns:context="http://www.springframework.org/schema/context"
然后我们打出:xmlns:util= 然后就会有相应的以提示,完整的内容如下:
xmlns:util="http://www.springframework.org/schema/util"
注意:xmlns:util 或者xmlns:p必须在xmlns:context="”这一行的下面打,否则也不会提示
2)在xsi:schemaLocation=内补充
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.0.xsd
注意:http://.../spring-context.xsd必须要写并且放在http://.../scontext下面,否则会报“无法找到元素context:component-scan”错
http://.../spring-util-4.0.xsd必须要写并且放在http://.../util下面,否则会报“无法找到元素 'util:map' 的声明”错
-->配置集合类型的bean
<!--集合bean--> <util:map id="mapBean"> <entry key="AA" value-ref="car"></entry> <entry key="BB" value-ref="car1"></entry> <entry key="CC" value-ref="car2"></entry> </util:map> <util:list id="listBean"> <ref bean="car"></ref> <ref bean="car1"></ref> <ref bean="car2"></ref> </util:list> ========其他bean引用集合bean========= <bean id="personMap" class="com.wufq.spring.PersonMap"> <property name="name" value="小昭"></property> <property name="map" ref="mapBean"></property> </bean>
二、FactoryBean
- spring中有两种类型的bean,一种是普通的bean(上面讲的那种)另外一种是工厂bean,即FactoryBean
- 工厂bean跟普通bean不同,其返回的对象不是指定类的一个实例,其返回的是该工厂bean的getObject方法锁返回的对象
- 工厂bean必须实现org,springframework.bean.factory.FactoryBean接口
#案例:通过FactoryBean实现对Car类的属性赋值
1)创建一个FactoryBeanTest类实现FactoryBean接口
package com.wufq.factorySpring; import com.wufq.spring.Car; import org.springframework.beans.factory.FactoryBean; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; /** * @Author wufq * @Date 2021/4/8 15:39 */ public class FactoryBeanTest implements FactoryBean<Car> { /* * FactoryBean具体创建的bean对象是由getObject()方法来返回的 * 当前案例:FactoryBean<T>接口内的类型是Car类型,所以需要返回Car类型的对象 * */ @Override public Car getObject() throws Exception { return new Car("扣扣","宝马",50000); } /* * 返回具体bean对象的类型 * */ @Override public Class<?> getObjectType() { return Car.class; } /* * bean可以是单例的,也可以是原型的(非单例) * */ @Override public boolean isSingleton() { return false; } }
2)创建spring的xml配置文件:factoryBean-di.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.xsd"> <!--通过FactoryBean来配置 FactoryBean具体返回的对象由getObject方法来决定 --> <bean id="factoryBean" class="com.wufq.factorySpring.FactoryBeanTest"></bean> </beans>
3)在FactoryBeanTest类内通过main测试
public static void main(String[] args){ ApplicationContext con = new ClassPathXmlApplicationContext("factoryBean-di.xml"); Car car = con.getBean("factoryBean", Car.class); System.out.println(car); } =====执行结果===== Car{brand='扣扣', crop='宝马', price='50000.0',speed='null'}
理解:普通bean是通过缺省构造器和构造方法来创建对象的,比较被动。而FactoryBean 创建的目的是Spring支持我们参与到bean对象的创建过程中,这样会灵活一些
三、bean的高级配置
1、bean和bean之间的继承关系(关键字:parent)
#案例 :实现address1继承address2的bean
1)创建一个Address类,有city和Street(街道)两个属性
2)创建spring的xml文件:spring-relation.xml
<!--bean的继承关系--> <bean id="address1" class="com.wufq.relation.Address"> <property name="city" value="beijing"></property> <property name="street" value="chaoyangjie"></property> </bean> <!--因为address2内class和city属性和address1一样,所以我们可以让address2继承address1来复用address1的class和city 继承关键字:parent --> <bean id="address2" parent="address1"> <property name="street" value="changanjie"></property> </bean>
3)创建测试类AddressTest测试address2是否继承了address1的bean
public class AddressTest { ApplicationContext context = null; @Before public void brf(){ context= new ClassPathXmlApplicationContext("spring-relation.xml"); } @Test public void testAddress(){ Address add1= context.getBean("address1",Address.class); System.out.println("Address1:"+add1); Address add2 = context.getBean("address2", Address.class); System.out.println("Address2:"+add2); } } ====执行结果==== Address1:Address{city='beijing', street='chaoyangjie'} Address2:Address{city='beijing', street='changanjie'}
由执行结果Address2可以看出来继承了Address1的
2、bean也可以实现抽象(关键字:abstract)
<!-- abstract="true":抽象bean 不能被创建对象,class可以忽略不写 继承抽象的父bean可以继承一些配置,但是id,abstract,autowire是不能被继承的 注意:由于抽象bean不能被创建对象,所以测试类的时候不能创建Address1的对象。Address add1= context.getBean("address1",Address.class); --> <bean id="address1" abstract="true" > <property name="city" value="beijing"></property> <property name="street" value="chaoyangjie"></property> </bean> <!--因为address2内class和city属性和address1一样,所以我们可以让address2继承address1来复用address1的class和city 继承关键字:parent --> <bean id="address2" class="com.wufq.relation.Address" parent="address1"> <property name="street" value="changanjie"></property> </bean>
3、bean之间的依赖关系(关键字:depends-on)
创建一个bean的时候必须保证另外一个bean也被创建,这时候我们称前面的bean对后面的bean有依赖。
<!--依赖关系--> <bean id="address3" class="com.wufq.relation.Address" parent="address1" depends-on="address4"> </bean> <bean id="address4" class="com.wufq.relation.Address"></bean>
“address3”依赖“address4”,如果没有创建address4时就会报错
四、bean的作用域★
在<bean>中可以用scope关键字设置作用域,以决定这个bean是单例的还是多例的
|-- singleton:单例的(默认值),在这个IOC容器中只能存在一个bean的对象。而且在IOC容器对象被创建时,就创建单例的bean的对象,后续每次通过getBean()方法获取bean对象时,返回的都是同一个对象
#案例演示:
1)创建Car类,包含两个私有属性brand,prices。创建set、get方法,重写toString()方法,创建缺省构造器:内部打印“Ainit car....”
2)创建spring的xml文件,设置作用域为:singleton(默认,可以不写)
<bean id="car" class="com.wufq.Spring.scope.Car" scope="singleton"> <property name="brand" value="奥迪"></property> <property name="prices" value="500000"></property> </bean>
3)创建测试类测试
public class CarTest { ApplicationContext context=null; @Before public void bef(){ context = new ClassPathXmlApplicationContext("spring-scope.xml"); }
@Test
public void testScope1(){}; //Ainit car.... //不获取bean对象,去执行同样会把缺省构造器内的此内容打印出来,说明在singleton模式下,在创建IOC容器时就已经创建了对象
@Test public void testScope2(){ Car car1 = context.getBean("car", Car.class); Car car2 = context.getBean("car",Car.class); System.out.println(car1==car2); //true -->正常情况下new对象,每个对象都是不一样的,这里两个对象是true说明创建IOC容器的时候就值创建了一个对象,所以在两次获取bean对象都是同一个对象 } }
|-- prototype:原型的/多例的。在整个IOC容器中可有多个bean的对象。在IOC容器对象被创建时,不会创建原型的bean的对象,而是等到每次通过getBean()方法获取bean对象时,才会创建一个新的bean对象
#案例演示:
1)修改spring的xml文件,设置作用域为:prototype
<bean id="car" class="com.wufq.Spring.scope.Car" scope="prototype"> <property name="brand" value="奥迪"></property> <property name="prices" value="500000"></property> </bean>
2)测试类测试
public class CarTest { ApplicationContext context=null; @Before public void bef(){ context = new ClassPathXmlApplicationContext("spring-scope.xml"); } @Test public void testScope1(){ } //没有结果-->说明只创建IOC容器不会创建对象 @Test public void testScope2(){ Car car1 = context.getBean("car", Car.class); Car car2 = context.getBean("car",Car.class); System.out.println(car1==car2); //true -->说明创建IOC容器的时候就值创建了一个对象,所以在两次获取bean对象都是同一个对象 } /* 打印结果: Ainit car... Ainit car... false 说明只有获取getBean方法时才会创建对象,并且每获取一次就创建一个对象,并且创建的对象不一样 */ }