静态方法(工具类)中调用Spring管理的Bean

场景:

  • 封装工具类,方便业务处理
  • 工具类中需要调用 spring管理的Bean
  • 测试调用报空指针异常问题

初步工具类代码:

@Component
public class ScriptExecuteContent {

@Autowired
private static SignRepository signRepository;

public static String checkSign(String certNo, String acctNo, String instCode) {
    Sign sign = signRepository.findByCertNoAndAcctNoAndInstCode(certNo, acctNo, instCode);
    if (null != sign
            && StringUtils.equals(sign.getStatus(), StatusEnum.SUCCESS.code())
            && DateUtil.getCurrentDate().before(sign.getExpireTime())) {
        return "1";
    } else {
        return "0";
    }
}
}

该段代码晃眼一看没啥问题,但是运行就会null异常,因为此处注入的signRepository为null,这是因为静态方法是属于类的,普通方法才属于对象,spring注入是在容器中实例化变量的,并且静态是优先于对象存在的,所以直接在静态方法中调用注入的静态变量其实是为null的。

思考: 

 

Spring Bean的生命周期:

实例化和属性赋值对应构造方法和setter方法的注入,初始化和销毁是用户能自定义扩展的两个阶段

  • 实例化 Instantiation
  • 属性赋值 Populate
  • 初始化 Initialization
  • 销毁 Destruction

初始化阶段Initialization  ==>  Bean 对象改造的4中方法:

销毁 Destruction阶段调用时机:

  • 单实例:容器关闭的时候
  • 多实例:容器不会管理这个Bean,不会调用它的销毁方法
     

解决方案一:

 @Autowired 用在构造函数上

我们知道@Autowired 注释,可以对类成员变量、方法及构造函数进行标注,完成自动装配的工作,此种方式就是在构造函数上使用@Autowired。

@Component
public class ScriptExecuteContent {

private static SignRepository signRepository;

@Autowired
public ScriptExecuteContent(SignRepository signRepository) {
    ScriptExecuteContent.signRepository = signRepository;
}

public static String checkSign(String certNo, String acctNo, String instCode) {
    Sign sign = signRepository.findByCertNoAndAcctNoAndInstCode(certNo, acctNo, instCode);
    if (null != sign
            && StringUtils.equals(sign.getStatus(), StatusEnum.SUCCESS.code())
            && DateUtil.getCurrentDate().before(sign.getExpireTime())) {
        return "1";
    } else {
        return "0";
    }
}
}

解决方案二:

使用 @PostConstruct 注解

  • 从Java EE5规范开始,Servlet中增加了两个影响Servlet生命周期的注解,@PostConstruct和@PreDestroy
  • Java中该注解的说明:@PostConstruct该注解是javax.annotation包下的,被用来修饰一个非静态的void()方法
  • 被@PostConstruct修饰的方法会在服务器加载Servlet的时候运行,并且只会被服务器执行一次
  • 被@PostConstruct修饰的方法在构造函数之后执行,init()方法之前执行
  • 被@PreDestroy()方法在destroy()方法执行之后执行
  • @PostConstruct注释规则:除了拦截器这个特殊情况以外,其他情况都不允许有参数,否则spring框架会报IllegalStateException;而且返回值要是void,但实际也可以有返回值,至少不会报错,只会忽略
  • 通常我们会是在Spring框架中使用到@PostConstruct注解 该注解的方法在整个Bean初始化中的执行顺序:Constructor(构造方法) -> @Autowired(依赖注入) -> @PostConstruct(注释的方法)

                                                                   

@Component
public class ScriptExecuteContent {

@Autowired
private SignRepository signRepository;

private static ScriptExecuteContent scriptExecuteContent;

@PostConstruct
public void update() {
    scriptExecuteContent = this;
    scriptExecuteContent.signRepository = this.signRepository;
}

public static String checkSign(String certNo, String acctNo, String instCode) {
    Sign sign = scriptExecuteContent.signRepository.findByCertNoAndAcctNoAndInstCode(certNo, acctNo, instCode);
    if (null != sign
            && StringUtils.equals(sign.getStatus(), StatusEnum.SUCCESS.code())
            && DateUtil.getCurrentDate().before(sign.getExpireTime())) {
        return "1";
    } else {
        return "0";
    }
}
}

范例2:

@Component
public class StaticBook {
    private static String url;

    @Value("${test.str}")
    private String str;

    @PostConstruct
    public void update() {
        this.url = this.str;
    }

    public static BookTestTemp getValue(){
        return new BookTestTemp(1, "bookName", "123", url);
    }
}

猜你喜欢

转载自blog.csdn.net/xiangwang2016/article/details/106148880