Spring相关知识

1. spring

1.1 什么是spring

  • Spring是一个生态:可以构建java应用所需的一切基础设施

  • 通常Spring指的就是Spring Framework

1.2 核心解释

  • spring是一个轻量级的开源容器框架

  • spring是为了解决企业级应用开发的业务逻辑层和其他各层对象和对象直接的耦合问题spring是一个I0C和AOP的容器框架。

  • IOC:控制反转

  • AOP:面向切面编程

  • 容器:包含并管理应用对象的生命周期

2. AOP(面向切面进行编程)

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在将与业务逻辑无关的通用功能(如日志记录、安全性、事务管理等)从核心业务逻辑中分离出来,以增强代码的模块化和可维护性。AOP 通过“切面”来定义这些通用功能,并将其“织入”到特定的程序执行点(如方法调用之前、之后或异常时)。

2.1 AOP 的核心概念

  • 切面(Aspect):切面是定义通用功能的模块,类似于一个类,它包含若干方法,定义了在应用程序中何时、如何执行该功能。

  • 连接点(Join Point):连接点是程序执行的某个具体点,通常是方法调用、异常抛出等。

  • 通知(Advice):通知定义了在特定连接点执行的行为,比如在某个方法执行前或后进行日志记录。

  • 切点(Pointcut):切点是指明哪些连接点会触发通知的执行,通常通过表达式来指定方法或类。

  • 织入(Weaving):织入是指将切面功能应用到目标对象的过程,Spring AOP支持运行时织入,即在应用运行期间,通过代理机制实现切面的应用。

2.2 Spring AOP 代码示例

以下是使用 Spring AOP 的简单示例,展示如何定义一个日志切面,并将其应用到特定的业务方法中。

2.2.1 Maven 依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-aop</artifactId>
</dependency>

2.2.2 定义切面类

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Aspect
@Component
public class LoggingAspect {

    // 在目标方法执行之前调用
    @Before("execution(* com.example.service.MyService.*(..))")
    public void logBefore() {
        System.out.println("方法执行前记录日志。");
    }

    // 在目标方法执行之后调用
    @After("execution(* com.example.service.MyService.*(..))")
    public void logAfter() {
        System.out.println("方法执行后记录日志。");
    }

    // 环绕通知,控制方法的执行
    @Around("execution(* com.example.service.MyService.*(..))")
    public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("方法执行前后记录日志。");
        Object result = joinPoint.proceed(); // 执行目标方法
        System.out.println("方法执行完成。");
        return result;
    }

    // 在目标方法成功返回后调用,并获取返回值
    @AfterReturning(pointcut = "execution(* com.example.service.MyService.*(..))", returning = "result")
    public void logAfterReturning(Object result) {
        System.out.println("方法成功返回,返回值:" + result);
    }

    // 在目标方法抛出异常后调用,并获取异常信息
    @AfterThrowing(pointcut = "execution(* com.example.service.MyService.*(..))", throwing = "error")
    public void logAfterThrowing(Throwable error) {
        System.out.println("方法抛出了异常:" + error);
    }
}

2.2.3 业务类

package com.example.service;

import org.springframework.stereotype.Service;

@Service
public class MyService {

    // 正常业务逻辑
    public String performAction() {
        System.out.println("执行业务逻辑。");
        return "操作成功!";
    }

    // 模拟抛出异常的业务逻辑
    public void performError() {
        System.out.println("执行可能抛出异常的逻辑。");
        throw new RuntimeException("发生了错误!");
    }
}

2.2.4 启用 AOP 配置

确保在应用的配置类中启用了 AOP 支持:

import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableAspectJAutoProxy
public class AppConfig {
}

2.2.5 测试代码

package com.example;

import com.example.service.MyService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.stereotype.Component;

@Component
public class AppRunner implements CommandLineRunner {

    @Autowired
    private MyService myService;

    @Override
    public void run(String... args) throws Exception {
        System.out.println("调用 performAction 方法:");
        String result = myService.performAction();
        System.out.println("返回结果:" + result);

        System.out.println("\n调用 performError 方法:");
        try {
            myService.performError();
        } catch (Exception e) {
            System.out.println("捕获到异常:" + e.getMessage());
        }
    }
}

输出结果

调用 performAction 方法:

方法执行前记录日志。

执行业务逻辑。

方法执行后记录日志。

方法成功返回,返回值:操作成功!

返回结果:操作成功!

调用 performError 方法:

方法执行前记录日志。

执行可能抛出异常的逻辑。

方法执行后记录日志。

方法抛出了异常:java.lang.RuntimeException: 发生了错误!

捕获到异常:发生了错误!

2.3 总结 Spring AOP 中的五种通知类型:

  • @Before:目标方法执行之前触发。

  • @After:目标方法执行之后无论结果如何都会触发。

  • @Around:目标方法执行的前后都会触发,且可以控制方法是否继续执行。

  • @AfterReturning:目标方法正常返回后触发,可以获取返回值。

  • @AfterThrowing:目标方法抛出异常后触发,可以获取异常信息。

3. IoC(控制反转)

IoC 是一种编程设计原则,主要目的是将对象的创建与管理交给外部容器,而不是让对象在内部自行创建。Spring 框架广泛应用 IoC 来进行对象的管理和依赖注入,极大地提高了代码的可维护

性、灵活性和测试性。在传统编程中,对象通常由应用程序显式创建(通过 new 关键字),且对象之间的依赖关系由程序员手动管理。使用 IoC 后,对象的创建和依赖关系的管理都由 IoC 容器

(例如 Spring 容器)负责,程序不再需要显式地去构建和管理依赖。

3.1 IoC 的工作原理

IoC 的核心思想是将控制权从应用程序反转到容器,并通过依赖注入(Dependency Injection, DI)来实现对象之间的解耦。以下是 IoC 的工作方式:

  • 容器管理对象的生命周期:IoC 容器负责创建和销毁应用程序中的对象。

  • 依赖注入:当一个对象依赖于另一个对象时,IoC 容器会在创建对象时自动将依赖注入进去,而不是让对象自己去创建依赖。依赖注入可以通过构造器注入、setter 注入等方式来实现。

  • 解耦:对象不需要知道其他对象是如何创建的,从而实现低耦合。

3.2 IoC 的作用

  • 提高代码的可维护性:通过 IoC,依赖关系通过配置文件或注解声明,而不是直接写在代码里,修改依赖关系时不需要修改业务逻辑。

  • 提高测试性:在测试时可以轻松地替换某些依赖,进行单元测试。

  • 灵活性和扩展性:依赖可以动态注入,可以根据不同的环境或需求使用不同的实现。

3.3 IoC 实现方式

依赖注入是 IoC 的一种实现方式,主要有以下几种注入方式:

  • 构造器注入:通过构造器传入依赖对象。

  • Setter 注入:通过 setter 方法传入依赖对象。

  • 接口注入(在 Spring 中不常用)。

3.4 IoC 的具体代码示例

以下是通过 Spring 框架使用 IoC 和依赖注入的代码示例。

3.4.1 定义业务接口和实现类

// 定义服务接口
public interface MessageService {
    String getMessage();
}

// 实现服务接口
public class EmailMessageService implements MessageService {
    @Override
    public String getMessage() {
        return "这是电子邮件消息";
    }
}

3.4.2 使用 IoC 的业务类

业务类 UserController 依赖于 MessageService,通过 IoC 让 Spring 管理这个依赖。

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

@Component
public class UserController {

    private final MessageService messageService;

    // 通过构造器注入依赖
    @Autowired
    public UserController(MessageService messageService) {
        this.messageService = messageService;
    }

    public void sendMessage() {
        System.out.println(messageService.getMessage());
    }
}

3.4.3 配置类或 XML 文件

可以使用 Spring 的 @Configuration 注解来配置 IoC 容器,或者通过 XML 文件进行配置。

使用 Java 配置:

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class AppConfig {

    // 注册 Bean
    @Bean
    public MessageService messageService() {
        return new EmailMessageService();  // 返回具体的实现类
    }

    // 将 UserController 也交给 Spring 管理
    @Bean
    public UserController userController() {
        return new UserController(messageService());
    }
}

使用 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">

    <!-- 定义 MessageService Bean -->
    <bean id="messageService" class="com.example.EmailMessageService"/>

    <!-- 定义 UserController Bean,并注入 MessageService -->
    <bean id="userController" class="com.example.UserController">
        <constructor-arg ref="messageService"/>
    </bean>
</beans>

3.4.4 启动 Spring 应用

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class Application {
    public static void main(String[] args) {
        // 使用 Java 配置类启动 Spring 容器
        ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

        // 获取 Bean 并调用业务方法
        UserController userController = context.getBean(UserController.class);
        userController.sendMessage();
    }
}

3.4.5 输出结果

当运行应用时,会看到如下输出:

这是电子邮件消息

3.5 IoC 的优点

  • 降低耦合度:业务逻辑不再关心对象的创建,所有对象的创建和管理都交由 IoC 容器来处理,极大地降低了对象之间的耦合度。

  • 更好的可测试性:通过依赖注入,可以在测试时轻松替换依赖的对象,尤其是使用 Mock 框架时。

  • 灵活的配置管理:通过配置文件(如 XML 或 Java 配置类),可以灵活地改变应用程序的依赖关系,减少代码的修改。

3.6 总结

  • IoC 是一种控制权的反转,使得对象的创建、依赖注入等工作从应用程序代码转移到框架中管理。

  • IoC 的主要实现方式是依赖注入,通过构造器注入、setter 注入等方式,轻松管理对象之间的依赖关系。

  • 通过 IoC,开发者可以更加专注于业务逻辑,而无需担心对象的创建和依赖管理,从而提高代码的可维护性、可扩展性和测试性。

posted @ 2024-10-24 00:22  全栈我来了  阅读(110)  评论(0)    收藏  举报