问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

Spring学习:Spring-Bean实例化(无参构造与有参构造方法实现)详解

创作时间:
作者:
@小白创作中心

Spring学习:Spring-Bean实例化(无参构造与有参构造方法实现)详解

引用
CSDN
1.
https://blog.csdn.net/m0_74363339/article/details/144518036

本文详细介绍了Spring框架中bean的实例化过程,特别是通过构造方法(无参和有参)来实例化bean。文章通过具体的代码示例和步骤讲解,帮助读者理解Spring容器如何管理bean以及如何使用构造方法实例化bean。

一、Spring容器之Bean的实例化

(1)"Bean"基本概念

  • 在Spring框架中,"Bean"这个词经常出现。它的本质上就是对象。
  • Spring容器管理的对象称为Bean。
  • 在Java基础的学习中,创建对象通常都是使用new+构造方法。
  • 对应Spring容器来说,它也是可以通过构造方法完成Bean的创建!

(2)Spring-Bean实例化的几种方式

二、Spring容器使用"构造方法"的方式实例化Bean

(1)无参构造方法实例化Bean

  • 注意:每个类会默认提供一个无参构造方法。就算未写,也是调用了无参构造方法。但如果手动提供了有参构造方法,一般一定记得再手动提供无参构造方法。
  • Spring容器是可以通过无参构造方法实例化Bean的。下面通过Demo(案例)进行演示。

Spring配置文件(目前只配置了"UserDaoImpl"的Bean)

<?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">
    <!--生产UserDao实现类的对象-->
    <bean id="userDao" class="com.fs.dao.impl.UserDaoImpl"></bean>
</beans>

UserDao接口

package com.fs.dao;
//UserDao接口
public interface UserDao {
    void add();
}

UserDaoImpl实现类

package com.fs.dao.impl;
import com.fs.dao.UserDao;
//UserDao接口的实现类
public class UserDaoImpl implements UserDao {
    //手动添加无参构造方法
    public UserDaoImpl() {
        System.out.println("UserDaoImpl无参构造方法执行了");
    }
    //实现UserDao接口中的add方法
    @Override
    public void add() {
        System.out.println("UserDaoImpl执行了add方法");
    }
}

程序的测试类

package com.fs.test;
import com.fs.dao.impl.UserDaoImpl;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//运行测试程序
public class MainApp {
    public static void main(String[] args) {
        //使用IoC容器(ApplicationContext)获取Spring容器管理的Bean对象
        //1.创建容器对象。实例化时参数指定对应的配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        //2.通过<bean>标签的唯一标识id获取对应UserDao接口的实现类"UserDaoImpl"的实例对象
        Object obj = context.getBean("userDao");
        //3.强制类型转换
        UserDaoImpl userDao = (UserDaoImpl)obj;
        userDao.add();
    }
}

Demo的运行结果

如果将无参构造方法public设置成private权限,Spring容器还能够帮忙实例化对象吗?

在以前的new+构造方法时显然是不能够的!但是Spring容器却可以!无论提供的无参构造方法是公共的还是私有的,Spring容器都能够调用到该无参构造方法。

这就是涉及到Spring容器内部底层工作原理——反射机制。这个后面再详细学习,现在只需要知道Spring容器是可以拿构造方法实例化Bean就行了。

是否可以直接不做任何操作让Spring容器使用有参构造方法实例化Bean?

答案是不行的。因为Spring创建的Bean的时候是默认调用无参构造方法。查看Spring的报错信息可以一层一层的往上分析。

(2)有参构造方法实例化Bean

package com.fs.a;
public class Student {
}

上面得Demo中Spring容器默认使用无参构造方法实例化Bean时。当把无参构造方法变成有参构造方法,不仅仅程序中会报错,xml文件中也会报错!因为此时只提供了有参构造方法,而未提供无参构造方法。

1、新建一个类"Student",并交给Spring容器管理。

package com.fs.a;
public class Student {
//类中提供一个有参构造方法
    public Student(String name)
    {
        System.out.println("参数是:"+name);
    }
}

这时像原先通过无参构造方法完成Bean实例化的Spring配置文件已经报错!因为此时只提供了有参构造方法,而未提供无参构造方法。

2、使用子标签完成Bean配置。

  • <bean>标签中的子标签用于指定构造函数参数。这样以便在Spring容器创建Bean时传递给相应的构造函数。
  • "value"属性的值就是给对应有参构造方法的参数变量赋值。
<!--配置Student类的对象-->
    <bean id="student" class="com.fs.a.Student">
        <constructor-arg value="zhangsan"/>
    </bean>

测试类MainApp02代码。也是一样的使用ApplicationContext容器的加载Spring配置文件与getBean()拿取Spring容器管理的对象(Student类)。

package com.fs.test;
import com.fs.a.Student;
import org.springframework.context.support.ClassPathXmlApplicationContext;
//测试类2
public class MainApp02 {
    public static void main(String[] args) {
        //使用IoC容器(ApplicationContext)获取Spring容器管理的Bean对象
        //1.创建容器对象。实例化时参数指定对应的配置文件
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("springConfig.xml");
        //2.通过<bean>标签的唯一标识id获取对应UserDao接口的实现类"UserDaoImpl"的实例对象
        Object obj = context.getBean("student");
        //3.强制类型转换
        Student student = (Student)obj;
        System.out.println(student);
    }
}

3、有参构造方法的参数为多个时(index与value)。

  • 修改Student类的有参构造方法。
package com.fs.a;
public class Student {
//类中提供一个有参构造方法
    public Student(String name,int age)
    {
        System.out.println("参数是:"+name+",年龄是:"+age);
    }
}

此时Spring的配置文件又出现了报错!

在子标签中除了给"value"属性赋值外,还需要指定参数的位置(索引)属性"index"的值,这样一一对应了有参构造方法的参数值。

<?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">
    <!--生产UserDao实现类的对象
    <bean id="userDao" class="com.fs.dao.impl.UserDaoImpl"></bean>-->
    <!--配置Student类的对象-->
    <bean id="student" class="com.fs.a.Student">
        <constructor-arg index="0" value="李四"/>
        <constructor-arg index="1" value="18"/>
    </bean>
</beans>

此时再运行测试类(MainApp02)程序查看结果。

若给int类型的age赋值一个字符串,Spring配置文件中也会报错提示。

删去标签内对应的配置。就会报错(没有默认的无参构造:No default constructor found)

4、标签内使用"name"属性。

  • 用"name"属性指定有参构造方法的参数,就不需要像"index"属性那样需要按顺序去赋值"value"属性。

<1>Spring-Context版本过高需要添加type属性。

  • 如依赖导入Spring-Context(6.2.0)。
  • 在直接指定name="age" value="18" 时无法解析成功!出现异常String无法——>int。
<!--https://mvnrepository.com/artifact/org.springframework/spring-context-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>6.2.0</version>
        </dependency>

解决方法:添加type属性,指定value参数值是int类型。

<2>Spring-Context版本中等不需要添加type属性。

  • 如依赖导入Spring-Context(5.3.18)。
  • 也许是版本低的原因,支持以前的写法(直接使用属性"name"指定对应有参构造方法里的参数,再通过value属性赋值)
       <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.3.18</version>
        </dependency>
<?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">
    <!--生产UserDao实现类的对象
    <bean id="userDao" class="com.fs.dao.impl.UserDaoImpl"></bean>-->
    <!--配置Student类的对象-->
    <bean id="student" class="com.fs.a.Student">
        <constructor-arg name="age" value="18"/>
        <constructor-arg name="name" value="wangwu"/>
    </bean>
</beans>

(3)使用场景

  • 当我们使用第三方的技术时,将它们也交给Spring容器进行管理。学会了使用无参构造与有参构造方法实例化Bean时,就可以直接使用Spring容器管理并获得Bean对象。
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号