Spring 全家桶之 Spring Framework 5.3(二)- Part B

简介: Spring IoC容中Bean的注册方式,通过继承实现Bean注册以及通过工厂方式注册Bean及实现Factory Bean注册Bean

一、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继承过来的

iShot_2022-11-15_10.10.42.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="stark@stark-industry.com"></property>
</bean>

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

iShot_2022-11-15_10.10.52.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中配置的顺序一致

iShot_2022-11-15_10.11.04.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

iShot_2022-11-15_10.11.13.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在容器创建完成之前就已经创建了

iShot_2022-11-15_10.11.24.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内存地址是不相同的

iShot_2022-11-15_10.13.45.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创建成功

iShot_2022-11-15_10.13.55.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

iShot_2022-11-15_10.14.05.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

iShot_2022-11-15_10.14.18.png

实现FactoryBean接口创建Bean,在容器中都是获取Bean时才创建Bean,跟方法中是否是单例无关
plus:BeanFactory和FactoryBean有什么区别?

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

相关文章
|
7月前
|
Java 开发者 Spring
Spring Framework 中的 @Autowired 注解:概念与使用方法
【4月更文挑战第20天】在Spring Framework中,@Autowired 注解是实现依赖注入(Dependency Injection, DI)的一种非常强大的工具。通过使用 @Autowired,开发者可以减少代码中的引用绑定,提高模块间的解耦能力
727 6
|
4月前
|
安全 Java 网络安全
Spring Framework JDK >= 9 远程代码执行(CVE-2022-22965)
Spring Framework JDK >= 9 远程代码执行(CVE-2022-22965)
|
6月前
|
前端开发 Java 调度
Spring Webflux 是 Spring Framework 提供的响应式编程支持
Spring Webflux 是 Spring Framework 提供的响应式编程支持
88 2
|
5月前
|
Cloud Native Java 开发者
深入解析Spring Framework的核心设计原理
深入解析Spring Framework的核心设计原理
|
5月前
|
安全 Java Apache
如何安装与使用Spring Boot 2.2.x、Spring Framework 5.2.x与Apache Shiro 1.7进行高效开发
【7月更文第1天】在现代Java Web开发领域,Spring Boot以其简化配置、快速开发的特点备受青睐。结合Spring Framework的成熟与Apache Shiro的强大权限控制能力,我们可以轻松构建安全且高效的Web应用。本篇文章将指导你如何安装并使用Spring Boot 2.2.x、Spring Framework 5.2.x以及Apache Shiro 1.7来构建一个具备基础权限管理功能的项目。
92 0
|
7月前
|
设计模式 Java 数据库连接
Spring Framework 6 中的设计模式
Spring Framework 6 中的设计模式
50 1
|
7月前
|
前端开发 Java Spring
Spring Framework五大功能模块
Spring Framework五大功能模块
|
开发框架 安全 Java
Spring Framework远程代码执行漏洞复现(CVE-2022-22965)
Spring Framework存在远程代码执行漏洞,攻击者可通过该漏洞执行系统命令。
466 1
Spring Framework远程代码执行漏洞复现(CVE-2022-22965)
|
前端开发 Java 数据库连接
【面试题精讲】Spring Framework有哪些模块?
【面试题精讲】Spring Framework有哪些模块?
|
XML Java 数据格式
Spring Framework的核心:IoC容器的实现(1)
Spring Framework的核心:IoC容器的实现(1)
81 0