我们将开发第一个Spring程序,读者应安装了IDEA工具,正确配置了Maven环境和JDK17
。在开发完后,我们会从10个细节来对这个程序进行详细的剖析。
为了使用Spring框架来管理对象,我们必须要引入Spring框架的基础依赖,在pom文件中添加下述依赖项:
<dependency>
<groupId>org.springframeworkgroupId>
<artifactId>spring-contextartifactId>
<version>6.2.5version>
dependency>
添加上述依赖后,通过IDEA的依赖分析工具,可以发现,spring-aop
、spring-beans
、spring-core
和spring-expression
四个jar包(还会引入io.micrometer:micrometer-observation
,我们暂时不考虑)都会被引进来。
被Spring容器管理的对象,我们称为Bean
。首先,我们先来定义一个Bean:
package com.selflearn.springbase.fristapp.bean;
/**
* 用户实体类
*/
public class User {
}
一开始,我们并不需要这个对象里面存在字段或方法,我们先来看看Spring是怎么创建Bean的。接下来,需要编写Spring的配置文件,在这里,我们定义一个first-app.xml
:
<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">
<bean id="userBean" class="com.selflearn.springbase.fristapp.bean.User"/>
beans>
如果是使用IDEA工具自动生成配置文件的话,我们仅需在
标签中,添加
标签即可。
在上述配置中,我们使用了bean
标签。在Spring中,bean
标签用于定义和配置Spring容器中的实体。在这里,我们使用了bean
标签的两个基本属性:id
和class
,这两个属性的作用如下:
id
:bean在Spring中的唯一标识符,在其他地方需要用这个id来引用此bean;class
:通过指定一个类的全限定名(即包括包名的完整类名),Spring容器就知道要实例化哪个类的对象。当然,bean
标签中除了这两个属性,还有其他属性,我们在后面的学习中会进行讨论。
bean定义好了,Spring配置文件也就编写好了,接下来,我们写一个测试程序,来进行测试:
package com.selflearn.springbase.fristapp;
import com.selflearn.springbase.fristapp.bean.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
/**
* 测试程序
*/
public class TestApplication {
public static void main(String[] args) {
// 获取Spring容器
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("first-app.xml");
// 从容器中获取对象
Object obj = applicationContext.getBean("userBean");
// 输出对象
System.out.println(obj);
}
}
执行结果:com.selflearn.springbase.fristapp.bean.User@5e17553a
通过代码执行结果可以看出,User
对象确实被创建出来了。但代码中,我们并没有显式地使用new User()
来创建对象,这说明Spring帮我们创建了。
在上述程序中,new ClassPathXmlApplicationContext("first-app.xml")
构造函数的执行,会解析first-app.xml
配置文件,从中读取并创建bean
。需要获取对象时,我们仅需调用getBean()
方法就可以获取到对应的对象实体。
建议:大家可以使用这种方法来优化下Spring学习笔记【01】Spring启示录中的程序。
接下来,我们将通过下述10个问题,来深入刨析下上面的程序:
bean
标签的id
属性可以重复吗?
id
是bean在Spring容器中的唯一标识,不可以重复。
在配置文件,可以再加一行同样的配置:
<bean id="userBean" class="com.selflearn.springbase.fristapp.bean.User"/>
<bean id="userBean" class="com.selflearn.springbase.fristapp.bean.User"/>
再启动测试程序的时候,会有如下报错:
Exception in thread "main" org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem: Bean name 'userBean' is already used in this element
Offending resource: class path resource [first-app.xml]
对象是怎么创建的?
对象是通过类的无参构造来创建的(通过反射)。
我们修改实体类如下:
/**
* 用户实体类
*/
public class User {
public User() {
System.out.println("User的无参构造被调用了...");
}
}
再执行测试程序,会得到下面的结果:
User的无参构造被调用了...
com.selflearn.springbase.fristapp.bean.User@5e17553a
由此可见,无参构造的确被调用了。大家可以试下,如果不提供无参构造的话会发生什么?
Spring是通过什么数据结构来管理bean的?
Spring底层是通过Map
集合来管理bean的。
Spring的配置文件的名字是固定的吗?
显然不是固定的,first-app
就是我们随便起的名字,你可以尝试下改个名字试试。
可以由多个Spring配置文件吗?
可以配置多个,通过传入多个参数来读取:
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("first-app.xml", "test.xml");
Spring配置文件中的类必须是自定义类吗?
不一定,也可以是Java的内置类,但是该类不能是抽象类,而且必须提供无参构造。
<bean id="str" class="java.lang.String"/>
如果使用getBean()
方法获取一个不存在的id会怎样?
如果没有定义的话,会报错。
Exception in thread "main" org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'userBean1' available
getBean()
只能得到Object
对象吗?
当然不是,可以通过以下方法获取对应类的实体:
User user = applicationContext.getBean("userBean", User.class);
ClassPathXmlApplicationContext
是怎么读取配置文件的?
从类路径下加载配置文件,如果没有类路径的话,要通过FileSystemXmlApplicationContext
来根据类系统路径加载配置文件。
我们用ApplicationContext
来表示容器,那ApplicationContext
是个什么东西?
ApplicationContext
是一个高级接口,继承了BeanFactory
接口。其中,BeanFactory
是Spring中的超级接口,就好比Java中的Object
。
[1] 动力节点Spring6教程
[2] DeepSeek