目录
一、创建 Bean 对象
二、将Bean对象存储到 Spring容器中
三、创建 Spring 上下文(得到一个Spring容器)
1. 通过在启动类中 ApplicationContext 获取一个 Spring容器
2. 通过在启动类种使用 BeanFactory 的方式来得到 Spring 对象 (此时获取 Bean 的路径也要保持一致)
四、从 Spring 容器中获取到 Bean 对象(并使用Bean对象)
1. 通过名称(.xml文件中设置的 id )
使用Applicationcontext 和 BeanFactory 的区别
(1)所以二者的区别之一:
(2)第二个区别:
2. 通过类型的方式获取 Bean 对象
3. 通过名称 + 类型的方式获取 Bean 对象
(1)先在.xml 文件中存储两个相同的 Bean 对象,然后再进行验证。
四、什么是DI(依赖注入)
前言
上一篇文章已经详细介绍了如何创建一个 Spring 项目,在创建好了 Spring 项目之后,就需要使用 Spring 容器存储和获取 Bean 对象了。
(Bean对象:在Java中,如果一个对象被使用多次,此时就可以成这个对象为 Bean 对象)
一、创建 Bean 对象
public class Student {
private void sayHi() {
System.out.println("Hii student");
}
}
二、将Bean对象存储到 Spring容器中
此时存储 Bean 对象是要依赖于xml配置文件的,里面要有一些配置信息,之后才能将 Bean对象存储到 Spring 容器中,如下图:
<?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:content="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<content:component-scan base-package="com.bit.service"></content:component-scan>
</beans>
之后将上述代码复制到创建的配置文件 spring-config.xml 文件中
在上述配置文件中添加下边代码:
<!--将 bean对象(com.spring.demo.Student)存到spring容器中,他的名称叫做student -->
<bean id="student" class="com.spring.demo.Student"></bean>
此时就把一个 Bean 对象(Student类)存储到 Spring 中了,接下来就是取出 Bean 对象了。
三、创建 Spring 上下文(得到一个Spring容器)
要想得到一个 Spring 容器有两种方式:
1. ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml"); |
2. //1. 得到Spring上下文对象 BeanFactory beanFactory = new XmlBeanFactory(new ClassPathResource("spring-config.xml")); |
1. 通过在启动类中 ApplicationContext 获取一个 Spring容器
此时需要注意:参数中的配置路径就是.xml 文件的名称,只有设置了这个文件名称,在程序运行的时候才会去这个文件中将 Bean 对象存储到 Spring 容器中。
2. 通过在启动类种使用 BeanFactory 的方式来得到 Spring 对象 (此时获取 Bean 的路径也要保持一致)
四、从 Spring 容器中获取到 Bean 对象(并使用Bean对象)
获取 Bean 对象有三种方式:(用的方法都是一样的,只是getBean()方法的传的参数不同)
1. 通过名称获取 |
2. 通过类型获取 |
3. 通过名称 + 类型的方式获取 |
1. 通过名称(.xml文件中设置的 id )
//2. 从Spring容器中获取到Bean对象
Student student = (Student) context.getBean("student");
//3.使用Bean对象
student.sayHi();
此时需要 注意:getBean方法中的参数是 Bean 对象中的名称,此时需要和 spring-config.xml 文件中的 Bean 对象的 id 设置的名称保持相同。
获取 Bean 对象之后我们可以使用 Student 类的sayHi方法证明以下 Bean 对象是否可以正常使用:
使用BeanFactory的方式获取并使用 Bean对象
使用Applicationcontext 和 BeanFactory 的区别
此时再创建一个新的Teacher类,然后在Student 和 Teacher 类中都加上构造方法,如下代码:
public class Student {
public Student() {
System.out.println("do student init");
}
public void sayHi() {
System.out.println("Hii student");
}
}
public class Teacher {
public Teacher() {
System.out.println("do teacher init");
}
public void sayHi() {
System.out.println("Hii Teacher");
}
}
此时再去用 ApplicationContext 和 Beanfactory就可以看到以下运行结果:
在App中并没有获取 Teacher 对象,但是此时却加载了 Teacher 类的构造方法,而BeanFatory只会在 getBean() 方法调用了之后才会加载初始化 Student 对象。
(1)所以二者的区别之一:
在使用 ApplicationContext 时是饿汉模式,当得到一个 Spring 容器的时候就初始化了所有的 Bean 对象的,但是使用 BeanFactory 时是懒汉模式(非必要不加载),也就是只有在获取 Bean 对象的时候才会去初始化这个对象。
这也是一个历史性的原因,在早期内存是比较昂贵的时候,是没有很大的存储空间,在一开始就初始化很多 Bean 对象的,但是随着后来的内存的价格相对不是很昂贵了,此时也就有多余的内存空间来存储很多的 Bean 对象了,尽管 Spring 是一个容器,但是底层存储的 Bean 对象本质还是在内存上存储的。
ApplicationContext的优点和缺点: | 一次 Spring 容器的加载,就会初始化里面的所有 Bean 对象,后续在读取 Bean 对象读取的就会非常快; 性能较高,但是同样的也会比较耗费内存。 |
BeanFactory的优点和缺点: | 是在getBean() 方法调用之后才会加载初始化 Bean 对象,所以性能比较低; 但是节省内存。 |
(2)第二个区别:
BeanFactory 是 ApplicationContext 的一个子类,所以ApplicationContext是后来有的,基于 BeanFactory又拓展了新的功能特性。
按下F4键之后,我们可以看到如下图:
2. 通过类型的方式获取 Bean 对象
虽然通过名称是可以获取到 Student 对象,但是需要强转之后才能获取,因为 getBean 方法的返回值是一个Object类型的,所以用 Student 类型的去接收返回值就需要强制类型转换;所以代码看起来好像不是很优雅,此时就可以通过对象的类型来获取一个 Bean 对象。
Student student = context.getBean(Student.class);//根据类型获取
此时的运行结果如下:
但是这种方式获取Bean 对象也是有问题的;如果此时有两个同类型的 Bean 对象,此时再去通过类型的方式来获取Bean 对象就会报如下图的错误,因为类型一样时,程序不知道该获取哪一个对象,所以此时虽然不用强转了,但是同类型的 Bean 对象只能有一个。
3. 通过名称 + 类型的方式获取 Bean 对象
首先注意一个问题:如果在 Spring 容器中存储同一个对象,存储两份,此时是有两个对象呢,还是只有一个对象,另一个对象的引用指向了第一个对象呢?
(1)先在.xml 文件中存储两个相同的 Bean 对象,然后再进行验证。
运行结果:
也就是说首先是允许存储两个相同的 Bean 对象的,但是此时结果是false,所以是在 Spring 容器中存储了两份 Bean 对象的。(每一次存储 Bean 对象的时候,不会因为类型相同就只创建一个对象)
根据名称 + 类型的方式来获取Bean 对象也是可以的,如下图结果:
四、什么是DI(依赖注入)
Student student = context.getBean("student",Student.class);//根据类型获取
上述代码就是依赖注入,就是DI,上一篇文章讲到IoC是一种思想,DI就是它的一种具体的实现方式,所以上面代码就是在程序运行的过程中动态的将 student 对象动态注入到当前运行的动态类中。