复用代码系列:Spring的ContextHolder

本文介绍三种从Spring ApplicationContext中获取Bean的方法。提供了实用的代码示例,包括如何利用静态变量保存ApplicationContext,以及如何通过注入ApplicationContext来获取Bean。
部署运行你感兴趣的模型镜像

复用代码系列目录

从Spring的ApplicationContext上下文中获取指定的Bean,复用代码如下:

代码一:

package com.spring.context_holder;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

/**
 * 以静态变量保存Spring Application, 可以在任何代码任何地方任何时候取出ApplicationContext
 * 
 *
 */
public class SpringContextHolder implements ApplicationContextAware {
 
    private static ApplicationContext applicationContext;
    
    private static Logger logger = LoggerFactory.getLogger(SpringContextHolder.class);
    /**
     * 实现ApplicationContextAware接口的context注入函数,将其存入静态变量
     */
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        SpringContextHolder.applicationContext = applicationContext;
        logger.debug("SpringContextHolder注入ApplicationContext");
    }

    /**
     * 获取存储在静态变量中的ApplicationContext
     * 
     * @return
     */
    public static ApplicationContext getApplicationContext() {
        checkApplicationContext();
        return applicationContext;
    }

    /**
     * 从静态变量ApplicationContext中获取Bean,自动转型为所赋值对象的类型
     * @param <T>
     * @param name
     * @return
     */
    @SuppressWarnings("unchecked")
    public static <T> T getBean(String name){
        checkApplicationContext();
        return (T) applicationContext.getBean(name);
    }
    
    @SuppressWarnings("unchecked")
    public static <T> T getBean(Class<T> clazz){
        checkApplicationContext();
        return (T) applicationContext.getBeansOfType(clazz);
    }
    /**
     * 清除ApplicationContext静态变量.
     */
    public static void cleanApplicationContext(){
        applicationContext=null;
    }
    /**
     * 检查是否获取到了ApplicationContext
     */
    private static void checkApplicationContext() {
        if (applicationContext == null) {
            throw new IllegalStateException(
                    "applicationContext未注入,请在applicationContext.xml中定义SpringContextHolder");
        }
    }
}

代码二:

package com.spring.context_holder;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;


@Service
@Lazy(false)
/**
 * 获取bean的工具类(通过注入applicationCotnext)
 *
 */
public class SpringUtils implements ApplicationContextAware,DisposableBean
{
    public static  ApplicationContext applicationContext = null;

    @SuppressWarnings("unchecked")
    public static <T> T getBean(String beanName){
        isInjected();
        return (T) applicationContext.getBean(beanName);
    }

    public static <T> T getBean(Class<T> requiredType){
        isInjected();
        return applicationContext.getBean(requiredType);
    }


    @Override
    public void destroy() throws Exception {    
        System.out.println("springUtils工具类清除注入的applicationContext");
        SpringUtils.applicationContext = null;
    }

    @Override
    public void setApplicationContext(ApplicationContext applicationContext)
            throws BeansException {
        System.out.println("springUtils工具类注入的applicationContext");
        SpringUtils.applicationContext = applicationContext;
    }

    /**
     * 判断是否注入
     * @return
     */
    public static void isInjected(){
        if(SpringUtils.applicationContext == null){
            throw new RuntimeException("springUtils applicationContext is not injected!");
        }
    }

    public static void main(String[] args) {
        System.out.println(applicationContext);
    }


}

代码三:

package com.spring.context_holder;

import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;

public class SpringBeanFactoryUtils  implements ApplicationContextAware {
    private static ApplicationContext appCtx;    
    /**  
     * 此方法可以把ApplicationContext对象inject到当前类中作为一个静态成员变量。  
     * @param applicationContext ApplicationContext 对象.  
     * @throws BeansException  
     * @author wangdf 
     */    
     
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {    
        appCtx = applicationContext;    
    }  
       
    /** 
     * 获取ApplicationContext 
     * @return 
     * @author wangdf 
     */  
    public static ApplicationContext getApplicationContext(){  
        return appCtx;  
    }  
       
    /**  
     * 这是一个便利的方法,帮助我们快速得到一个BEAN  
     * @param beanName bean的名字  
     * @return 返回一个bean对象  
     * @author wangdf 
     */    
    public static Object getBean(String beanName) {    
        return appCtx.getBean(beanName);    
    }    
}   


                

您可能感兴趣的与本文相关的镜像

Llama Factory

Llama Factory

模型微调
LLama-Factory

LLaMA Factory 是一个简单易用且高效的大型语言模型(Large Language Model)训练与微调平台。通过 LLaMA Factory,可以在无需编写任何代码的前提下,在本地完成上百种预训练模型的微调

<think>我们正在讨论Java中获取上下文信息的方法。根据用户的问题和之前的对话历史,用户希望了解在Java代码中获取上下文信息的不同方法。之前的回答已经详细介绍了获取HTTP请求头(Header)参数的三种方法,但用户现在的问题更广泛,是关于获取上下文信息(可能包括但不限于HTTP请求上下文、应用上下文等)。 结合引用内容,我们可以总结以下几种获取上下文信息的方法: 1. 方法参数传递(引用[1]):通过方法参数显式传递上下文数据。 2. 自定义上下文类(引用[2]):创建上下文类来封装公共上下文,并通过操作接口进行抽象。 3. 基于ThreadLocal的上下文管理(引用[3]):使用ThreadLocal来存储线程相关的上下文信息,尤其适用于多线程环境。 4. 通过Servlet API获取Web上下文(引用[4]):在Web应用中,通过HttpServletRequest、ServletContext等对象获取上下文路径或属性。 5. 获取Spring应用上下文(引用[5]):在Spring框架中,获取ApplicationContext对象来访问Bean和配置信息。 因此,我们将按照这些类别来组织回答。 另外,用户的问题是“我想查找在Java代码中获取上下文信息的方法”,所以我们需要覆盖这些不同的场景。 注意:我们需要在回答中自然地引用提供的引用标记([^1]到[^5]),但不要强制引用,只在相关内容处引用。 回答结构: 1. 方法参数传递(简单场景) 2. 自定义上下文类(面向对象设计) 3. 基于ThreadLocal的上下文管理(多线程场景) 4. Web应用中的上下文获取(Servlet上下文) 5. Spring框架中的上下文获取(ApplicationContext) 每个部分给出简要说明和代码示例。 最后,按照要求生成相关问题。 </think>### Java代码中获取上下文信息的方法全解析 在Java中,“上下文”通常指程序运行时的环境信息,包括线程状态、Web请求参数、应用配置等。以下是5类核心方法及其适用场景: --- #### 1. **方法参数显式传递** 通过方法参数直接传递上下文数据[^1],适用于简单调用链场景。 ```java // 示例:计算两数之和 public static int addNumbers(int a, int b) { // 上下文参数显式传递 return a + b; } public static void main(String[] args) { int result = addNumbers(10, 20); // 传递上下文数据 } ``` **特点**: - ✅ 简单直接,无额外依赖 - ❌ 不适合深层调用链 --- #### 2. **自定义上下文类** 封装公共上下文到独立类中[^2],适合复杂业务逻辑解耦。 ```java // 定义上下文类 public class AppContext { private String userId; private String traceId; public AppContext(String userId, String traceId) { this.userId = userId; this.traceId = traceId; } // getters... } // 操作接口抽象 public interface Operation { void execute(AppContext context); } // 上下文使用 public class PaymentService implements Operation { @Override public void execute(AppContext context) { System.out.println("UserID: " + context.getUserId()); } } ``` **特点**: - ✅ 高复用性,支持多操作封装 - ❌ 需额外设计接口和类 --- #### 3. **ThreadLocal上下文管理** 通过线程局部变量存储上下文[^3],解决多线程数据隔离问题。 ```java public class ContextManager { private static final ThreadLocal<AppContext> contextHolder = new ThreadLocal<>(); public static void setContext(AppContext ctx) { contextHolder.set(ctx); } public static AppContext getContext() { return contextHolder.get(); } public static void clear() { contextHolder.remove(); } } // 使用示例 ExecutorService executor = Executors.newFixedThreadPool(2); executor.submit(() -> { ContextManager.setContext(new AppContext("U1001", "TRACE_123")); // 设置线程上下文 new PaymentService().execute(ContextManager.getContext()); // 获取上下文 ContextManager.clear(); // 防止内存泄漏 }); ``` **特点**: - ✅ 线程安全,天然隔离 - ⚠️ 需手动清理防内存泄漏 --- #### 4. **Servlet API获取Web上下文** 通过Servlet容器API获取Web应用上下文[^4],适用于JavaEE应用。 ```java // 获取工程物理路径 String realPath = request.getServletContext().getRealPath("/uploads"); // 获取类加载路径 URL classPath = Thread.currentThread().getContextClassLoader().getResource(""); // 获取系统路径 String userDir = System.getProperty("user.dir"); // 项目根目录 ``` **特点**: - ✅ 标准化Web资源访问 - ❌ 依赖Servlet容器 --- #### 5. **Spring框架上下文管理** 通过ApplicationContext获取Spring托管Bean和配置[^5]。 ```java // 方法1:实现ApplicationContextAware @Component public class SpringContext implements ApplicationContextAware { private static ApplicationContext context; @Override public void setApplicationContext(ApplicationContext ctx) { context = ctx; } public static <T> T getBean(Class<T> beanClass) { return context.getBean(beanClass); } } // 方法2:直接注入 @RestController public class UserController { @Autowired private ApplicationContext context; // Spring自动注入 @GetMapping("/user") public User getUser() { return context.getBean(UserService.class).findUser(); } } ``` **特点**: - ✅ 全面管理Bean生命周期 - ❌ 依赖Spring框架 --- ### 方法选型指南 | **场景** | **推荐方法** | **关键优势** | |---------------------------|-------------------------|--------------------------| | 简单参数传递 | 方法参数显式传递[^1] | 零依赖,代码透明 | | 跨层级业务解耦 | 自定义上下文类[^2] | 高扩展性 | | 多线程数据隔离 | ThreadLocal管理[^3] | 线程安全 | | Web资源路径获取 | Servlet API[^4] | 标准化访问 | | Spring Bean依赖管理 | ApplicationContext[^5] | 完整的IoC容器支持 | > **最佳实践**: > - Web开发优先选择Servlet API或Spring上下文 > - 工具类/中间件使用ThreadLocal管理上下文 > - 避免在静态变量中存储可变上下文数据 --- ### 常见问题解决方案 1. **ThreadLocal内存泄漏** 使用`try-finally`确保清理: ```java try { ContextManager.setContext(...); // 业务逻辑 } finally { ContextManager.clear(); } ``` 2. **Spring上下文获取失败** 检查Bean作用域:确保非`prototype`作用域的Bean才可实现`ApplicationContextAware`。 3. **Web路径获取为null** 使用标准化路径格式: ```java // 正确写法 String path = request.getServletContext().getRealPath("/WEB-INF/config.xml"); ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值