Spring系列:聊聊Spring工厂对象创建与Spring的注入

前言

本章主要对Spring工厂创建对象,以及Spring框架中的注入做一个#简单的说明。

1. Spring工厂创建对象原理讨论

1. 通过Spring工厂创建对象,重要有如下几步:
# 第一步:创建一个Account实体类
# 第二步:到applicationContext.xml中配置Account
# 第三步:测试-->创建工厂,读取applicationContext.xml配
置文件,并通过工厂对象中的方法getBean()获取Accout这个id属
性所对应的这个对象。

2. 对Spring工厂创建对象原理简单说明
⑴ 首先我们通过"读取Spring的配置文件applicationContext.xml" 
来创建Spring的工厂---->其次通过创建的工厂调用'getBean()'获取配
置文件中定义的<bean id="xxx">中的id值获取对象--->注意:它这边
的通过Spring工厂获取的对象实际底层是通过'反射'来创建对象,反射创
建Account对象(Account account = new Account()--->反射在创建
对象的同时也是会调用对象的构造方法的就是上面说的Account account 
= new Account();--->所以说Spring工厂它创建对象的底层实际上是通
过反射来调用对象的构造方法,创建对象的。--->所以类对象必须存在构
造方法,才可以实现对象的创建。

------------------------------------------------------

3. 对于实体类是否需要Spring工厂来进行创建呢?
答案就是:所有实体对象是不会交给Spring创建的,他是由持久层框架来
创建的。因为它需要数据,而数据来源于数据库,而Spring是不知道数据
库的。


2. Spring的注入

2.1 什么是注入

注入:通过Spring工厂及配置文件,为所创建对象的成员变量赋值。

2.2 Spring实现注入有两种方式

  1. Spring实现注入有两种方式:Set注入 + 构造注入。

2.3 方式一:Set注入

2.3.1 Set注入实战

1. 要使用"注入"为成员变量赋值的话,需要做的准备为↓:
⑴ 第一步:在类层面:在类Person中为成员变量提供Get/Set方法。
⑵ 第二步:配置Spring的配置文件(applicationContext.xml)
<bean id="person" class="com.spring5.demo01.entity.Person">
    <!--
    <property>标签中的name的值应与实体配Person中的属性值对应
    -->
    <property name="id">
        <value>10</value>
    </property>
    <property name="name">
        <value>xiaoming</value>
    </property>
</bean>

⑶ 第三步:测试
/**
 * 通过Spring配置文件进行赋值
 */
@Test
public void test8() {
    //1.指定配置文件,创建Spring工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    //利用bean中name属性指定的别名来获取bean
    Person person = (Person)ctx.getBean("person");
    System.out.println(person);
}

-----------------------------------------------

2. 注入的好处
⑴ 解耦合:日后只要是对Person对象的值不满意了,我无需去对代码
层面进行修改,只需要直接在applicationContext.xml中去修改
即可。因为我们改的是配置文件,因此它不涉及重新编译以及重新
部署的过程,他就直接将Person中的值修改了。

2.3.2 对Spring注入原理的简单说明

1. 对Spring注入原理的简单说明(底层需要Set()方法):
--->实现Spring的注入过程中,我们主要是在Spring的配置
文件中利用<Property>标签对对象的'成员变量'进行赋值,但是
实际上配置文件applicationContext.xml中的<Property>标签
底层实际上等效于是调用了对象的'Set()'方法来实现'对象成员
变量的赋值的。因此我们要实现Spring注入操作,必须给对象加上
Set()方法才可以实现在Spring配置文件利用<Property>标签
完成对象'成员变量'的赋值操作。

2.3.3 Spring注入-JDK内置类型

1. JDK内置类型
⑴ 若对象中的成员变量的类型属于:String类型 + 8种基本数据类型
--->对于以上的类型在<property>里面使用的是"<value>标签"来实现赋值。
<property name="id">
    <value>10</value>
</property>
<property name="name">
    <value>xiaoming</value>
</property>


⑵ 若对象中的成员变量的类型属于:数组类型
--->对于以上的类型在<property>里面使用的是<list>中嵌套<value>
<property name="emails">
    <list>
       <value>aaa@123.com.cn</value>
       <value>bbb@123.com.cn</value>
       <value>ccc@123.com.cn</value>
    </list>
</property>

⑶ 若对象中的成员变量的类型属于:List集合类型
- 注意:我们这里用的<list>标签与字段类型是"数组"用到的<list>是
同一个标签,因为List集合的底层也是用数组来完成的。
--->List集合在配置文件的用法,如下所示↓:
<property name="addresses">
    <list>
        <value>aaa111</value>
        <value>bbb222</value>
        <value>ccc333</value>
    </list>
</property>



------------------------------------------------


2. 以上涉及的实体类对象和配置文件(applicationContext.xml)以及测试类汇总,如下所示↓:
⑴ 实体类Person
@Data
@ToString
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    private Integer id;
    private String name;
    private String[] emails; 
    private List<String> addresses; 
}

⑵ Spring配置文件(applicationContext.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">

    <!--
        id:属性名字(唯- )
        class:属性配置全限定名(包名.类名)
    -->
    <bean id="person" class="com.spring5.demo01.entity.Person">
   <!--
    <property>标签中的name的值应与实体配Person中的属性值对应
    -->
        <property name="id">
            <value>10</value>
        </property>
        <property name="name">
            <value>xiaoming</value>
        </property>
        <property name="emails">
            <list>
               <value>aaa@123.com.cn</value>
               <value>bbb@123.com.cn</value>
               <value>ccc@123.com.cn</value>
            </list>
        </property>
        <property name="addresses">
            <list>
                <value>aaa111</value>
                <value>bbb222</value>
                <value>ccc333</value>
            </list>
        </property>


    </bean>
</beans>

⑶ 测试类
/**
 * 用于测试:JDK类型成员变量的赋值
 */
@Test
public void test9() {
    //1.指定配置文件,创建Spring工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    //利用bean中name属性指定的别名来获取bean
    Person person = (Person)ctx.getBean("person");
    String[] emails = person.getEmails();
    for (String email : emails) {
        System.out.println("eamil = " + email);
    }
    System.out.println("-----------------------");

    List<String> addresses = person.getAddresses();
    for (String a : addresses) {
        System.out.println("addresses = " + a);
    }
}

2.3.4 Spring注入-用户自定义类型

1. 由于UserDAO是我们自定义的一个类型,因此下面演示如何
使用Set实现自定义类型的注入的两种方式。
➀ 第一种方式:
⑴ 第一步:声明对象下自定义的成员变量"UserDAO"。通过Spring的方式完成
Set的注入。
/**
 * 通过Spring的Set方式完成自定义类型的注入
 */
private UserDAO userDAO;

⑵ 第二步:声明完自定义的成员变量"UserDAO",提供UserDAO的
Get和Set方法。
▲ 注意:我们给"自定义的成员变量"UserDAO",提供UserDAO的Get
和Set方法"的目的是因为Spring底层在帮我们利用Set实现注入的
过程中需要用到Get和Set方法。因此我们需要提供"成员变
量"UserDAO"的Get和Set方法"。

public UserDAO getUserDAO() {
    return userDAO;
}

public void setUserDAO(UserDAO userDAO) {
    this.userDAO = userDAO;
}

⑶ 第三步:通过Spring的配置文件(applicationContext.xml)为
我们自定义的类型"UserDAO"进行赋值。
<bean id="userService" class="com.spring5.demo01.service.UserServiceImpl">
    <property name="userDAO">
        <!-- 表示:将UserDAOImpl对象赋值给上面property标签中的userDAO成员变量的方式 -->
        <!--下面没有写id,是因为这个bean只在这里使用一次,且没有人去引用这个bean,因此id不写也可以-->
        <bean class="com.spring5.demo01.dao.UserDAOImpl" />
    </property>
</bean>

⑷ 第四步:测试:
/**
 * 用于测试:用户自定义类型成员变量的赋值
 */
@Test
public void test10() {
    //1.指定配置文件,创建Spring工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    //利用bean中name属性指定的别名来获取bean
    UserService userService = (UserService) ctx.getBean("userService");
    userService.register(new User(1,"hhh","hhh123456"));
    userService.login("admin","123123");
}

⑸ 具体的UserServiceImpl类的代码,如下所示↓:
public class UserServiceImpl implements UserService {
//    private UserDAO userDAO = (UserDAO) BeanFactory.getBean("userDAO");

    /**
     * 通过Spring的Set方式完成自定义类型的注入
     */
    private UserDAO userDAO;

    public UserDAO getUserDAO() {
        return userDAO;
    }

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    //注册
    public void register(User user) {
        userDAO.save(user);
    }

    //登录
    public void login(String name, String password) {
        userDAO.queryUserByNameAndPassword(name,password);
    }
}


-----------------------------------------------------------

➁ 第二种方式
--->为什么要增加自定义类型注入的第二种方式呢?是因为
第一种方式实现注入存在问题
⑴ 配置文件代码冗余
-->配置文件中相同代码被配置多次。
⑵ 被注入的对象(UserDAO),多次创建,浪费(JVM)内存资源
-->相同的类配置多次,以此造成JVM虚拟机的内存资源的浪费问题。

⑶ 以上两个问题,如图所示-"图-方式一问题"
⑷ 第二种方式代码演示,如下所示↓:
- 步骤一:为成员变量提供Get和Set方法
    /**
     * 通过Spring的Set方式完成自定义类型的注入
     */
    private UserDAO userDAO;

    public UserDAO getUserDAO() {
        return userDAO;
    }

    public void setUserDAO(UserDAO userDAO) {
        this.userDAO = userDAO;
    }
    
- 步骤二:配置文件中进行配置
<bean id="userDAO" class="com.spring5.demo01.dao.UserDAOImpl" ></bean>
<bean id="userService" class="com.spring5.demo01.service.UserServiceImpl">
    <property name="userDAO">
        <ref bean="userDAO"/>
    </property>
</bean>

- 步驟三:測試
/**
 * 用于测试:用户自定义类型成员变量的赋值
 */
@Test
public void test10() {
    //1.指定配置文件,创建Spring工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    //利用bean中name属性指定的别名来获取bean
    UserService userService = (UserService) ctx.getBean("userService");
    userService.register(new User(1,"hhh","hhh123456"));
    userService.login("admin","123123");
}


2.4 方式二:构造注入

1. Spring构造注入的开发步骤分为两步,如下所示↓:
⑴ 第一步:提供有参构造方法
# 创建Customer对象,提供有参构造
public class Customer implements Serializable {
    private String name;
    private int age;

    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    @Override
    public String toString() {
        return "Customer{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

⑵ 第二步:Spring配置文件的配置
# 利用配置文件applicationContext.xml对属性赋值,实现注入
<bean id="customer" class="com.spring5.demo02.constructer.Customer">
    <!--
        一个<constructor-arg>标签对应构造方法当中的一个参数。
        意思就是说:若构造方法有两个入参,就需要在这边定义两个"<constructor-arg>标签"
    -->
    <constructor-arg>
        <!-- <constructor-arg>便签里面写上具体的赋值 -->
        <!--给name赋值-->
        <value>aaa</value>
    </constructor-arg>

    <constructor-arg>
        <!--给age赋值-->
        <value>102</value>
    </constructor-arg>
</bean>

⑶ 第三步:测试给Customer对象注入的值是否成功
/**
 * 用于测试:构造注入
 */
@Test
public void test11() {
    //1.指定配置文件,创建Spring工厂
    ApplicationContext ctx = new ClassPathXmlApplicationContext("/applicationContext.xml");
    //2.获取bean定义的对象
    Customer customer = (Customer) ctx.getBean("customer");
    System.out.println(customer);
}
--->测试结果,如图所示-"图-构造注入结果"。

在这里插入图片描述

图-构造注入结果

3. 注入总结

1. Spring的注入方式有两种:Set注入 + 构造注入
--->虽然这两种注入的方式有所不同,但是它们最终达到的效果都
是一样的,都是通过Spring的配置文件给对象的'成员变量'赋值。


----------------------------------------------


2. 未来实战当中,使用'Set注入'还是'构造注入'中的哪一种呢?
答案:使用'Set注入'会更多,原因有如下几点↓:
⑴ 原因一:构造注入很麻烦,因为它有重载
⑵ 原因二:Spring框架的底层也是大量的应用了'set注入'


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值