一、Spring IoC 容器 Bean 花式注册与获取
花式四:通过继承实现Bean的注册
在assign_value.xml中增加xml配置,继承其他bean的配置信息要使用parent属性
<!--继承用的配置信息-->
<bean id="stark10" class="com.citi.entity.Person">
<property name="lastName" value="stark10"></property>
<property name="age" value="18"></property>
<property name="gender" value="男"></property>
<property name="email" value="stark@stark-industry.com"></property>
</bean>
<!--继承stark10的配置信息-->
<bean id="stark11" class="com.citi.entity.Person" parent="stark10">
<property name="lastName" value="stark11"></property>
</bean>
增加测试方法
@Test
public void testAssignByExtend(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:assign_value.xml");
Person stark11 = context.getBean("stark11",Person.class);
Person stark10 = context.getBean("stark10",Person.class);
System.out.println(stark10);
System.out.println(stark11);
}
执行测试,除了名字不同,邮件性别等信息都是从stark10继承过来的
通过abstract属性将bean配置变成一个配置模版,只能用于继承配置信息,无法直接获取
修改xml配置,增加abstract=“true”
<bean id="stark10" class="com.citi.entity.Person" abstract="true">
<property name="lastName" value="stark10"></property>
<property name="age" value="18"></property>
<property name="gender" value="男"></property>
<property name="email" value="stark@stark-industry.com"></property>
</bean>
再次执行测试,获取stark10出错,stark01已被标记为abstarct,只能用于其他bean继承配置信息
花式五:实现互相依赖的Bean的注册
分别给Car,Book,Person实体类增加无参构造方法,并在其中打印一句话
System.out.println(this.getClass().getName() + "无参构造方法被调用");
新建一个bean的xml配置dependency_bean.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"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p = "http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<bean id="person" class="com.citi.entity.Person"></bean>
<bean id="car" class="com.citi.entity.Car"></bean>
<bean id="book" class="com.citi.entity.Book"></bean>
</beans>
增加新的测试类及测试方法
@Test
public void testGetBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:dependency_bean.xml");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
Bean的创建顺序与xml中配置的顺序一致
想要改变顺序还可以使用depends-on标签
<bean id="person" class="com.citi.entity.Person" depends-on="car,book"></bean>
<bean id="car" class="com.citi.entity.Car"></bean>
<bean id="book" class="com.citi.entity.Book"></bean>
执行测试,实现了先创建依赖的car,book,最后再创建person
花式六:实现多实例Bean的注册
bean的注册默认是单实例的,创建多实例的Bean需要增加prototype属性
增加singleton_prototype_bean.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"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p = "http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<bean id="person" class="com.citi.entity.Person"></bean>
<bean id="car" class="com.citi.entity.Car"></bean>
<bean id="book" class="com.citi.entity.Book"></bean>
</beans>
增加测试类及测试方法
public class SingletonPrototypeBeanTest {
@Test
public void testGetBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:singleton_prototype_bean.xml");
System.out.println("IoC容器创建完成");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
}
}
执行测试方法,单实例bean在容器创建完成之前就已经创建了
将person增加scope属性,修改为多实例
<bean id="person" scope="prototype" class="com.citi.entity.Person"></bean>
修改测试代码
public class SingletonPrototypeBeanTest {
@Test
public void testGetBean(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:singleton_prototype_bean.xml");
System.out.println("IoC容器创建完成");
Person p1 = context.getBean(Person.class);
Person p2 = context.getBean(Person.class);
System.out.println(p1 == p2);
}
}
执行测试,多实例Bean是在容器创建完成之后创建的,且多实例的Bean内存地址是不相同的
scope属性还有两个value是request和session,基本很少使用
花式七:Factory创建Bean
工厂分为静态工厂和实例工厂
- 静态工厂: 工厂本身不用创建Bean,通过静态方法调用 对象 = 工厂类.工厂方法名
- 实例工厂: 工厂本身需要创建Bean,通过先创建出一个工厂对象 工厂类 工厂对象 = new 工厂类(),从工厂对象获取实例 工厂对象.getBean()
entity包中增加Tesla实体类
public class Tesla {
private String name;
private String battery; // 电池
private String engine; // 电机
private String chassis; //底盘
private String bodywork; // 车身
private String owner; // 车主
// 此处省略getter/setter/toString方法
}
新增facotry包,创建静态工厂和实例工厂类
public class TeslaInstanceFactory {
public Tesla getTesla(String owner){
System.out.println("TeslaInstanceFactory被调用");
Tesla tesla = new Tesla();
tesla.setName("Model 3");
tesla.setBattery("4680");
tesla.setOwner(owner);
return tesla;
}
}
public class TeslaStaticFactory {
public static Tesla getTesla(String owner){
System.out.println("TeslaStaticFactory被调用");
Tesla tesla = new Tesla();
tesla.setName("Model3");
tesla.setBattery("4680");
tesla.setOwner(owner);
return tesla;
}
}
静态工厂创建 Bean
在factory.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"
xmlns:util="http://www.springframework.org/schema/util"
xmlns:p = "http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd">
<!--静态工厂创建bean,不需要创建工厂本身
id:指的是Bean的id,不是工厂的id
class:值得是静态工厂类的全类名
factory-method:指定哪个方法创建Tesla Bean
constructor-arg: 使用setter方法赋值
-->
<bean id="model3" class="com.citi.factory.TeslaStaticFactory" factory-method="getTesla">
<!--相当于工厂方法getTesla传入的参数,不加这个属性会报错-->
<constructor-arg value="musk1"></constructor-arg>
</bean>
</beans>
创建测试类FactoryTest,新增测试方法testGetBeanByStaticFactory()
public class FactoryTest {
@Test
public void testGetBeanByStaticFactory(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:factory.xml");
System.out.println("IoC容器创建完成");
Tesla model3 = context.getBean("model3",Tesla.class);
System.out.println(model3);
}
}
执行测试方法,控制台输出如下,Tesla Bean创建成功
实例工厂创建 Bean
在factory.xml中增加实例工厂创建Bean的配置
<bean id="ShanghaiGigaFactory" class="com.citi.factory.TeslaInstanceFactory" >
</bean>
<bean id="modelS" class="com.citi.entity.Tesla" factory-bean="ShanghaiGigaFactory" factory-method="getTesla">
<!--相当于工厂方法getTesla传入的参数,不加这个属性会报错-->
<constructor-arg value="musk2"></constructor-arg>
</bean>
增加测试方法
@Test
public void testGetBeanByInstanceFactory(){
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:factory.xml");
System.out.println("IoC容器创建完成");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Tesla modelS = context.getBean("modelS",Tesla.class);
System.out.println(modelS);
}
控制台成功打印出modelS
实现FactoryBean接口创建 Bean
新增一个FactorBean的实现类BerlinGigaFactoryBean,泛型为要创建的类型
public class BerlinGigaFactoryBean implements FactoryBean<Tesla> {
// 返回创建的对象
@Override
public Tesla getObject() throws Exception {
System.out.println("实现FactoryBean接口创建Bean");
Tesla tesla = new Tesla();
tesla.setName("Cybertruck");
return tesla;
}
// 返回常见的类型
@Override
public Class<?> getObjectType() {
return Tesla.class;
}
// 是否为单例,默认非单例模式
@Override
public boolean isSingleton() {
return false;
}
}
在factory.xml中增加配置
<!--实现FactoryBean接口创建Bean配置文件-->
<bean id="BerlinGigaFactory" class="com.citi.factory.BerlinGigaFactoryBean">
</bean>
增加测试方法
@Test
public void testGetBeanByImplFactoryBean() throws Exception {
ApplicationContext context = new ClassPathXmlApplicationContext("classpath:factory.xml");
System.out.println("IoC容器创建完成");
String[] beanDefinitionNames = context.getBeanDefinitionNames();
for (String beanDefinitionName : beanDefinitionNames) {
System.out.println(beanDefinitionName);
}
Tesla cybertruck = (Tesla) context.getBean("berlinGigaFactory");
System.out.println(cybertruck);
}
执行测试方法,直接获取实现FactoryBean接口的实例即可得到Tesla Bean cybertruck
实现FactoryBean接口创建Bean,在容器中都是获取Bean时才创建Bean,跟方法中是否是单例无关
plus:BeanFactory和FactoryBean有什么区别?
BeanFactory是容器的顶层接口,ApplicationContext就是间接实现了该接口,可以通过getBean()方法获取容器中的Bean,FactoryBean接口是用来注册Bean的,使用该接口需要实现接口中的方法。