Spring @PostConstruct vs. atributo do método init

103

Existe alguma diferença entre usar a @PostConstructanotação e declarar o mesmo método init-methodda configuração Spring XML?

Jan Zyka
fonte

Respostas:

153

Não, praticamente não acho que haja alguma diferença, mas há prioridades na forma como funcionam. @PostConstruct, init-methodsão BeanPostProcessors.

  1. @PostConstructé uma anotação JSR-250 enquanto init-methodé a maneira do Spring de ter um método de inicialização.
  2. Se você tiver um @PostConstructmétodo, ele será chamado primeiro, antes que os métodos de inicialização sejam chamados.
  3. Se o seu bean implementa InitializingBean e substitui afterPropertiesSet, primeiro @PostConstructé chamado, depois o afterPropertiesSete então init-method.

Para mais informações, você pode verificar a documentação de referência do Spring .

Antes das especificações JSR 250, o uso do método init em xml era a forma preferida, uma vez que desacopla classes java (beans) de quaisquer classes / anotações específicas de spring. Portanto, se você estiver construindo uma biblioteca que não precisa ser dependente de beans de infraestrutura de spring então, o uso do método init foi preferido. Durante o método de criação, você pode especificar o método que precisa ser chamado como método de inicialização.

Agora, com a introdução das especificações JSR 250 no Java EE e o suporte do spring para essas anotações, a dependência do framework do spring foi reduzida até certo ponto.

Mas tenho que admitir que a adição dessas coisas aumenta a legibilidade do código. Portanto, há prós e contras em ambas as abordagens.

Aravind A
fonte
22
Se um bean estiver usando mais de um desses métodos e contando com a ordem de inicialização, será terrivelmente complexo e impossível de manter.
Donal Fellows de
2
@Donal Muito verdadeiro. Estava apenas fornecendo informações de como isso funciona.
Aravind A
1
Há uma diferença importante: você precisa configurar especificamente o Spring para processar anotações para fazer @PostConstruct funcionar: stackoverflow.com/q/3434377/134898
Juan Calero
@DonalFellows, mas você precisa saber disso se planeja fazer os exames de certificação;)
S.Klechkovski
@DonalFellows - Você poderia elaborar sua resposta? Quero dizer, as dificuldades enfrentadas se um bean depender da ordem de inicialização. Na verdade, eu quero saber qual é o melhor. PostConstruct ou Bean (initMethod = "init") para fazer algumas coisas de inicialização de um bean antes de atender a qualquer solicitação?
Ayaskant
19

Não há diferença real. Depende de como você prefere configurar seu sistema e isso é uma questão de escolha pessoal. Eu mesmo prefiro usar @PostConstructanotações para meu próprio código (já que o bean só é configurado corretamente depois que o método é chamado) e eu uso init-methodao instanciar beans de bibliotecas não compatíveis com Spring (não é possível aplicar anotações lá, é claro!) mas posso entender totalmente as pessoas que desejam fazer tudo de uma forma ou de outra.

Donal Fellows
fonte
4

@postconstruct não faz parte da primavera. Faz parte do pacote javax. Ambos são iguais. usando o método init, precisamos adicionar no arquivo xml. Se você usar @postconstruct, adicionar no xml não é necessário. Confira o artigo abaixo.

http://answersz.com/spring-postconstruct-and-predestroy/

Amruth M Raj
fonte
3

Como você pode ver no diagrama abaixo de Bean Creation Life-Cycle Callback .

Retorno de chamada do ciclo de vida da criação do feijão

Esta 3 etapa acontece no retorno de chamada do ciclo de vida da criação do feijão:

  1. É mencionado que @PostConstructserá chamado.
  2. Se InitializingBeanfor implementado, então afterPropertiesSet()será chamado.
  3. Se a definição de bean contém init-methodou @Bean(initmethod="..")então chama o método init.

Este diagrama é do Pro Spring 5: um guia detalhado para o Spring Framework e suas ferramentas

yashjain12yj
fonte
3

Não pode ser diferença entre @PostConstructe init-methodporque @PostConstructé tratada na postProcessAfterInitializationfase de inicialização de feijão ( AbstractAutowireCapableBeanFactory.initializeBean()método) por CommonAnnotationBeanPostProcessor, enquanto initmétodo é chamado após a conclusão da postProcessBeforeInitializationfase (e, por esta matéria, antes do início da postProcessAfterInitializationfase).
EDIT : Então, a sequência é: 1) postProcessBeforeInitializationfase, 2) initmétodo é chamado, 3) postProcessAfterInitializationfase, que chama@PostConstruct método

(Como uma nota lateral, uma declaração da resposta aceita

@PostConstruct, init-method são BeanPostProcessors

não está totalmente correto: @PostConstructé tratado por um BeanPostProcessor, o initmétodo não é.)

Não serão diferença se alguns (potencialmente personalizado) BeanPostProcessor, que é configurado com ( Ordered.getOrder()) a ser executado depois CommonAnnotationBeanPostProcessor, está fazendo algo sério em seu postProcessBeforeInitializationmétodo.
Não nenhuma diferença com a configuração padrão do Spring BeanPostProcessorsporque todos os BeanPostProcessorsque são configurados para serem executados depois CommonAnnotationBeanPostProcessor, não fazem nada nopostProcessBeforeInitialization método.

Concluindo, a resposta aceita e as semelhantes estão certas ... em 99% dos casos, e este post é apenas uma homenagem ao conceito "o diabo está nos detalhes"

igor.zh
fonte
Oi! Isso é confuso, se PostConstruct for executado antes do método init, como ele será tratado pelo postProcessAfterInitialization se o método init for executado após postProcessBeforeInitialization e antes de postProcessAfterInitialization ???
Maxrunner
@Maxrunner, desculpe a confusão e muito obrigado por avisar! Na verdade, eu nunca quis dizer que PostConstruct é executado antes do método init. De qualquer forma, atualizei minha resposta com alguns esclarecimentos
igor.zh
2

Código completo aqui: https://github.com/wkaczurba/so8519187 ( spring-boot )

Usando anotações:

@Slf4j
@Component
public class MyComponent implements InitializingBean {

    @Value("${mycomponent.value:Magic}")
    public String value;

    public MyComponent() {
        log.info("MyComponent in constructor: [{}]", value); // (0) displays: Null
    }

    @PostConstruct
    public void postConstruct() {
        log.info("MyComponent in postConstruct: [{}]", value); // (1) displays: Magic
    }

    @Override // init-method; overrides InitializingBean.afterPropertiesSet()
    public void afterPropertiesSet() {
        log.info("MyComponent in afterPropertiesSet: [{}]", value);  // (2) displays: Magic
    }   

    @PreDestroy
    public void preDestroy() {
        log.info("MyComponent in preDestroy: [{}]", value); // (3) displays: Magic
    }
}

Nos dá:

Atualizando org.springframework.context ...

MyComponent in constructor: [null]
MyComponent in postConstruct: [Magic]
MyComponent in afterPropertiesSet: [Magic]
...

Registrando beans para exposição JMX na inicialização
DemoApplication iniciado em 0,561 segundos (JVM em execução em 1.011)
Fechando org.springframework.context .. Cancelando o registro de beans expostos JMX no desligamento

...
MyComponent in preDestroy: [Magic]

Witold Kaczurba
fonte