Cenas:
- Ferramentas de pacote para facilitar o processamento de negócios
- Beans gerenciados pela primavera precisam ser chamados na classe de ferramentas
- A chamada de teste relata um problema de exceção de ponteiro nulo
Código preliminar da ferramenta:
@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"; } } }
O código é deslumbrante e não há nada de errado com ele, mas ele será executado com uma exceção nula, porque o signRepository injetado aqui é nulo. Isso ocorre porque o método estático pertence à classe e o método comum pertence ao objeto. Spring a injeção é instanciada no contêiner. Variáveis e estática existem em preferência aos objetos, portanto, as variáveis estáticas injetadas diretamente no método estático são, na verdade, nulas.
Pensamento:
- Ainda é o problema do ciclo de vida do Spring Bean
- E a ordem de carregamento: Construtor (método de construção) -> @Autowired (injeção de dependência) -> @PostConstruct (método anotado) problema
O ciclo de vida do Spring Bean:
Instanciação e atribuição de propriedade correspondem à injeção de métodos construtores e setter, inicialização e destruição são dois estágios que os usuários podem personalizar e estender
- Instanciação
- Atribuição de atributo Preencher
- Inicialização
- Destruição
Inicialização ==> 4 métodos de transformação do objeto Bean:
Quando convocar a fase de destruição:
- Instância única: quando o contêiner é fechado
- Multi-instância: O contêiner não gerenciará este Bean e não chamará seu método de destruição
Solução um:
@Autowired é usado no construtor
Sabemos que a anotação @Autowired pode anotar variáveis de membros de classe, métodos e construtores para completar o trabalho de montagem automática.Assim, usar @Autowired no construtor.
@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"; } } }
Solução dois:
Use a anotação @PostConstruct
- A partir da especificação Java EE5, duas anotações que afetam o ciclo de vida do Servlet foram adicionadas ao Servlet, @PostConstruct e @PreDestroy
- Explicação desta anotação em Java: @PostConstruct Esta anotação está no pacote javax.annotation e é usada para decorar um método void () não estático
- O método modificado por @PostConstruct será executado quando o servidor carregar o Servlet e só será executado uma vez pelo servidor
- O método modificado por @PostConstruct é executado após o construtor e antes do método init ()
- O método @PreDestroy () é executado depois que o método destroy () é executado
- Regras de anotação @PostConstruct: Exceto para o caso especial de interceptor, nenhum parâmetro é permitido em outros casos, caso contrário, o framework spring reportará IllegalStateException; e se o valor de retorno for nulo, ele pode realmente ter um valor de retorno, pelo menos não relatar um erro, ele só será ignorado
- Normalmente usamos o método de anotação @PostConstruct no framework Spring para anotar a ordem de execução do método de anotação em toda a inicialização do Bean: Construtor (método de construção) -> @Autowired (injeção de dependência) -> @PostConstruct (método anotado)
@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"; } } }
Exemplo 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); } }