最简单的Spring程序
1. Spring的基本结构
在一个最简单的Spring程序中,通常包含以下几个部分:
- Bean:Spring管理的对象,通常是POJO(Plain Old Java Object)。
- ApplicationContext:Spring的IOC(Inversion of Control,控制反转)容器,负责管理Bean的创建和依赖注入。
- 配置文件:Spring XML配置文件或者基于注解的配置,Spring通过这些配置来初始化并管理Bean。
基本示例
代码结构:
css
src
└── main
└── java
├── com.example
│ ├── AppConfig.java
│ ├── UserService.java
│ └── Main.java
└── resources
└── beans.xml
1. 创建Bean(POJO)
这是一个最简单的业务类 UserService
,模拟一个服务层对象。
java
package com.example;
public class UserService {
public void saveUser() {
System.out.println("User saved!");
}
}
2. 配置Bean(XML配置)
在Spring中,beans.xml
是用来定义Bean的配置文件。我们在这里定义 UserService
对象。
XML
<!-- beans.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为userServiceBean的bean,类为UserService 注意这里Class后面是全限定类名 -->
<bean id="userServiceBean" class="com.example.UserService"/>
</beans>
3. 使用Spring容器获取Bean
在 Main.java
中,我们通过Spring的 ApplicationContext
容器来获取 UserService
Bean 并调用其方法。
java
package com.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 加载Spring配置文件并初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 获取userServiceBean
UserService userService = context.getBean("userServiceBean", UserService.class);
// 调用UserService的方法
userService.saveUser();
}
}
详细解释
1.ClassPathXmlApplicationContext("beans.xml")
java
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
ClassPathXmlApplicationContext
是ApplicationContext
的一个实现类,负责从类路径下加载指定的XML文件并初始化Spring容器。- 参数
beans.xml
:- 文件名 :这个参数指定了配置文件的名称。在这个例子中**,
beans.xml
是Spring的配置文件,定义了所有Spring管理的Bean。** - 路径要求 :文件
beans.xml
必须位于类路径下(通常是在src/main/resources
目录中)。Spring会自动查找类路径中的这个文件,并根据配置加载Bean。 - 文件类型 :
beans.xml
是一个标准的XML文件,包含Spring应用的配置,包括Bean的定义、依赖注入等信息。
- 文件名 :这个参数指定了配置文件的名称。在这个例子中**,
注意事项:
ClassPathXmlApplicationContext
只能从类路径中加载文件,确保beans.xml
在类路径中能够被找到。如果文件不在类路径中,可以使用其他实现类如FileSystemXmlApplicationContext
从文件系统中加载配置。
2.context.getBean("userServiceBean", UserService.class)
java
UserService userService = context.getBean("userServiceBean", UserService.class);
getBean(String name, Class<T> requiredType)
:这是ApplicationContext
接口的一个方法,用来从Spring容器中获取一个特定的Bean。这个方法根据指定的Bean名称和类型从容器中返回已初始化的Bean对象。
参数详解:
1. name
("userServiceBean"):
-
这是你在Spring配置文件(
beans.xml
)中定义的Bean的ID。 -
例如,在
beans.xml
中,你可能有这样的Bean定义:XML<bean id="userServiceBean" class="com.example.UserService"/>
在这里,
userServiceBean
是这个UserService
Bean 的ID,必须和配置文件中的id
保持一致。如果ID不匹配,Spring会抛出NoSuchBeanDefinitionException
。
2. requiredType
(UserService.class
):
-
这是Bean的类型,要求Spring返回的Bean对象必须能够被转换为这个类型。
UserService.class
是目标Bean的类型,即类UserService
。 -
这个类型检查是为了确保Spring容器返回的Bean符合预期的类型。如果Bean的实际类型和这里指定的类型不兼容,会抛出
BeanNotOfRequiredTypeException
。 -
requiredType
参数可以省略,比如:javaUserService userService = (UserService) context.getBean("userServiceBean");
- 但是这种方式需要手动进行类型转换(即强制类型转换),不如直接使用
getBean
的泛型版本安全,因为后者会自动进行类型检查。
- 但是这种方式需要手动进行类型转换(即强制类型转换),不如直接使用
注意事项:
name
必须与Spring配置文件中的id
或name
属性一致。requiredType
必须是Bean的实际类型或其父类/接口,如果类型不匹配会抛出异常
Spring对IoC的实现
IoC 控制反转
-
控制反转是一种思想。
-
控制反转是为了降低程序耦合度,提高程序扩展力,达到OCP原则,达到DIP原则。
-
控制反转,反转的是什么?
-
将对象的创建权利交出去,交给第三方容器负责。
-
将对象和对象之间关系的维护权交出去,交给第三方容器负责。
-
-
控制反转这种思想如何实现呢?
- DI(Dependency Injection):依赖注入
依赖注入:
依赖注入实现了控制反转的思想。 Spring通过依赖注入的方式来完成Bean管理的。 Bean管理说的是:Bean对象的创建,以及Bean对象中属性的赋值(或者叫做Bean对象之间关系的维护)。
-
依赖指的是对象和对象之间的关联关系。
-
注入指的是一种数据传递行为,通过注入行为来让对象和对象产生关系。
依赖注入常见的实现方式包括两种:
-
第一种:set注入
-
第二种:构造注入
set注入:
set注入,基于set方法实现的,底层会通过反射机制调用属性对应的set方法然后给属性赋值。这种方式要求属性必须对外提供set方法
什么是 Set
注入?
Setter
注入是一种常用的依赖注入方式,通过Spring容器调用对象的 setter
方法来完成依赖的注入。这种方式常用于当依赖是可选的,或者对象在创建后可以被修改时。与构造器注入相比,Setter
注入的灵活性更高。注意:在实例化对象之后才进行set注入。
Set
注入的工作原理
- Bean定义 :在Spring配置文件(XML或注解)中,定义目标Bean,并使用
property
标签或注解指明哪个属性需要注入。 - Spring容器调用
Setter
方法 :在创建Bean实例后,Spring容器会自动调用相应的setter
方法,将依赖对象注入到Bean中。
代码示例
以下是一个简单的 Setter
注入示例:
1. 创建依赖类 UserDao
java
package com.example;
public class UserDao {
public void save() {
System.out.println("Saving user data...");
}
}
2. 创建服务类 UserService
UserService
依赖于 UserDao
,并使用 Setter
方法来注入这个依赖。
java
package com.example;
public class UserService {
private UserDao userDao;
// Setter方法,用于注入依赖
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void saveUser() {
userDao.save();
System.out.println("User saved by UserService");
}
}
3. Spring XML配置(beans.xml
)
在Spring配置文件中,使用 <property>
标签来实现 Setter
注入。
XML
<!-- beans.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">
<!-- 定义UserDao对象 -->
<bean id="userDaoBean" class="com.example.UserDao" />
<!-- 定义UserService对象,并通过Setter方法注入UserDao依赖 -->
<bean id="userServiceBean" class="com.example.UserService">
<!-- 注入依赖,通过setUserDao方法 -->
<property name="userDao" ref="userDaoBean" />
</bean>
</beans>
4. 使用 ApplicationContext
获取 UserService
Bean
java
package com.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 加载Spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 获取userServiceBean
UserService userService = context.getBean("userServiceBean", UserService.class);
// 调用UserService的方法
userService.saveUser();
}
}
4. 关键知识点
1. property
标签
-
在Spring的XML配置文件中,
<property>
标签用于指定要注入的属性。 -
name
属性对应Bean类中的setter
方法的属性名。 -
ref
属性指定要注入的依赖Bean的ID。XML<property name="userDao" ref="userDaoBean" />
-
name
:对应UserService
类中的setUserDao
方法中的userDao
属性(set方法的方法名,去set,然后把剩下的单词首字母变小写)。 -
ref
:引用了userDaoBean
,这个Bean在Spring配置文件中定义(指定的是要注入的bean的id)。
2. Spring的 Setter
注入流程
- 创建Bean :Spring首先会根据配置文件中的
<bean>
元素创建对象实例 (如UserService
)。 - 调用
Setter
方法 :对象实例创建后,Spring会根据<property>
标签的配置,调用相应的setter
方法(如setUserDao
),将依赖对象注入到目标对象中。
构造注入:
构造器注入是通过构造函数来注入对象的依赖。Spring会根据构造函数的参数来识别需要注入的依赖,并在实例化对象时注入这些依赖。注意和set注入不同,set注入是实例化对象之后。
3. 代码示例
1. 依赖类 UserDao
java
package com.example;
public class UserDao {
public void save() {
System.out.println("UserDao: Saving user data...");
}
}
2. 服务类 UserService
(使用构造器注入)
UserService
依赖 UserDao
,并通过构造函数注入 UserDao
对象。
java
package com.example;
public class UserService {
private UserDao userDao;
// 构造器,用于注入依赖
public UserService(UserDao userDao) {
this.userDao = userDao;
}
public void saveUser() {
userDao.save();
System.out.println("UserService: User saved.");
}
}
3. Spring XML配置(beans.xml
)
在Spring配置文件中,通过 constructor-arg
元素来配置构造器注入。
单个参数
XML
<!-- beans.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">
<!-- 定义UserDao对象 -->
<bean id="userDao" class="com.example.UserDao" />
<!-- 定义UserService对象,通过构造器注入UserDao依赖 -->
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userDao"/>
</bean>
</beans>
多个参数
CustomerService:
java
package spring6.service;
import spring6.Dao.UserDao;
public class CustomerService {
private UserDao userDao;
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public CustomerService(UserDao userDao2) {
this.userDao = userDao2;
}
public void save(){
userDao.insert();
}
}
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">
<bean id="userDaoBean2" class="spring6.Dao.UserDao">
</bean>
<bean id="customerService" class="spring6.service.CustomerService">
<!-- <property name="userDao2" ref="userDao2"/>-->
<!-- index属性指定参数下标,第一个参数是0,第二个参数是1,第三个参数是2,以此类推-->
<!-- ref属性用来指定注入的bean的id-->
<constructor-arg index="0" ref="userDaoBean2"/>
</bean>
<bean id="customerService2" class="spring6.service.CustomerService">
<!-- 根据构造方法参数的名字进行注入-->
<constructor-arg name="userDao2" ref="userDaoBean2"/>
</bean>
</beans>
- 使用
ApplicationContext
获取UserService
Bean
java
package com.example;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Main {
public static void main(String[] args) {
// 加载Spring配置文件并初始化容器
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 获取userService对象
UserService userService = context.getBean("userService", UserService.class);
// 调用UserService的方法
userService.saveUser();
}
}
4. 关键知识点
1. constructor-arg
标签
constructor-arg
标签用于Spring的XML配置中,用来配置构造器注入。
2. ref属性
单个参数
ref
属性指定要注入的Bean的ID,这个引用会在目标类的构造函数中被传入。
XML
<constructor-arg ref="userDao"/>
多个参数
1. index
属性
index
属性用于明确指定构造函数参数的顺序位置。Spring会根据构造函数中参数的位置来注入对应的Bean。这种方式在构造函数有多个参数时非常直观和有效,尤其是多个参数类型相同的情况下。
代码中的示例:
XML
<constructor-arg index="0" ref="userDaoBean2"/>
index="0"
:表示将userDaoBean2
注入到构造函数的第一个参数位置。- 如果构造函数有多个参数,
index
指定了注入的顺序。0
表示第一个参数,1
表示第二个参数,依此类推。
2. name
属性
name
属性用于通过参数的名称(构造函数中声明的参数名)来注入Bean。Spring通过反射机制获取构造函数的参数名称,并根据这个名称来进行依赖注入。
XML
<constructor-arg name="userDao2" ref="userDaoBean2"/>
name="userDao2"
:表示将userDaoBean2
注入到名为userDao2
的构造函数参数中。- 这种方式要求构造函数的参数名称必须与
name
属性的值匹配。
举例 :
1. 构造函数基础
构造函数是一个类的特殊方法,用于在创建该类的对象时进行初始化。在Java中,一个类可以有多个参数的构造函数,这意味着你在创建对象时可以传递多个值进行初始化。
例如,下面的 CustomerService
类的构造函数有两个参数:
java
public class CustomerService {
private UserDao userDao;
private OrderDao orderDao;
// 构造函数有两个参数
public CustomerService(UserDao userDao, OrderDao orderDao) {
this.userDao = userDao;
this.orderDao = orderDao;
}
}
这个构造函数有两个参数:UserDao
和 OrderDao
。在创建 CustomerService
对象时,必须同时提供这两个依赖。
2. Spring 中的多个构造函数参数
当你在Spring中使用构造器注入时,如果你的类的构造函数有多个参数,你需要告诉Spring应该如何注入这些依赖。Spring有多种方式处理这些参数,比如通过参数的顺序、参数的类型或者通过参数的名称。
示例:多个构造函数参数的构造器注入
java
public class CustomerService {
private UserDao userDao;
private OrderDao orderDao;
// 构造函数有两个参数
public CustomerService(UserDao userDao, OrderDao orderDao) {
this.userDao = userDao;
this.orderDao = orderDao;
}
}
在这个示例中,CustomerService
的构造函数需要两个对象:UserDao
和 OrderDao
。
3. Spring XML 配置 - 指定多个构造函数参数
使用 index
属性指定参数顺序
XML
<bean id="userDao" class="com.example.UserDao"/>
<bean id="orderDao" class="com.example.OrderDao"/>
<bean id="customerService" class="com.example.CustomerService">
<constructor-arg index="0" ref="userDao"/>
<constructor-arg index="1" ref="orderDao"/>
</bean>
使用 name
属性指定参数名称
XML
<bean id="userDao" class="com.example.UserDao"/>
<bean id="orderDao" class="com.example.OrderDao"/>
<bean id="customerService" class="com.example.CustomerService">
<constructor-arg name="userDao" ref="userDao"/>
<constructor-arg name="orderDao" ref="orderDao"/>
</bean>
在这个配置中:
name="userDao"
和name="orderDao"
表示注入的对象是根据构造函数中的参数名称匹配的。
在开发中如果 需要自动实例化dao包中的对象的话到底应该怎么做?
通常**,我们需要自动实例化dao包中的对象,需要在Service层中使用Dao中的类**。如果不使用spring的话,通常需要在 Service
层手动编写对象实例化的代码,如 new DaoClass()
。这种方式虽然简单直观,但在复杂的应用中,当对象之间的依赖关系较多时,手动管理这些依赖关系将变得困难,并且会导致代码难以维护和扩展。
如果运用spring,spring中的spring.xml中可以实现自动实例化,来自动管理对象的创建和依赖关系,这样就能方便一点
所以说spring.xml到底应该如何配置呢?
1. DAO类的实例化
首先,你需要在XML文件中为DAO类定义一个Bean。假设你有一个名为UserDao
的DAO类:
XML
<bean id="userDao" class="com.example.dao.UserDao"/>
这样,Spring就会自动实例化一个UserDao
对象,并将其放入Spring容器中,ID为userDao
。
2. 在Service中注入DAO类
接下来,在Service类中,你需要通过依赖注入的方式将UserDao
传递给Service类。假设你的Service类是UserService
,并且有一个UserDao
类型的属性(通常是通过setter
方法或者构造方法来注入的)。
2.1 通过Setter注入
如果UserService
类中有setUserDao(UserDao userDao)
方法,XML配置可以这样写:
XML
<bean id="userService" class="com.example.service.UserService">
<property name="userDao" ref="userDao"/>
</bean>
<property>
:表示为userService
Bean的属性设置值。name
:表示UserService
类中的userDao
属性。ref
:引用了Spring容器中ID为userDao
的Bean。
2.2 通过构造方法注入
如果你希望通过构造方法注入UserDao
,并且UserService
类有一个构造方法是public UserService(UserDao userDao)
,XML配置可以这样写:
XML
<bean id="userService" class="com.example.service.UserService">
<constructor-arg ref="userDao"/>
</bean>
<constructor-arg>
:表示构造方法参数的引用。ref
:表示注入的Bean,即userDao
。
3. Service与DAO的关系总结
- DAO层负责直接与数据库进行交互,如增删改查操作。
- Service层负责业务逻辑处理,它会调用DAO层的方法来处理数据库中的数据。
在Spring中,通过依赖注入,Service层不需要自己去创建DAO层的对象,Spring会自动实例化DAO层,并将它注入到Service层。