Spring框架:从入门到精通的全面指南

📃个人主页:小韩学长yyds-优快云博客

⛺️ 欢迎关注:👍点赞 👂🏽留言 😍收藏 💞 💞 💞

箴言:拥有耐心才是生活的关键

目录

Spring 框架简介

Spring 核心概念

控制反转(IoC)

依赖注入(DI)

面向切面编程(AOP)

Spring 入门案例

环境搭建

第一个 Spring 程序

运行和测试

基于 XML 管理 Bean

环境准备

获取 Bean 方式

依赖注入方式

基于 setter 依赖注入

基于构造器依赖注入

特殊值处理注入

字面量赋值

null 值处理

xml 实体和 CDATA 区的使用

对象类型属性注入

引用外部 bean

内部 bean

级联属性赋值

集合类型属性注入

List 集合

Map 集合

引用集合类型 Bean

p 命名空间

引入外部属性文件

bean 的作用域

基于注解管理 Bean

创建子工程

开启组件扫描

使用注解定义 Bean

@Autowired 注入

@Resource 注入

Spring 全注解开发


Spring 框架简介

Spring 框架是 Java 开发领域的基石,是一个开源的轻量级应用框架,为 Java 企业级应用开发提供了全面的基础架构支持。它就像是一个功能强大的 “瑞士军刀”,涵盖了从对象管理到 Web 开发、事务处理等各个方面,极大地简化了开发过程。

Spring 框架具有诸多显著特性:

  • 轻量级:Spring 框架的设计目标之一就是轻量级,它对系统资源的占用极少,无论是在小型应用还是大型企业级项目中,都能高效运行。比如,在一个内存有限的服务器环境中,Spring 应用程序的启动和运行都不会给系统带来过多负担。
  • 开源:作为开源框架,Spring 拥有庞大的社区支持。全球各地的开发者都可以参与到 Spring 的开发和改进中,不断丰富其功能和特性。开发者在使用过程中遇到问题时,可以在社区中找到大量的解决方案和相关资料。
  • 控制反转(IoC):这是 Spring 框架的核心特性之一。IoC 将对象的创建和管理从应用程序代码中分离出来,交由 Spring 容器负责。例如,在传统的 Java 开发中,我们可能需要手动创建对象并管理它们之间的依赖关系,而在 Spring 中,只需要通过配置或注解,就能让 Spring 容器自动创建和注入所需的对象,大大降低了代码的耦合度。
  • 面向切面编程(AOP):AOP 允许将横切关注点(如日志记录、事务管理、权限控制等)与业务逻辑分离,通过在运行时动态地将这些关注点织入到目标对象中,实现代码的复用和模块化。比如,在一个电商系统中,我们可以通过 AOP 统一为所有业务方法添加日志记录功能,而不需要在每个业务方法中重复编写日志代码。

Spring 核心概念

控制反转(IoC)

控制反转(Inversion of Control,IoC)是 Spring 框架的核心思想之一。在传统的 Java 开发中,对象的创建和依赖关系的管理通常由开发者在代码中手动完成。例如,在一个简单的用户管理系统中,如果我们有一个UserService类依赖于UserDao类,在传统方式下,我们会在UserService类中通过new关键字来创建UserDao的实例,如下所示:

public class UserService {

private UserDao userDao = new UserDao();

public void saveUser(User user) {

userDao.save(user);

}

}

这样做会导致UserService与UserDao之间的耦合度非常高,如果需要更换UserDao的实现类,就需要修改UserService的代码。

而在 Spring 中,通过 IoC 机制,对象的创建和管理不再由应用程序自身负责,而是交给了 Spring 容器。Spring 容器负责创建对象、管理对象的生命周期以及维护对象之间的依赖关系。我们只需要在配置文件或使用注解告诉 Spring 容器需要创建哪些对象以及它们之间的依赖关系即可。这样一来,对象之间的耦合度大大降低,代码的可维护性和可扩展性得到了显著提高。例如,使用 Spring 的配置文件来管理UserService和UserDao的依赖关系:

<bean id="userDao" class="com.example.dao.UserDaoImpl"/>

<bean id="userService" class="com.example.service.UserService">

<property name="userDao" ref="userDao"/>

</bean>

在上述配置中,Spring 容器会根据配置文件创建UserDao和UserService的实例,并将UserDao的实例注入到UserService中,从而实现了对象之间依赖关系的管理。

依赖注入(DI)

依赖注入(Dependency Injection,DI)是实现 IoC 的具体方式。它的核心思想是将对象所依赖的外部资源(如其他对象、配置信息等)通过某种方式(如构造函数、Setter 方法等)注入到对象中,而不是由对象自己去创建或查找这些依赖。

Spring 提供了多种依赖注入的实现方式,其中最常用的是构造器注入和属性注入。

构造器注入:通过构造函数来实现依赖注入。当一个类的构造函数参数包含其他依赖对象时,Spring 容器会在创建该类的实例时,将对应的依赖对象作为参数传递给构造函数。例如:

public class OrderService {

private OrderDao orderDao;

public OrderService(OrderDao orderDao) {

this.orderDao = orderDao;

}

public void placeOrder(Order order) {

orderDao.saveOrder(order);

}

}

在 Spring 配置文件中,可以这样配置:

<bean id="orderDao" class="com.example.dao.OrderDaoImpl"/>

<bean id="orderService" class="com.example.service.OrderService">

<constructor-arg ref="orderDao"/>

</bean>

属性注入:通过 Setter 方法来实现依赖注入。Spring 容器会在创建对象后,调用对象的 Setter 方法将依赖对象注入到对象中。例如:

public class ProductService {

private ProductDao productDao;

public void setProductDao(ProductDao productDao) {

this.productDao = productDao;

}

public void addProduct(Product product) {

productDao.saveProduct(product);

}

}

在 Spring 配置文件中,配置如下:

<bean id="productDao" class="com.example.dao.ProductDaoImpl"/>

<bean id="productService" class="com.example.service.ProductService">

<property name="productDao" ref="productDao"/>

</bean>

面向切面编程(AOP)

面向切面编程(Aspect Oriented Programming,AOP)是一种与面向对象编程(OOP)相辅相成的编程思想。OOP 主要关注的是将业务逻辑封装成一个个独立的对象,通过对象之间的交互来完成业务功能;而 AOP 则是将那些与业务逻辑无关,但又横切于多个业务模块的功能(如日志记录、事务管理、权限控制等)抽取出来,形成独立的切面(Aspect),然后在运行时将这些切面动态地织入到目标对象的方法执行过程中。

在 AOP 中,有几个重要的概念:

  • 切面(Aspect):切面是一个关注点的模块化,它将横切关注点(如日志记录、事务管理等)封装成一个独立的模块。例如,我们可以将日志记录功能封装成一个切面。
  • 连接点(Joinpoint):连接点是程序执行过程中的某个特定位置,如方法调用、异常抛出等。在 Spring 中,连接点主要指的是方法调用。
  • 切入点(Pointcut):切入点是对连接点的进一步筛选,它定义了哪些连接点会被织入切面。例如,我们可以定义一个切入点,只对业务层中所有以save开头的方法进行日志记录。
  • 增强(Advice):增强是在切入点处执行的具体操作,它定义了在连接点处要执行的额外功能。常见的增强类型有前置增强(Before Advice)、后置增强(After Advice)、环绕增强(Around Advice)、异常增强(After Throwing Advice)和最终增强(After Finally Advice)。例如,前置增强可以在方法执行前记录日志,后置增强可以在方法执行后记录日志。

通过 AOP,我们可以将业务逻辑和系统服务进行分离,提高代码的复用性和可维护性。例如,在一个电商系统中,我们可以通过 AOP 统一为所有业务方法添加日志记录功能,而不需要在每个业务方法中重复编写日志代码。在 Spring 中,可以通过 XML 配置或注解的方式来实现 AOP。下面是一个使用注解实现 AOP 的简单示例:

import org.aspectj.lang.ProceedingJoinPoint;

import org.aspectj.lang.annotation.Around;

import org.aspectj.lang.annotation.Aspect;

import org.springframework.stereotype.Component;

@Aspect

@Component

public class LoggingAspect {

@Around("execution(* com.example.service.*.*(..))")

public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {

System.out.println("Before method execution: " + joinPoint.getSignature().getName());

Object result = joinPoint.proceed();

System.out.println("After method execution: " + joinPoint.getSignature().getName());

return result;

}

}

在上述示例中,LoggingAspect是一个切面类,@Aspect注解表明它是一个切面,@Component注解将其纳入 Spring 容器的管理。@Around注解定义了一个环绕增强,切入点表达式execution(* com.example.service.*.*(..))表示对com.example.service包下所有类的所有方法进行增强。在方法执行前后,会分别打印日志信息。

Spring 入门案例

环境搭建

在开始 Spring 之旅前,我们需要搭建好开发环境。

必备环境

  • JDK:建议使用 JDK 1.8 及以上版本,确保 Java 开发环境的稳定运行。例如,在企业级项目中,JDK 1.8 已经被广泛应用,其强大的功能和稳定性为 Spring 开发提供了坚实的基础。
  • Maven:Maven 是项目管理和构建工具,能帮助我们轻松管理项目依赖和构建过程。推荐使用 3.6.3 及以上版本。Maven 通过简单的配置文件(pom.xml),就能让我们快速引入各种依赖库,避免了手动下载和管理 jar 包的繁琐过程。
  • 开发工具:可以选择 IntelliJ IDEA、Eclipse 等流行的 Java 开发工具,它们提供了丰富的插件和便捷的开发功能,能大大提高开发效率。以 IntelliJ IDEA 为例,它对 Spring 的支持非常友好,不仅能自动提示 Spring 相关的代码,还提供了强大的代码导航和调试功能。

配置 Maven 项目

  1. 打开 IntelliJ IDEA,创建一个新的 Maven 项目。在创建过程中,按照向导提示,填写项目的基本信息,如 GroupId、ArtifactId 和 Version 等。这些信息将唯一标识我们的项目,例如,GroupId 可以设置为公司或组织的域名倒写,ArtifactId 则是项目的名称,Version 用于标识项目的版本号。
  2. 创建完成后,在项目的 pom.xml 文件中引入 Spring 依赖。我们可以在Maven 仓库中搜索所需的 Spring 依赖,然后将其添加到 pom.xml 文件中。例如,添加 Spring Context 依赖:
    <dependencies>
    
    <dependency>
    
    <groupId>org.springframework</groupId>
    
    <artifactId>spring-context</artifactId>
    
    <version>5.3.10.RELEASE</version>
    
    </dependency>
    
    </dependencies>

在上述配置中,<groupId>org.springframework</groupId>表示 Spring 的组织 ID,<artifactId>spring-context</artifactId>表示 Spring 上下文模块的工件 ID,<version>5.3.10.RELEASE</version>表示版本号。引入spring-context依赖后,Spring 的基础依赖就被引入了项目中 。

第一个 Spring 程序

  1. 创建 Java 类:在项目的src/main/java目录下创建一个简单的 Java 类,例如HelloWorld类:
    public class HelloWorld {
    
    private String message;
    
    public void setMessage(String message) {
    
    this.message = message;
    
    }
    
    public void sayHello() {
    
    System.out.println("Message: " + message);
    
    }
    
    }

在这个类中,我们定义了一个message属性,并提供了setMessage方法用于设置属性值,以及sayHello方法用于输出消息。2. 创建 Spring 配置文件:在src/main/resources目录下创建 Spring 配置文件

applicationContext.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="helloWorld" class="com.example.HelloWorld">

<property name="message" value="Hello, Spring!"/>

</bean>

</beans>

在上述配置中,<bean>标签用于配置 Spring 容器管理的对象,id属性为对象的唯一标识,class属性指定对象的全限定类名。<property>标签用于设置对象的属性,name属性指定属性名,value属性指定属性值。通过这个配置文件,我们告诉 Spring 容器创建一个HelloWorld类的实例,并将message属性设置为Hello, Spring!。

运行和测试

  1. 运行 Spring 程序:在项目中创建一个测试类,例如HelloWorldTest类:
    import org.springframework.context.ApplicationContext;
    
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class HelloWorldTest {
    
    public static void main(String[] args) {
    
    // 加载Spring配置文件,创建Spring容器
    
    ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
    
    // 从Spring容器中获取HelloWorld对象
    
    HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");
    
    // 调用HelloWorld对象的sayHello方法
    
    helloWorld.sayHello();
    
    }
    
    }

在上述代码中,首先通过ClassPathXmlApplicationContext类加载 Spring 配置文件applicationContext.xml,创建 Spring 容器。然后使用context.getBean("helloWorld")方法从容器中获取HelloWorld对象,最后调用helloWorld.sayHello()方法输出消息。

  1. 使用 JUnit 进行测试:为了更方便地测试 Spring 程序,我们可以使用 JUnit 测试框架。首先在 pom.xml 文件中添加 JUnit 依赖:
    <dependency>
    
    <groupId>junit</groupId>
    
    <artifactId>junit</artifactId>
    
    <version>4.13.2</version>
    
    <scope>test</scope>
    
    </dependency>

然后创建一个 JUnit 测试类,例如HelloWorldJUnitTest类:

import org.junit.Test;

import org.springframework.context.ApplicationContext;

import org.springframework.context.support.ClassPathXmlApplicationContext;

import static org.junit.Assert.*;

public class HelloWorldJUnitTest {

@Test

public void testHelloWorld() {

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");

assertNotNull(helloWorld);

helloWorld.sayHello();

}

}

在上述测试类中,使用@Test注解标记测试方法testHelloWorld。在测试方法中,首先创建 Spring 容器,获取HelloWorld对象,然后使用assertNotNull方法断言对象不为空,最后调用sayHello方法输出消息。运行这个测试类,如果一切正常,我们将在控制台看到Message: Hello, Spring!的输出,这表明 Spring 已经成功创建和管理HelloWorld对象,并且对象的属性也被正确设置 。

基于 XML 管理 Bean

环境准备

在使用 XML 配置 Bean 之前,需要确保项目中引入了 Spring 的相关依赖。如果使用 Maven 构建项目,在pom.xml文件中添加如下依赖:

<dependencies>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.3.10.RELEASE</version>

</dependency>

</dependencies>

引入依赖后,在src/main/resources目录下创建 Spring 的配置文件,通常命名为applicationContext.xml。这个文件将用于配置 Spring 容器管理的 Bean 。

获取 Bean 方式

在 Spring 容器中获取 Bean 有多种方式,其中最常用的是根据 id 获取和根据类型获取。

根据 id 获取:通过ApplicationContext的getBean(String name)方法,传入 Bean 的 id 来获取对应的 Bean 实例。例如:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloWorld helloWorld = (HelloWorld) context.getBean("helloWorld");

在上述代码中,"helloWorld"是配置文件中 Bean 的 id,通过context.getBean("helloWorld")从 Spring 容器中获取HelloWorld类型的 Bean 实例。

根据类型获取:使用ApplicationContext的getBean(Class<T> requiredType)方法,传入 Bean 的类型来获取对应的 Bean 实例。例如:

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloWorld helloWorld = context.getBean(HelloWorld.class);

这种方式要求 Spring 容器中该类型的 Bean 是唯一的,否则会抛出NoUniqueBeanDefinitionException异常。

此外,还可以同时根据 id 和类型获取 Bean,使用ApplicationContext的getBean(String name, Class<T> requiredType)方法 :

ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

HelloWorld helloWorld = context.getBean("helloWorld", HelloWorld.class);

依赖注入方式

基于 setter 依赖注入

基于 setter 的依赖注入是通过调用 Bean 的 setter 方法来实现依赖注入的。在 Spring 配置文件中,使用<property>标签来配置依赖注入。

例如,假设有一个UserService类依赖于UserDao类,UserService类的定义如下:

public class UserService {

private UserDao userDao;

public void setUserDao(UserDao userDao) {

this.userDao = userDao;

}

public void saveUser(User user) {

userDao.save(user);

}

}

在 Spring 配置文件applicationContext.xml中,配置如下:

<bean id="userDao" class="com.example.dao.UserDaoImpl"/>

<bean id="userService" class="com.example.service.UserService">

<property name="userDao" ref="userDao"/>

</bean>

在上述配置中,<property>标签的name属性指定要注入的属性名,ref属性指定要注入的 Bean 的 id。通过这种方式,Spring 容器在创建userService实例时,会调用setUserDao方法将userDao实例注入到userService中 。

基于构造器依赖注入

基于构造器的依赖注入是通过调用 Bean 的构造函数来实现依赖注入的。在 Spring 配置文件中,使用<constructor-arg>标签来配置构造器参数。

例如,假设有一个OrderService类,其构造函数接受一个OrderDao类型的参数,OrderService类的定义如下:

public class OrderService {

private OrderDao orderDao;

public OrderService(OrderDao orderDao) {

this.orderDao = orderDao;

}

public void placeOrder(Order order) {

orderDao.saveOrder(order);

}

}

在 Spring 配置文件applicationContext.xml中,配置如下:

<bean id="orderDao" class="com.example.dao.OrderDaoImpl"/>

<bean id="orderService" class="com.example.service.OrderService">

<constructor-arg ref="orderDao"/>

</bean>

在上述配置中,<constructor-arg>标签的ref属性指定要注入的 Bean 的 id,Spring 容器在创建orderService实例时,会调用对应的构造函数将orderDao实例注入到orderService中。<constructor-arg>标签还可以通过index属性指定参数的位置索引(从 0 开始),通过type属性指定参数的类型,通过value属性直接赋值 。

特殊值处理注入

字面量赋值

在 Spring 配置文件中,可以使用<property>标签的value属性为 Bean 的属性赋值字面量。例如:

<bean id="person" class="com.example.Person">

<property name="name" value="张三"/>

<property name="age" value="20"/>

</bean>

上述配置中,为Person类的name属性赋值为张三,age属性赋值为20。

null 值处理

当需要为 Bean 的属性赋值为null时,可以使用<null/>标签。例如:

<bean id="book" class="com.example.Book">

<property name="author">

<null/>

</property>

</bean>

在上述配置中,book的author属性被赋值为null 。

xml 实体和 CDATA 区的使用

当属性值中包含特殊字符(如<、>、&等)时,如果直接使用这些字符,可能会导致 XML 解析错误。此时可以使用 XML 实体或 CDATA 区来处理。

使用 XML 实体:例如,要表示&字符,可以使用&amp;实体。

<bean id="message" class="com.example.Message">

<property name="content" value="这是一个包含&amp;符号的消息"/>

</bean>

使用 CDATA 区:CDATA 区中的内容会被 XML 解析器原样解析,不会对其中的特殊字符进行转义。例如:

<bean id="message" class="com.example.Message">

<property name="content">

<value><![CDATA[这是一个包含<特殊字符>的消息]]></value>

</property>

</bean>

在上述配置中,content属性的值包含<特殊字符>,使用 CDATA 区确保这些特殊字符不会被 XML 解析器错误解析 。

对象类型属性注入

引用外部 bean

在一个 Bean 中引用另一个外部 Bean 是非常常见的场景。例如,UserService类依赖于UserDao类,UserService类中的userDao属性需要引用外部定义的UserDao Bean。在 Spring 配置文件中,配置如下:

<bean id="userDao" class="com.example.dao.UserDaoImpl"/>

<bean id="userService" class="com.example.service.UserService">

<property name="userDao" ref="userDao"/>

</bean>

在上述配置中,userService的userDao属性通过ref属性引用了userDao Bean,这样 Spring 容器在创建userService实例时,会将userDao实例注入到userService中 。

内部 bean

内部 Bean 是在另一个 Bean 的配置中定义的 Bean,它只能在外部 Bean 中使用,不能被外部直接引用。例如:

<bean id="outerBean" class="com.example.OuterBean">

<property name="innerBean">

<bean id="innerBean" class="com.example.InnerBean"/>

</property>

</bean>

在上述配置中,innerBean是定义在outerBean内部的 Bean,它只能被outerBean使用,其他 Bean 无法直接引用innerBean 。

级联属性赋值

级联属性赋值允许通过一个 Bean 的属性来访问和设置另一个 Bean 的属性。例如,假设有Address类和Person类,Person类包含一个Address类型的属性,并且Address类有city属性。

public class Address {

private String city;

public String getCity() {

return city;

}

public void setCity(String city) {

this.city = city;

}

}

public class Person {

private Address address;

public Address getAddress() {

return address;

}

public void setAddress(Address address) {

this.address = address;

}

}

在 Spring 配置文件中,可以通过级联属性赋值来设置Person的Address的city属性:

<bean id="address" class="com.example.Address">

<property name="city" value="北京"/>

</bean>

<bean id="person" class="com.example.Person">

<property name="address" ref="address"/>

<!-- 级联属性赋值 -->

<property name="address.city" value="上海"/>

</bean>

在上述配置中,首先通过ref属性将address Bean 注入到person的address属性中,然后通过address.city的方式直接设置address的city属性为上海 。

集合类型属性注入

List 集合

在 Spring 配置文件中,可以使用<list>标签来注入 List 集合类型的属性。例如,假设有一个CourseService类,它有一个List<String>类型的courses属性,用于存储课程名称。

public class CourseService {

private List<String> courses;

public void setCourses(List<String> courses) {

this.courses = courses;

}

public void printCourses() {

for (String course : courses) {

System.out.println(course);

}

}

}

在 Spring 配置文件applicationContext.xml中,配置如下:

<bean id="courseService" class="com.example.CourseService">

<property name="courses">

<list>

<value>Java</value>

<value>Spring</value>

<value>MySQL</value>

</list>

</property>

</bean>

在上述配置中,<list>标签内的<value>标签分别表示 List 集合中的元素,Spring 容器在创建courseService实例时,会将这些元素注入到courses属性中 。

Map 集合

使用<map>标签可以注入 Map 集合类型的属性。例如,假设有一个Student类,它有一个Map<String, Integer>类型的scores属性,用于存储学生的课程成绩。

public class Student {

private Map<String, Integer> scores;

public void setScores(Map<String, Integer> scores) {

this.scores = scores;

}

public void printScores() {

for (Map.Entry<String, Integer> entry : scores.entrySet()) {

System.out.println(entry.getKey() + ": " + entry.getValue());

}

}

}

在 Spring 配置文件applicationContext.xml中,配置如下:

<bean id="student" class="com.example.Student">

<property name="scores">

<map>

<entry key="数学" value="90"/>

<entry key="语文" value="85"/>

<entry key="英语" value="95"/>

</map>

</property>

</bean>

在上述配置中,<map>标签内的<entry>标签用于定义 Map 集合中的键值对,key属性表示键,value属性表示值 。

引用集合类型 Bean

当集合中的元素是其他 Bean 时,可以使用<ref>标签来引用。例如,假设有Book类和Library类,Library类有一个List<Book>类型的books属性。

public class Book {

private String title;

public String getTitle() {

return title;

}

public void setTitle(String title) {

this.title = title;

}

}

public class Library {

private List<Book> books;

public void setBooks(List<Book> books) {

this.books = books;

}

public void printBooks() {

for (Book book : books) {

System.out.println(book.getTitle());

}

}

}

在 Spring 配置文件applicationContext.xml中,配置如下:

<bean id="book1" class="com.example.Book">

<property name="title" value="《Spring实战》"/>

</bean>

<bean id="book2" class="com.example.Book">

<property name="title" value="《Effective Java》"/>

</bean>

<bean id="library" class="com.example.Library">

<property name="books">

<list>

<ref bean="book1"/>

<ref bean="book2"/>

</list>

</property>

</bean>

在上述配置中,<list>标签内的<ref>标签分别引用了book1和book2 Bean,将这两个 Bean 注入到library的books属性中 。

p 命名空间

p 命名空间是 Spring 提供的一种简化 Bean 属性配置的方式。使用 p 命名空间可以在<bean>标签内直接通过属性名来设置 Bean 的属性,而不需要使用<property>标签。

首先,需要在 Spring 配置文件的<beans>标签中引入 p 命名空间:

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

然后,就可以使用 p 命名空间来配置 Bean 的属性。例如,假设有一个Person类:

public class Person {

private String name;

private int age;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public int getAge() {

return age;

}

public void setAge(int age) {

this.age = age;

}

}

在 Spring 配置文件中,可以使用 p 命名空间配置如下:

<bean id="person" class="com.example.Person" p:name="李四" p:age="25"/>

上述配置等价于使用<property>标签的配置:

<bean id="person" class="com.example.Person">

<property name="name" value="李四"/>

<property name="age" value="25"/>

</bean>

使用 p 命名空间可以使配置更加简洁明了 。

引入外部属性文件

在实际开发中,通常会将一些配置信息(如数据库连接信息、系统参数等)外部化,存储在属性文件中,这样便于管理和维护。Spring 提供了引入外部属性文件的功能。

首先,在src/main/resources目录下创建属性文件,例如config.properties,内容如下:

jdbc.url=jdbc:mysql://localhost:3306/mydb

jdbc.username=root

jdbc.password=123456

然后,在 Spring 配置文件中引入这个属性文件:

<context:property-placeholder location="classpath:config.properties"/>

上述配置中,<context:property-placeholder>标签用于引入属性文件,location属性指定属性文件的位置,classpath:表示从类路径下查找文件。

引入属性文件后,就可以在 Spring 配置中使用属性文件中的值。例如,配置数据源:

<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource">

<property name="url" value="${jdbc.url}"/>

<property name="username" value="${jdbc.username}"/>

<property name="password" value="${jdbc.password}"/>

</bean>

在上述配置中,通过${}占位符的方式引用属性文件中的值,Spring 容器在解析配置文件时,会将占位符替换为实际的值 。

bean 的作用域

Spring 中 Bean 的作用域定义了 Bean 在 Spring 容器中的生命周期和实例数量。Spring 支持多种作用域:

  • singleton:单例作用域,这是 Spring 的默认作用域。在这种作用域下,Spring 容器只会创建一个 Bean 实例,所有对该 Bean 的请求都会返回同一个实例。例如,在一个电商系统中,用户管理模块的UserService Bean 通常可以配置为单例作用域,因为整个系统只需要一个UserService实例来处理用户相关的业务逻辑,这样可以节省系统资源,提高性能。
  • prototype:原型作用域,每次对该 Bean 的请求都会创建一个新的实例。例如,在一个在线考试系统中,每个考生的答题记录可以使用一个AnswerRecord Bean 来记录,由于每个考生的答题情况不同,所以AnswerRecord Bean 适合配置为原型作用域,每次创建一个新的实例来记录不同考生的答题信息。
  • request:请求作用域,在一次 HTTP 请求中,一个 Bean 定义对应一个实例。该作用域仅在基于 Web 的 Spring ApplicationContext 情形下有效。例如,在一个 Web 应用中,处理用户登录请求的 `Login

基于注解管理 Bean

创建子工程

为了深入学习基于注解的 Bean 管理,我们首先创建一个新的 Maven 子工程。以 IDEA 为例,打开 IDEA 后,选择File -> New -> Project,在弹出的窗口中选择Maven,然后点击Next。在后续步骤中,填写 GroupId(如com.example)、ArtifactId(如spring-annotation-demo)等项目信息,最后点击Finish完成项目创建。

创建完成后,在pom.xml文件中添加 Spring 相关依赖:

<dependencies>

<dependency>

<groupId>org.springframework</groupId>

<artifactId>spring-context</artifactId>

<version>5.3.10.RELEASE</version>

</dependency>

</dependencies>

开启组件扫描

在 Spring 中,使用注解定义 Bean 的前提是要开启组件扫描功能,这样 Spring 容器才能扫描到被注解标记的类并将其注册为 Bean。

如果使用 XML 配置,在applicationContext.xml文件中添加如下配置:

<context:component-scan base-package="com.example"/>

上述配置表示 Spring 容器会扫描com.example包及其子包下的所有类。

如果使用 Java 配置类,可以创建一个配置类并添加@ComponentScan注解:

import org.springframework.context.annotation.ComponentScan;

import org.springframework.context.annotation.Configuration;

@Configuration

@ComponentScan("com.example")

public class AppConfig {

}

在上述代码中,@Configuration注解表示这是一个配置类,@ComponentScan注解指定了扫描的包路径 。

使用注解定义 Bean

Spring 提供了多个注解用于定义 Bean,这些注解都具有特定的语义,有助于提高代码的可读性和可维护性。

  • @Component:这是一个通用的组件注解,用于标记一个类为 Spring 管理的组件。例如:
    import org.springframework.stereotype.Component;
    
    @Component
    
    public class UserService {
    
    // 业务逻辑代码
    
    }

在上述示例中,UserService类被@Component注解标记,Spring 容器会自动扫描到该类并将其注册为一个 Bean,默认的 Bean 名称为类名首字母小写,即userService。

  • @Controller:用于标记 Spring MVC 中的控制器类,主要处理用户请求并返回视图或数据。例如:
    import org.springframework.stereotype.Controller;
    
    import org.springframework.web.bind.annotation.GetMapping;
    
    import org.springframework.web.bind.annotation.ResponseBody;
    
    @Controller
    
    public class UserController {
    
    @GetMapping("/user")
    
    @ResponseBody
    
    public String getUser() {
    
    return "This is a user";
    
    }
    
    }

在 Spring MVC 应用中,@Controller注解会将控制器类纳入 Spring 容器管理,@GetMapping注解用于映射 HTTP GET 请求到getUser方法,@ResponseBody注解表示该方法的返回值会直接作为响应体返回给客户端 。

  • @Service:用于标记业务层的服务类,封装了具体的业务逻辑。例如:
    import org.springframework.stereotype.Service;
    
    @Service
    
    public class OrderService {
    
    // 订单相关业务逻辑代码
    
    }

在实际开发中,OrderService类通常会依赖其他组件(如OrderDao)来完成数据库操作等业务功能 。

  • @Repository:用于标记数据访问层(DAO)类,主要负责与数据库进行交互。例如:
    import org.springframework.stereotype.Repository;
    
    @Repository
    
    public class ProductDao {
    
    // 数据库操作代码
    
    }

@Repository注解不仅将ProductDao类注册为 Bean,还提供了数据访问异常的处理机制,例如将 JDBC 异常转换为 Spring 的DataAccessException,方便上层业务统一处理异常 。

@Autowired 注入

@Autowired注解是 Spring 提供的用于实现依赖注入的重要注解,它基于类型进行自动装配。

属性注入:在需要注入依赖的属性上直接使用@Autowired注解。例如:

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

@Service

public class UserServiceImpl implements UserService {

@Autowired

private UserDao userDao;

@Override

public User getUserById(int id) {

return userDao.findById(id);

}

}

在上述示例中,UserServiceImpl类依赖于UserDao,通过在userDao属性上添加@Autowired注解,Spring 容器会自动将UserDao类型的 Bean 注入到userDao属性中 。

set 注入:通过在 Setter 方法上使用@Autowired注解来实现依赖注入。例如:

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

@Service

public class UserServiceImpl implements UserService {

private UserDao userDao;

@Autowired

public void setUserDao(UserDao userDao) {

this.userDao = userDao;

}

@Override

public User getUserById(int id) {

return userDao.findById(id);

}

}

在这种方式下,Spring 容器会在创建UserServiceImpl实例后,调用setUserDao方法将UserDao实例注入 。

构造方法注入:在构造方法上使用@Autowired注解。例如:

import org.springframework.beans.factory.annotation.Autowired;

import org.springframework.stereotype.Service;

@Service

public class UserServiceImpl implements UserService {

private final UserDao userDao;

@Autowired

public UserServiceImpl(UserDao userDao) {

this.userDao = userDao;

}

@Override

public User getUserById(int id) {

return userDao.findById(id);

}

}

使用构造方法注入时,如果当前类只有一个构造方法,@Autowired注解可以省略。这种方式能确保依赖的UserDao在UserServiceImpl实例创建时就被注入,并且可以将userDao属性声明为final,提高代码的安全性和不可变性 。

@Resource 注入

@Resource注解是 Java EE 提供的用于依赖注入的注解,它既可以按名称注入,也可以按类型注入。

与@Autowired不同,@Resource默认按名称注入,如果找不到与名称匹配的 Bean,才会按类型注入。例如:

import javax.annotation.Resource;

import org.springframework.stereotype.Service;

@Service

public class UserServiceImpl implements UserService {

@Resource(name = "userDao")

private UserDao userDao;

@Override

public User getUserById(int id) {

return userDao.findById(id);

}

}

在上述示例中,通过@Resource注解的name属性指定要注入的 Bean 名称为userDao,如果 Spring 容器中存在名为userDao的 Bean,则会将其注入到userDao属性中。如果不指定name属性,@Resource会尝试根据属性名查找匹配的 Bean 。

@Resource和@Autowired的主要区别在于:

  • 来源不同:@Autowired是 Spring 框架特有的注解,而@Resource是 Java EE 标准注解,在非 Spring 环境中也可以使用。
  • 注入方式不同:@Autowired默认按类型注入,@Resource默认按名称注入。
  • 功能特性不同:@Autowired更侧重于 Spring 框架内的依赖注入,配合@Qualifier等注解可以更灵活地处理复杂的依赖关系;@Resource在处理与 Java EE 其他技术集成时更为方便 。

Spring 全注解开发

在 Spring 中,除了使用 XML 配置文件外,还可以完全使用注解进行配置,实现零 XML 配置的开发方式。

首先,创建一个配置类,使用@Configuration注解标记它为一个配置类,并在类中使用@Bean注解定义 Bean。例如:

import org.springframework.context.annotation.Bean;

import org.springframework.context.annotation.Configuration;

@Configuration

public class AppConfig {

@Bean

public UserService userService() {

return new UserServiceImpl();

}

@Bean

public UserDao userDao() {

return new UserDaoImpl();

}

}

在上述配置类中,@Bean注解标记的方法返回的对象会被注册为 Spring 容器中的 Bean,方法名即为 Bean 的名称。

在测试类中,可以通过AnnotationConfigApplicationContext来加载配置类并获取 Bean:

import org.springframework.context.ApplicationContext;

import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class AppTest {

public static void main(String[] args) {

ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

UserService userService = context.getBean(UserService.class);

User user = userService.getUserById(1);

System.out.println(user);

}

}

通过这种方式,我们可以完全摆脱 XML 配置文件,仅使用注解来完成 Spring 的配置和 Bean 管理,使代码更加简洁、易读,并且便于维护和扩展 。

结语

🔥如果此文对你有帮助的话,欢迎💗关注、👍点赞、⭐收藏、✍️评论,支持一下博主~ 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值