Spring在使用的类方法里仍能使用注入的依赖的相关措施

今天依要求做一个数据字典的模块,其中要做的一个业务是更新数据字典后删除对应的缓存,这里要求使用类方法。一开始我是这么写的。(改动的是refreshCacheByEntryId() )

错误写法1:类方法里含有没有static修饰的对象

@Component
@Log4j2
public class DictUtils {

  private static DictUtils dictUtils;
  @Autowired
  private DictEntryService dictEntryService;

 @Value("${spring.profiles.active}")
 private  String env;

  public static void initMap(){
    bitMap = MapUtil.newHashMap();
    log.error("缓存Map清除完毕");
  }  

 // 刷单个redis的dict
  public static void refreshCacheByEntryId(@NotNull String entryId){
    boolean b = false;
    // 这里也会爆红
    if( this.env.equals("dev") ){
    // 此处会在这里报红
      DictEntry entry = dictEntryService.getByEntityId(entryId);
      ...
  }
}

这种方式在DictEntry entry = dictEntryService.getByEntityId(entryId);这一行就开始报红了,也就是说不能后在类方法里访问本类的属性

错误写法2:没有用static修饰方法

然后试了下吧static给去掉

@Component
@Log4j2
public class DictUtils {

  private static DictUtils dictUtils;
  @Autowired
  private DictEntryService dictEntryService;

// 加上了static
 @Value("${spring.profiles.active}")
 private static String env;

public static void initMap(){
    bitMap = MapUtil.newHashMap();
    log.error("缓存Map清除完毕");
  }  

 // 刷单个redis的dict
  public void refreshCacheByEntryId(@NotNull String entryId){
    boolean b = false;
    
    if( DictUtils.env.equals("dev") ){
    
      DictEntry entry = dictEntryService.getByEntityId(entryId);
      ...
  }
}

这样是不报红了,但是如果在另外一方直接引入的话,比如下方

@RestController("dictEntryController")
@RequestMapping("/api/v1/dict/dictEntry")
public class DictEntryController extends BaseController {
	@Autowired
    private DictEntryService dictEntryService;

	@PutMapping(value = "{id}")
    @ApiOperation(value = "更新对象记s录", notes = "更新对象记录", produces = "application/json")
        public R update(@RequestBody DictEntry entity) {
        R<DictEntry> entryR = dictEntryService.update(entity);
        // 清空缓存
        if(entryR.isSuccess()){
        	// 此处在方法执行的时候会报红
            DictUtils.refreshCacheByEntryId(entity.getId());
            System.out.println("111");
        }
        return entryR;
    }

}

会发现执行到 DictUtils.refreshCacheByEntryId(entity.getId());爆红了,因为不能不能直接使用对象方法,只能用new来使用对象方法,那就和一开始我们要的使用类方法来实现不符了

错误写法3:直接同时用static修饰方法,用static修饰依赖

那既然这样,把方法和依赖同时用static来修饰不就可以了么?此处做法会发现一个很大的问题。先黏代码

@Component
@Log4j2
public class DictUtils {

  private static DictUtils dictUtils;

	// 用static修饰
  @Autowired
  private static DictEntryService dictEntryService;

	// 用static修饰
	@Value("${spring.profiles.active}")
     private static String env2;

public static void initMap(){
    ...
  }  

	// 用static修饰方法
  public static void refreshCacheByEntryId(@NotNull String entryId){
    boolean b = false;
    // 用DictUtils.env获取
    if( DictUtils.env.equals("dev") ){
    	// 此处不会爆红,但是会引发注入问题,下文说
      DictEntry entry = dictEntryService.getByEntityId(entryId);
      ...
  }
}

然后另一方的调用

@RestController("dictEntryController")
@RequestMapping("/api/v1/dict/dictEntry")
public class DictEntryController extends BaseController {
	@Autowired
    private DictEntryService dictEntryService;

	@PutMapping(value = "{id}")
    @ApiOperation(value = "更新对象记s录", notes = "更新对象记录", produces = "application/json")
        public R update(@RequestBody DictEntry entity) {
        R<DictEntry> entryR = dictEntryService.update(entity);
      
        if(entryR.isSuccess()){
        	// 此处不报红了
            DictUtils.refreshCacheByEntryId(entity.getId());
        }
        return entryR;
    }

}

然后接下来发现运行的时候,报错了,报了个null指针,在哪里报错了?
而且发现env也为null ,@Value注解获取配置文件的值env失败了

	// 就是这一行,env为null
		if( DictUtils.env.equals("dev") ){
        	// 这一行也是,此时dictEntryService为null
            DictUtils.refreshCacheByEntryId(entity.getId());
        }
    	
      DictEntry entry = dictEntryService.getByEntityId(entryId);
      ...

奇怪,那dictEntryService不是已经写了@Autowired了么?为什么为null?是注入失败了么?
答案是是的
那该如何解决这个问题 ?

解决问题

答案是如果想要既实用类方法,又要类方法里面的依赖成功注入,那么要这么做

@Component
@Log4j2
public class DictUtils {

	// 此处要加static
  private static DictUtils dictUtils;

	// 此处不用加static
  @Autowired
  private DictEntryService dictEntryService;

	// 此处不用加static
 @Value("${spring.profiles.active}")
 private String env;

  private static Map<String,List<DictEntry>> bitMap;
  

	// 进行初始化操作赋值
  @PostConstruct
  public void init() {
    dictUtils = this;
    dictUtils.dictEntryService = this.dictEntryService;
    dictUtils.env  = this.env;
    bitMap = MapUtil.newHashMap();
  }

	public static void initMap(){
	    ...
	 }  

  public static void refreshCacheByEntryId(@NotNull String entryId){
    boolean b = false;
    // 此处改成dictUtils
    if( dictUtils.env.equals("dev") ){
    	// 此处改成dictUtils
      DictEntry entry = dictUtils.dictEntryService.getByEntityId(entryId);
      ...
  }
}

此时是可行的,为什么呢?
因为在@PostConstruct注解中,他的执行顺序是在@Autowired之后的,而@Autowired是在装载类之后的
即顺序:装载类——Autowired——PostConstruct
此时dictUtils = this;此时的this才是已经被装配的(类上有 @Component 注解),然后之后使用这种方式就能够完美获得注入的依赖,而且@Value注解也生效了
实现了在spring里使用类方法来实现业务,并且同时能在类方法里使用已经注入的依赖

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值