目录
- 1 什么是spring
- 2 spring的优势
- 3 IOC的概念和作用
- 3.1 无参数构造函数的实例化方式
- 3.2 使用工厂中的普通方法实例化对象
- 4 Bean
- 4.1 Bean相关概念
- 4.2 Bean对象的作用范围
- 5 DI
- 5.1 构造函数注入
- 5.2 set方法注入
- 5.3 复杂类型数据注入
- 5.4 基于注解的IOC
- 5.4.1 包扫描
- 5.4.2 @Component
- 5.4.3 由Component衍生的注解
- 5.4.4 @Autowired
- 5.4.5 其他注入数据的注解
- 6 配置类
- 6.1. `@Configuration` 注解
- 6.2 `@Import` 注解
- 6.3 `@PropertySource` 注解
- 6.4 综合示例
1 什么是spring
Spring 是一个开源的 Java 应用框架,旨在简化企业级应用开发。它利用依赖注入(DI)和面向切面编程(AOP)减少代码耦合,提升可测试性和维护性。Spring 核心容器管理应用对象的生命周期和配置。
2 spring的优势
-
简化开发:通过依赖注入(DI)和面向切面编程(AOP),Spring 让代码更加模块化、解耦,减少了样板代码,提升了开发效率。
-
灵活性:Spring 提供了多种配置方式(注解、XML、JavaConfig),支持多种持久化框架和第三方库集成,适应不同的应用需求。
-
测试友好:依赖注入让单元测试和集成测试更加简便,无需依赖运行环境即可快速测试业务逻辑。
-
生态丰富:Spring 有强大的生态系统,包括 Spring Boot(简化配置和部署)、Spring Security(提供安全管理)、Spring Cloud(微服务支持)等,能够满足复杂的应用场景。
-
轻量级:Spring 的核心容器是小巧的,开发者可以选择性地使用需要的模块,避免不必要的依赖。
3 IOC的概念和作用
3.1 无参数构造函数的实例化方式
创建一个XML配置文件(例如 applicationContext.XML)
<bean id="userService" class="com.example.UserService"/>
使用Spring的ApplicationContext加载XML配置文件
// 加载 Spring XML 配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
// 获取 Bean
UserService userService = (UserService) context.getBean("userService");
3.2 使用工厂中的普通方法实例化对象
首先,创建一个工厂类,其中包含一个普通方法来创建 Bean 实例。
package com.example;
public class UserFactory {
public UserService createUserService() {
return new UserService();
}
}
在 Spring 的 XML 配置文件中,配置工厂 Bean 和使用工厂方法来创建 Bean。
<!-- 定义工厂 Bean -->
<bean id="userFactory" class="com.example.UserFactory"/>
<!-- 使用工厂方法来创建 Bean -->
<bean id="userService" factory-bean="userFactory" factory-method="createUserService"/>
4 Bean
4.1 Bean相关概念
-
Bean: 在计算机英语中,有可重用组件(如持久层和业务层的接口和重用)的含义。
-
JavaBean: 其实JavaBean并不完全等于实体类,因为实体类只是可重用组件的一部分,也就是JavaBean的范围大于实体类的范围。
JavaBean的含义:用Java语言编写的可重用组件。
4.2 Bean对象的作用范围
bean标签的scope属性,
作用:用于指定bean的作用范围
取值:
-
singleton:单例的(默认值)
-
prototype:多例的
-
···等
5 DI
依赖注入:Dependency Injection
5.1 构造函数注入
bean标签内部的constructor-arg标签
标签中的属性:
- name:用于给构造函数中指定名称的参数赋值
- value:用于提供标准类型和String类型的数据
- ref:用于指定其他的bean类型数据(就是在ioc容器中出现过的bean对象)
需要提供一个含参数的构造器
public class Account{
private Integer id;
private String name;
public Account(Integer id,String name){
this.id = id;
this.name = name;
}
}
<bean id = "account" class = "com.example.Account">
<constructor-arg name = "id" value = 10></constructor-arg>
<constructor-arg name = "name" value ="张三"></constructor-arg>
</bean>
5.2 set方法注入
bean标签内部的property标签
标签的属性:
- name:用于给构造函数中指定名称的参数赋值
- value:用于提供标准类型和String类型的数据
- ref:用于指定其他的bean类型数据(就是在ioc容器中出现过的bean对象)
需要提供set方法
public class Account{
private Integer id;
private String name;
public void setId(Integer id){
this.id = id;
}
public void setName(String name){
this.name = name;
}
}
<bean id="account" class="com.example.Account">
<property name = "id" value = 10></property>
<property name = "name" value ="张三"></property>
</bean>
5.3 复杂类型数据注入
在 Spring 框架中,除了注入简单的类型(如 String
、int
等),还可以注入复杂类型的数据,例如 List
、Set
、Map
和 Properties
。这些复杂类型的数据可以通过 property
标签及其子标签来配置。
package com.example;
public class UserService {
private List<String> emails;
private Set<String> phoneNumbers;
private Map<String, String> userRoles;
private Properties props;
public void setEmails(List<String> emails) {
this.emails = emails;
}
public void setPhoneNumbers(Set<String> phoneNumbers) {
this.phoneNumbers = phoneNumbers;
}
public void setUserRoles(Map<String, String> userRoles) {
this.userRoles = userRoles;
}
public void setProps(Properties props) {
this.props = props;
}
}
<bean id="userService" class="com.example.UserService">
<!-- 注入 List -->
<property name="emails">
<list>
<value>john@example.com</value>
<value>jane@example.com</value>
</list>
</property>
<!-- 注入 Set -->
<property name="phoneNumbers">
<set>
<value>+123456789</value>
<value>+987654321</value>
</set>
</property>
<!-- 注入 Map -->
<property name="userRoles">
<map>
<entry key="john" value="admin"/>
<entry key="jane" value="user"/>
</map>
</property>
<!-- 注入 Properties -->
<property name="props">
<props>
<prop key="language">English</prop>
<prop key="country">USA</prop>
</props>
</property>
</bean>
</beans>
5.4 基于注解的IOC
5.4.1 包扫描
使用注解时要告知spring在创建容器时要扫描的包
<context:component-scan base-package="com.example"></context:component-scan>
5.4.2 @Component
-
用法:定义在类名上
-
作用:用于把当前类对象存入spring容器中
-
属性:value:用于指定bean的id,默认值是类名(首字母小写)
5.4.3 由Component衍生的注解
- @Controller:一般用在表现层
- @Service:一般用在业务
- @Repository:一般用在持久层
这三个注解他们的作用和属性与@Component相同,他们三个是spring框架为我们提供明确的三层使用的注解。
5.4.4 @Autowired
@Autowired
是 Spring 框架中用于实现依赖注入(Dependency Injection, DI)的核心注解之一。它可以自动将 Spring 容器中匹配的 Bean 注入到需要的地方。@Autowired
可以用于构造函数、字段、setter 方法或任意方法。
@Autowired 的详细使用
- 字段注入
这是最常见的方式,直接在字段上使用 @Autowired
注解,Spring 会自动将匹配的 Bean 注入到该字段。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserService {
@Autowired
private UserRepository userRepository;
public void displayUser() {
userRepository.findUser();
}
}
- 构造函数注入
在构造函数上使用 @Autowired
注解,Spring 会在实例化时通过构造函数注入依赖。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void displayUser() {
userRepository.findUser();
}
}
- Setter 方法注入
通过在 setter 方法上使用 @Autowired
注解,Spring 会在 Bean 创建后调用该方法完成注入。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserService {
private UserRepository userRepository;
@Autowired
public void setUserRepository(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void displayUser() {
userRepository.findUser();
}
}
- 任意方法注入
除了构造函数和 setter 方法,@Autowired
还可以用在任意方法上。Spring 会在 Bean 创建后调用该方法完成注入。
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
@Component
public class UserService {
private UserRepository userRepository;
@Autowired
public void arbitraryMethod(UserRepository userRepository) {
this.userRepository = userRepository;
}
public void displayUser() {
userRepository.findUser();
}
}
- 默认行为与
@Autowired
的要求
- 默认行为:
@Autowired
注解默认采用byType
的方式进行注入。如果找到多个匹配的 Bean,Spring 会尝试根据@Qualifier
注解进一步确定要注入的 Bean。 - 必填性:默认情况下,
@Autowired
是必填的(required=true
),即 Spring 必须找到一个匹配的 Bean,否则会抛出NoSuchBeanDefinitionException
异常。 - 非必填性:可以通过设置
@Autowired(required = false)
来使依赖成为可选的,这样如果找不到匹配的 Bean,Spring 将不会注入任何东西。
5.4.5 其他注入数据的注解
@Qualifier
、@Resource
和 @Value
都是 Spring 框架中用于依赖注入(Dependency Injection, DI)的注解,但它们的用途和使用场景有所不同。
@Qualifier
@Qualifier
注解用于在多个相同类型的 Bean 中指定注入哪一个具体的 Bean。它通常与 @Autowired
一起使用。
使用场景
当有多个相同类型的 Bean 存在时,Spring 无法确定注入哪一个 Bean,这时可以使用 @Qualifier
注解来指定具体的 Bean。
示例
假设我们有两个实现 UserRepository
接口的 Bean:
import org.springframework.stereotype.Repository;
@Repository("primaryUserRepository")
public class PrimaryUserRepository implements UserRepository {
// 实现
}
@Repository("secondaryUserRepository")
public class SecondaryUserRepository implements UserRepository {
// 实现
}
在 UserService
中,我们可以使用 @Qualifier
注解来指定注入 secondaryUserRepository
:
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
@Component
public class UserService {
private final UserRepository userRepository;
@Autowired
public UserService(@Qualifier("secondaryUserRepository") UserRepository userRepository) {
this.userRepository = userRepository;
}
public void displayUser() {
userRepository.findUser();
}
}
@Resource
@Resource
注解是 Java 的标准注解(JSR-250),用于依赖注入。它可以根据名称或类型进行注入。默认情况下,@Resource
是按名称注入的,如果没有找到匹配的名称,则按类型注入。
使用场景
@Resource
注解通常用于按名称注入 Bean,如果不指定名称,则会使用默认的名称(即字段名)。
示例
假设我们有两个实现 UserRepository
接口的 Bean:
import org.springframework.stereotype.Repository;
@Repository("primaryUserRepository")
public class PrimaryUserRepository implements UserRepository {
// 实现
}
@Repository("secondaryUserRepository")
public class SecondaryUserRepository implements UserRepository {
// 实现
}
在 UserService
中,我们可以使用 @Resource
注解来指定注入 secondaryUserRepository
:
import javax.annotation.Resource;
import org.springframework.stereotype.Component;
@Component
public class UserService {
@Resource(name = "secondaryUserRepository")
private UserRepository userRepository;
public void displayUser() {
userRepository.findUser();
}
}
@Value
@Value
注解用于注入配置文件中的值或直接注入字符串、数字等常量值。它通常用于注入简单的属性,例如字符串、数字、布尔值等。
使用场景
@Value
注解通常用于注入配置文件中的属性值,或者直接注入常量值。
示例
假设我们在 application.properties
文件中定义了一个属性:
app.name=MyApplication
在 UserService
中,我们可以使用 @Value
注解来注入这个属性值:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class UserService {
@Value("${app.name}")
private String appName;
public void displayAppName() {
System.out.println("Application Name: " + appName);
}
}
我们也可以直接注入常量值:
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
@Component
public class UserService {
@Value("Hello, World!")
private String greeting;
public void displayGreeting() {
System.out.println(greeting);
}
}
4.@Scope
@Scope
是 Spring 框架中的一个注解,用于定义 Bean 的作用域。Bean 的作用域决定了 Bean 的生命周期以及 Spring 容器如何管理 Bean 的实例。通过 @Scope
注解,你可以指定 Bean 在应用中的生命周期和可访问范围。
常见的作用域
-
singleton(单例)
- 描述:这是 Spring 的默认作用域。在单例作用域中,每个 Spring IoC 容器仅创建一个 Bean 实例,并且所有对 Bean 的请求都会共用这一个实例。
- 适用场景:大多数无状态的 Bean 都适合使用单例作用域。
-
prototype(原型)
- 描述:每次请求都会创建一个新的 Bean 实例。
- 适用场景:当 Bean 是有状态的,即每个实例需要独立的状态时,应使用原型作用域。
-
request(请求)
- 描述:在 Web 应用中,每个 HTTP 请求都会创建一个 Bean 实例。该 Bean 只在当前 HTTP 请求内有效。
- 适用场景:需要在单个 HTTP 请求中维护状态的 Bean。
-
session(会话)
- 描述:在 Web 应用中,每个 HTTP Session 都会创建一个 Bean 实例。该 Bean 只在当前 HTTP Session 内有效。
- 适用场景:需要在用户 Session 范围内维护状态的 Bean。
-
application(应用)
- 描述:在 Web 应用中,每个 ServletContext(即整个应用)只有一个 Bean 实例。该 Bean 在整个应用范围内有效。
- 适用场景:需要在应用范围内共享数据的 Bean。
-
websocket(WebSocket)
- 描述:在 Web 应用中,每个 WebSocket 连接都会创建一个 Bean 实例。该 Bean 只在当前 WebSocket 连接内有效。
- 适用场景:需要在 WebSocket 连接范围内维护状态的 Bean。
使用 @Scope 注解
你可以使用 @Scope
注解来显式地指定 Bean 的作用域。以下是一些示例:
Singleton Scope
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
@Component
@Scope("singleton")
public class SingletonBean {
// Bean implementation
}
6 配置类
好的,@Configuration
、@Import
和 @PropertySource
是 Spring 框架中常用的注解,分别用于配置类、模块化配置和外部属性文件的加载。下面分别介绍这三个注解的用途和使用方法。
6.1. @Configuration
注解
@Configuration
注解用于标记一个类为 Spring 配置类。配置类中可以定义 @Bean
注解的方法,用于创建和配置 Spring 容器中的 Bean。配置类可以替代传统的 XML 配置文件。
特点
- 替代 XML 配置:使用 Java 代码代替 XML 文件进行配置。
- 集中管理 Bean:在一个类中定义多个 Bean,方便管理。
- 支持依赖注入:可以在配置类中注入其他 Bean。
示例
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class AppConfig {
@Bean
public MyBean myBean() {
return new MyBean();
}
}
6.2 @Import
注解
@Import
注解用于将一个或多个配置类导入到当前配置类中。通过 @Import
,可以实现模块化配置,将多个配置类组合在一起。
特点
- 模块化配置:将多个配置类组合在一起,便于管理和维护。
- 代码复用:可以在多个配置类中导入相同的配置类,避免重复代码。
示例
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({DatabaseConfig.class, ServiceConfig.class})
public class AppConfig {
// 其他 Bean 定义
}
6.3 @PropertySource
注解
@PropertySource
注解用于加载外部属性文件(如 .properties
或 .yml
文件),并将其中的属性值注入到 Spring 环境中。通常与 @Value
或 @ConfigurationProperties
注解一起使用。
特点
- 加载外部属性文件:支持加载
.properties
或.yml
文件。 - 动态配置:可以通过属性文件动态配置应用的行为。
- 支持多文件:可以加载多个属性文件。
示例
属性文件 app.properties
app.name=MyApp
app.version=1.0
配置类
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:app.properties")
public class AppConfig {
@Value("${app.name}")
private String appName;
@Value("${app.version}")
private String appVersion;
public void printAppInfo() {
System.out.println("App Name: " + appName);
System.out.println("App Version: " + appVersion);
}
}
6.4 综合示例
以下是一个综合使用 @Configuration
、@Import
和 @PropertySource
的示例:
- 属性文件
database.properties
db.url=jdbc:mysql://localhost:3306/mydb
db.username=root
db.password=secret
- 配置类
DatabaseConfig
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
@Configuration
@PropertySource("classpath:database.properties")
public class DatabaseConfig {
@Value("${db.url}")
private String dbUrl;
@Value("${db.username}")
private String dbUsername;
@Value("${db.password}")
private String dbPassword;
@Bean
public DataSource dataSource() {
// 使用属性值创建数据源
return new DataSource(dbUrl, dbUsername, dbPassword);
}
}
- 配置类
ServiceConfig
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ServiceConfig {
@Bean
public MyService myService() {
return new MyService();
}
}
- 主配置类
AppConfig
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
@Configuration
@Import({DatabaseConfig.class, ServiceConfig.class})
public class AppConfig {
// 其他 Bean 定义
}