QA 由浅入深 Spring Framework 5.0(三)

Chapter 02 - 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="[email protected]"></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继承过来的 image.png

通过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="[email protected]"></property>
</bean>
复制代码

再次执行测试,获取stark10出错,stark01已被标记为abstarct,只能用于其他bean继承配置信息

image.png

花式五:实现互相依赖的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中配置的顺序一致

image.png 想要改变顺序还可以使用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 image.png

花式六:实现多实例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在容器创建完成之前就已经创建了

image.png 将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内存地址是不相同的

image.png 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创建成功

image.png

实例工厂常见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 image.png 实现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 image.png 实现FactoryBean接口创建Bean,在容器中都是获取Bean时才创建Bean,跟方法中是否是单例无关 plus:BeanFactory和FactoryBean有什么区别?

BeanFactory是容器的顶层接口,ApplicationContext就是间接实现了该接口,可以通过getBean()方法获取容器中的Bean,FactoryBean接口是用来注册Bean的,使用该接口需要实现接口中的方法。

猜你喜欢

转载自juejin.im/post/7048621407902629918
QA