spring在静态方法中使用注入类

在开发时遇到需要将多个来源的数据转换为统一的格式,不同来源的数据转换逻辑不同。所以想利用工厂模式 让所有的转换类继承一个公有的类 然后在工厂类中根据不同的来源 返回不同的实例。比如在处理A数据源时 返回AConverter,处理B数据源时 返回BConverter
一开始的写法:

@Component
public class ConverterFactory {

@Resource
private AConverter aConverter;
@Resource
private BConverter bConverter;
@Resource
private CConverter cConverter;

public static POIConverter getConverter(String type) {
    switch (type) {
        case "a" : return aConverter;
        case "b" : return bConverter;
        case "c" : return cConverter;
    }
    return null;
}

}
可是会报错 因为静态方法中不能使用非静态的变量,而Resource注解不支持静态属性上添加。同事给出了解决方案 在初始化之后将包涵已经注入好各个converter的this付给一个静态的变量factory 在getConverter方法中 通过factory来获得注入的对象。

[java] view plain copy
@Component
public class ConverterFactory {

@Resource  
private AConverter aConverter;  
@Resource  
private BConverter bConverter;  
@Resource  
private CConverter cConverter;  

private static ConverterFactory factory;  

@PostConstruct  
public void init() {  
    factory = this;  
}  

public static POIConverter getConverter(String type) {  
    switch (type) {  
        case "a" : return factory.aConverter;  
        case "b" : return factory.bConverter;  
        case "c" : return factory.cConverter;  
    }  
    return null;  
}  

}

原文地址:https://segmentfault.com/a/1190000003858538

对于注解@PostConstruct的说明:http://www.cnblogs.com/damowang/p/4172478.html

<think>我们面对的问题是:如何在静态方法使用Spring管理的Bean。由于@Autowired不能直接用于静态字段(因为Spring基于实例进行依赖注入),我们需要通过间接方式实现。参考解决方案:1.使用@PostConstruct生命周期回调:通过非静态字段接收注入,再赋值给静态变量2.使用ApplicationContextAware接口获取Spring上下文,然后通过上下文获取Bean考虑到用户想在静态方法使用,我们重点介绍如何将Bean赋值给静态变量,以便静态方法可以访问。方案一:使用@PostConstruct步骤:a.在中定义静态字段(目标)b.定义非静态字段并使用@Autowired注入c.使用@PostConstruct方法注入的实例赋值给静态字段示例代码:注意:静态方法可以通过这个静态字段访问到注入的Bean。方案二:实现ApplicationContextAware接口这种方式可以获取到Spring的ApplicationContext,然后通过它来获取Bean。我们同样可以在初始化时将需要的Bean赋值给静态变量。下面分别给出两个方案的代码示例:方案一示例:```importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importjavax.annotation.PostConstruct;@ComponentpublicclassMyStaticUtil{privatestaticMyServicemyServiceStatic;//静态字段@AutowiredprivateMyServicemyServiceInstance;//非静态字段,用于注入@PostConstructpublicvoidinit(){myServiceStatic=myServiceInstance;//将注入的非静态字段赋值给静态字段}publicstaticvoidperformStaticTask(){//现在静态方法中可以使用myServiceStaticmyServiceStatic.doSomething();}}```方案二示例(更通用,可以获取任意Bean,但通常用来获取自身需要的特定Bean):我们也可以结合ApplicationContextAware和静态字段,但是注意,直接使用ApplicationContext来获取Bean在静态方法中会稍显繁琐。下面示例是在初始化时获取特定Bean并赋值给静态字段:```importorg.springframework.beans.BeansException;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.stereotype.Component;@ComponentpublicclassSpringContextHolderimplementsApplicationContextAware{privatestaticApplicationContextapplicationContext;@OverridepublicvoidsetApplicationContext(ApplicationContextapplicationContext)throwsBeansException{SpringContextHolder.applicationContext=applicationContext;}publicstatic<T>TgetBean(Class<T>beanClass){returnapplicationContext.getBean(beanClass);}}```然后在静态方法中,我们可以这样使用:MyServicemyService=SpringContextHolder.getBean(MyService.class);myService.doSomething();但是注意,这种方式在静态方法中每次调用都要通过getBean,而且要求调用时ApplicationContext已经初始化,并且存在该型的Bean。如果只是想让静态方法访问特定的Bean,建议使用方案一,因为更直接。总结:-方案一适用于静态方法需要使用特定Bean的情况,而且这个Bean在初始化时就已知。-方案二适用于需要动态获取各种Bean的情况,提供了更大的灵活性。然而,值得注意的是,在静态方法使用依赖注入的Bean违背了Spring的依赖注入原则(面向对象),因此应该谨慎使用。建议优先考虑重构代码,避免在静态方法使用注入的Bean,而是通过Spring管理的Bean来调用。相关问题:1.在静态方法中调用Spring注入的Bean会有什么问题?2.除了@PostConstruct,还有哪些生命周期回调方法?3.如何确保在静态方法中获取Spring容器时容器已经初始化完成?</think> ### 如何在静态方法使用Spring依赖注入的解决方案 #### ⚙️ 核心问题分析 Spring的依赖注入基于**对象实例**实现,静态方法和字段属于级别,无法直接使用`@Autowired`。解决方案需通过**中介对象**桥接静态方法与容器管理的Bean[^2][^3]。 --- ### ✅ 推荐解决方案 #### 方案1:通过实例字段过渡(最优解) ```java @Component public class DeptService { private static SysDeptQueueMapper staticMapper; // 静态目标 @Autowired private SysDeptQueueMapper instanceMapper; // 非静态注入点 @PostConstruct private void initStatic() { staticMapper = instanceMapper; // 关键赋值 } public static void staticMethod() { staticMapper.selectById(1); // 安全调用 } } ``` **原理**: 1. 非静态字段`instanceMapper`由Spring注入 2. `@PostConstruct`在依赖注入完成后执行赋值 3. 静态字段`staticMapper`获得有效实例引用[^2] **优势**: - 线程安全(单例模式) - 100%兼容Spring生命周期 - 符合IoC设计规范 #### 方案2:应用上下文持有器 ```java @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); } } // 静态方法中的使用 public class DeptUtils { public static void updateDept() { SysDeptQueueMapper mapper = SpringContext.getBean(SysDeptQueueMapper.class); mapper.updateById(...); } } ``` **适用场景**: - 需要动态获取不同型的Bean - 跨多个静态方法的通用工具[^2] --- ### ⚠️ 典型错误示范 ```java // 错误方案:直接注入静态字段 @Component public class WrongExample { @Autowired // 完全无效! private static SysDeptQueueMapper mapper; // 始终为null public static void errorMethod() { mapper.selectList(null); // NullPointerException } } ``` **原因**: Spring的`AutowiredAnnotationBeanPostProcessor`会主动忽略static字段[^3]。 --- ### 📊 方案对比表 | 方案 | 线程安全 | 适用场景 | Spring规范符合度 | |------|----------|----------|------------------| | 实例字段过渡 | ✅ | 特定Bean的静态调用 | ⭐⭐⭐⭐⭐ | | 上下文持有器 | ✅ | 动态获取多型Bean | ⭐⭐⭐⭐ | | 直接注入静态字段 | ❌ | 永远不可行 | ⭕ | --- ### 🌟 最佳实践建议 1. **优先重构代码** - 99%的静态方法依赖需求可通过合理设计对象结构解决 - 将“静态工具”改造为`@Component`管理的Service 2. **强制依赖检查** 在静态方法起始处增加校验: ```java public static void criticalMethod() { if(staticMapper == null) throw new IllegalStateException("依赖未初始化!"); // ... } ``` 3. **控制使用范围** 静态方法调用注入Bean的适用场景: - 遗留系统改造 - 工具整合 - 与静态API(如JPA回调)的对接 > **架构警示**:频繁在静态方法使用容器依赖会破坏IoC设计原则,使代码难以测试和维护[^1]。 --- ### ❓相关问题 1. `@PostConstruct`中的初始化操作是否会重复执行? [^2]: 单例Bean只会初始化一次 2. 如何在Quartz定时任务中使用依赖注入? [^1]: 通过`JobFactory`集成Spring容器 3. 静态字段赋值是否存在线程竞争风险? [^2]: 单例模式初始化线程安全 4. 如何验证静态依赖是否成功注入? [^3]: 使用`BeanPostProcessor`调试注入过程 [[^1]: 字段注入文档](https://spring.io/guides) [[^2]: 静态字段解决方案](https://stackoverflow.com/a/4397189) [[^3]: 注入处理器源码](https://github.com/spring-projects/spring-framework/blob/main/spring-beans/src/main/java/org/springframework/beans/factory/annotation/AutowiredAnnotationBeanPostProcessor.java)]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值