最简单的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是这个UserServiceBean 的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获取UserServiceBean
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>:表示为userServiceBean的属性设置值。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层。