Como chamar um método após a inicialização do bean ser concluída?

237

Eu tenho um caso de uso em que preciso chamar um método (não estático) no bean apenas uma vez no carregamento do ApplicationContext. Tudo bem, se eu usar MethodInvokingFactoryBean para isso? Ou temos uma solução melhor?

Como uma observação lateral, eu uso o ConfigContextLoaderListener para carregar o Contexto do Aplicativo no aplicativo Web. E quer, se o bean 'A' for instanciado, chame methodA () uma vez.

Como isso pode ser bem feito?

pico
fonte

Respostas:

196

Você pode usar algo como:

<beans>
    <bean id="myBean" class="..." init-method="init"/>
</beans>

Isso chamará o método "init" quando o bean for instanciado.

Mercer Traieste
fonte
15
O postConstruct deve ser melhor na maioria dos casos, pois não queremos mexer na inicialização do Spring Bean.
Lwpro2
4
@ lwpro2 O que você quer dizer com "não quero estragar a inicialização do spring bean" aqui?
Yngve Sneen Lindal
@Mercer Traieste, o que devo dar para o atributo class aqui? Posso dar a classe de controlador aqui?
precisa saber é o seguinte
314

Para expandir a sugestão @PostConstruct em outras respostas, essa é realmente a melhor solução, na minha opinião.

  • Ele mantém seu código dissociado da API Spring (@PostConstruct está em javax. *)
  • Anota explicitamente seu método init como algo que precisa ser chamado para inicializar o bean
  • Você não precisa se lembrar de adicionar o atributo init-method à sua definição de bean spring, o spring chamará automaticamente o método (assumindo que você registre a opção annotation-config em outro lugar do contexto).
skaffman
fonte
9
Obrigado, isso funciona. Observação: Se você deseja usar com o Primavera você deve incluir "<context: anotação-config />" para registrar o feijão CommonAnnotationBeanPostProcessor (como mencionado acima)
khylo
2
Um adequado <context:component-scan>também funciona e pode ser útil para reduzir o tempo de inicialização, se você tiver grandes bibliotecas não Spring no caminho de classe.
Donal Fellows
5
O JavaDoc para PostConstruct diz que apenas um método pode ser anotado por classe: docs.oracle.com/javaee/5/api/javax/annotation/…
Andrew Swan
O @PostConstruct não funciona com um gerenciador de transações, consulte: forum.spring.io/forum/spring-projects/data/…
mmm
2
@PostConstruct também não será de muita utilidade para você quando o feijão estiver instanciar não é uma classe de sua própria, mas alguns terceira classe partido
John Rix
102

Existem três abordagens diferentes a serem consideradas, conforme descrito na referência

Use o atributo init-method

Prós:

  • Não requer bean para implementar uma interface.

Contras:

  • Nenhuma indicação imediata desse método é necessária após a construção para garantir que o bean esteja configurado corretamente.

Implementar InitializingBean

Prós:

  • Não há necessidade de especificar o método init ou ativar o processamento de digitalização / anotação de componentes.
  • Apropriado para beans fornecidos com uma biblioteca, em que não queremos que o aplicativo que usa esta biblioteca se preocupe com o ciclo de vida do bean.

Contras:

  • Mais invasivo do que a abordagem do método init.

Use a anotação do estilo de vida JSR-250 @PostConstruct

Prós:

  • Útil ao usar a varredura de componentes para detectar automaticamente os beans.
  • Deixa claro que um método específico deve ser usado para inicialização. A intenção está mais próxima do código.

Contras:

  • A inicialização não é mais especificada centralmente na configuração.
  • Lembre-se de ativar o processamento de anotações (que às vezes pode ser esquecido)
kit de ferramentas
fonte
4
Eu acho que é realmente bom usá- @PostConstructlo precisamente porque faz parte da classe que ele precisa do método que chama no final do processamento de inicialização.
Donal Fellows
Se essa classe realmente precisa dela e você não pode fazê-lo no construtor, considero que é um cheiro de código.
user482745
39

Você já tentou implementar InitializingBean? Parece exatamente o que você procura.

A desvantagem é que seu bean torna-se compatível com o Spring, mas na maioria dos aplicativos isso não é tão ruim.

Jon Skeet
fonte
2
Existe um motivo para você optar por implementar a interface em vez de especificar um método init no XML?
6789 Mark
4
Isso é uma questão de gosto. A interface faz parte do modelo de componente Spring e serve a esse propósito, e somente para um método nomeado personalizado, pode não ser realmente óbvio que ele precisa ser chamado para concluir o ciclo de vida do componente. Portanto, isso serve principalmente à comunicação. Obviamente, com a desvantagem da dependência introduzida no framework Spring. Uma boa maneira no meio é o uso de @PostConstruct, já que tem a semântica claras, mas não introduz a dependência ...
Oliver Drotbohm
7
Oliver me dá algumas desculpas legais, mas na verdade eu tinha acabado de esquecer o método init :) Uma outra razão é que o próprio tipo sabe que precisa ser "finalizado" depois que todas as propriedades foram definidas - não é fundamentalmente algo que deve estar na configuração.
9139 Jon Skeet
8

Você pode implantar um BeanPostProcessor personalizado no contexto do aplicativo para fazê-lo. Ou, se você não se importa em implementar uma interface Spring no seu bean, pode usar a interface InitializingBean ou a diretiva "init-method" (mesmo link).

Rob H
fonte
Alguém tem detalhes sobre como escrever um BeanPostProcessor. Parece ser exatamente o que eu preciso. Cheers :)
peakit
Navios de primavera com muitos exemplos. Basta olhar para a API JavaDoc para BeanPostProcessor e você encontrará links para muitas classes de implementação. Então olhe o código fonte para eles.
Rob H
-7

Para esclarecer ainda mais qualquer confusão sobre as duas abordagens, ou seja, o uso de

  1. @PostConstruct e
  2. init-method="init"

Por experiência pessoal, percebi que o uso de (1) funciona apenas em um contêiner de servlet, enquanto (2) funciona em qualquer ambiente, mesmo em aplicativos de desktop. Portanto, se você usasse o Spring em um aplicativo independente, teria que usar (2) para realizar isso ", chame esse método após a inicialização.

Ayorinde
fonte
4
Tecnicamente, @PostConstruct(quando usado em um aplicativo baseado no Spring) está vinculado à vida útil do contexto do Spring. Tais contextos podem ser usados ​​em todos os tipos de aplicativos.
Donal Fellows
Esse era o comportamento que eu esperava, mas não funcionou para mim.
Ayorinde