2

前言

在使用Spring Boot框架的开发时,"上下文" 是一个非常重要的概念。上下文(Context)不仅帮助我们在应用程序的不同部分传递信息,还能用于管理应用的配置和状态。之前不太理解上下文,其实我门早就是使用到了上下文的概念了,继续往下看,你肯定用到过下面功能。

什么是上下文?

上下文,顾名思义是指程序执行时的一种环境信息或状态,通常包含了当前请求、配置、资源等一系列信息。在Spring Boot中,上下文可以被视为一个容器,用于存储和管理应用程序的配置信息、对象实例(Bean)以及它们之间的依赖关系。这个容器是整个应用程序运行的基础,负责组织和管理不同模块的交互。

上下文作用

存储配置信息:上下文通常包含应用程序的全局配置信息,比如数据库配置、缓存配置等。这些信息在整个应用程序中共享。
管理 Bean 生命周期:Spring 的上下文可以创建、管理、销毁 Bean,并负责 Bean 之间的依赖注入,简化了开发过程。
资源共享:上下文允许不同模块或组件之间共享数据或资源,避免重复配置和数据传递。
应用事件管理:上下文还可以用来监听和处理应用程序中的事件,如应用启动、关闭、异常等。

为什么要有上下文?

依赖注入的基础

在传统的面向对象编程中,类与类之间的依赖关系通常通过构造函数、工厂方法等方式进行显式地管理。这种方式往往会导致代码的耦合度较高,并且增加了维护难度。而上下文为开发者提供了一种简洁的依赖注入机制。
Spring Boot使用上下文来管理应用程序中的 Bean。通过上下文,开发者可以轻松地将类的依赖注入到其他类中,而不需要手动实例化这些类。Spring 上下文自动负责这些 Bean 的创建、初始化、销毁等生命周期管理。
例如,在一个 Spring Boot 项目中,假设我们有一个 UserServiceImpl 依赖于 UserRepository

@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserRepository userRepository;

    public User getUserById(Long id) {
        return userRepository.findById(id).orElseThrow(EntityNotFoundException::new);
    }
}

在这个例子中,UserServiceImpl 并不需要显式地创建 UserRepository 实例。Spring Boot 的上下文会根据注解(如 @Autowired)自动将 UserRepository 注入到 UserServiceImpl 中,从而极大地简化了对象的依赖管理。

配置的集中管理

当我门在团队开发的时候,每个人的电脑环境不一样,这个时候我们可以将这些配置信息集中管理,避免在代码中硬编码配置,并且能够根据不同环境灵活切换配置。
application.yml 文件定义配置时,这些配置会被自动加载到上下文中,供应用的各个部分使用。例如:

spring:
  config:
    activate:
      on-profile: ZJ-TUTE
  datasource:
    url: "jdbc:mysql://localhost:3307/minio-brower?characterEncoding=utf-8"
    username: "root"
    password: "123456"

事件驱动机制

即当应用程序中的某些操作或状态变化时,可以发布事件,相关的组件可以监听并响应这些事件。
例如,我们可以监听应用程序启动事件,执行一些初始化操作,例如:

@Component
public class InitUser implements ApplicationListener<ContextRefreshedEvent>, Ordered {
  public static int order = Integer.MIN_VALUE;
  private static final Logger logger = LoggerFactory.getLogger(InitUser.class);

  private final UserRepository userRepository;

  public InitUser(UserRepository userRepository) {
    this.userRepository = userRepository;
  }

  @Override
  public void onApplicationEvent(ContextRefreshedEvent contextRefreshedEvent) {

    logger.info("初始化用户");
    if (userRepository.count() == 0) {
      User user = new User();
      user.setName("admin");
      user.setUsername("admin");
      user.setPassword("admin");
      userRepository.save(user);
    }
  }

当项目启动的时候,就会先初始化一个用户。

上下文的实际应用场景

Web 应用中的上下文

在 Web 应用中,我们可以通过上下文获取与请求、会话相关的信息。例如:

@PostMapping(produces = "text/xml; charset=UTF-8")
  public void api(HttpServletRequest httpServletRequest,
                  HttpServletResponse httpServletResponse,
                  @RequestParam("signature") String signature,
                  @RequestParam(name = "encrypt_type", required = false) String encType,
                  @RequestParam(name = "msg_signature", required = false) String msgSignature,
                  @RequestParam("timestamp") String timestamp,
                  @RequestParam("nonce") String nonce) throws IOException {
}

通过 HttpServletRequest 获取当前请求信息,HttpServletResponse 代表响应的上下文,用于构建返回给客户端的响应。

配置文件的注入与使用

在上下文中将外部配置文件中的参数直接注入到某个类中。例如,假设我们在 application.yml 文件中定义了一些应用配置:

image.png

我们可以通过 @Value 注解将这些配置注入到类中:

  @Value("${wx.mp.token}")
  private String token;

  @Value("${wx.mp.appid}")
  private String appid;

  @Value("${wx.mp.secret}")
  private String appSecret;

  @Value("${wx.mp.aesKey}")
  private String aesKey;

通过上下文,Spring Boot 自动加载配置文件并解析其中的配置参数。

安全上下文的使用

在安全框架中,安全上下文用于存储当前用户的身份信息和权限信息。Spring Security 提供了 SecurityContextHolder 类,它封装了用户认证和授权的上下文信息。
例如,我们可以通过安全上下文获取当前用户的身份信息:

@GetMapping("/currentUser")
    public String getCurrentUser() {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
        //当前用户
        return authentication.getName();
    }

SecurityContextHolderSpring Security 的上下文管理器,它提供了关于当前用户的安全信息。

总结

当初始化一个Spring项目时,实际上已经在使用Spring的上下文。上下文在应用启动时被创建并充当应用的核心管理者,会扫描、注册、管理Bean,提供全局的配置、事件管理等一些 功能。


zZ_jie
401 声望9 粉丝

虚心接受问题,砥砺前行。