Як викликати метод після завершення ініціалізації боба?


237

У мене є випадок використання, коли мені потрібно викликати (нестатичний) метод лише в один раз при завантаженні ApplicationContext. Чи добре, якщо для цього я використовую MethodInvokingFactoryBean? Або у нас є якесь краще рішення?

Як бічну примітку, я використовую ConfigContextLoaderListener для завантаження контексту програми у веб-програму. І хочете, що якщо bean 'A' створений лише один раз, виклик methodA () один раз.

Як це можна зробити красиво?

Відповіді:


196

Ви можете використовувати щось на кшталт:

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

Це призведе до виклику методу "init", коли квасоля є екземпляром.


15
postConstruct має бути кращим у більшості випадків, хоча ми не хочемо псуватися з ініціалізацією весняних бобів.
lwpro2

4
@ lwpro2 Що ви маєте на увазі під "тут не хочуть псуватися з ініціалізацією весняних бобів"?
Yngve Sneen Lindal

@Mercer Traieste, що мені тут слід вказати для атрибута класу? Чи можу я дати клас контролера тут?
KJEjava48

314

Для розширення пропозиції @PostConstruct на інші відповіді, на мою думку, це дійсно найкраще рішення.

  • Він зберігає ваш код, від'єднаний від Spring API (@PostConstruct знаходиться в javax. *)
  • Він чітко коментує ваш метод init як щось, що потрібно викликати для ініціалізації бобів
  • Вам не потрібно пам’ятати, щоб додати атрибут методу init до вашого визначення весняних бобів, весна автоматично викличе метод (якщо припустимо, ви зареєструєте параметр-конфігурація анотацій де-небудь ще в контексті).

9
Дякую, це працює. Зауважте, якщо ви хочете використовувати Spring, ви повинні включити "<контекст: annotation-config />", щоб зареєструвати боб CommonAnnotationBeanPostProcessor (як згадувалося вище)
khylo

2
Підходящий <context:component-scan>також працює, і може бути корисним для скорочення часу запуску, якщо у вас на класі є великі бібліотеки, які не є Spring.
стипендіати

5
У JavaDoc для PostConstruct йдеться про те, що лише один метод може бути анотований до нього для кожного класу: docs.oracle.com/javaee/5/api/javax/annotation/…
Ендрю Лебедь

@PostConstruct не працює з менеджером транзакцій, див .: forum.spring.io/forum/spring-projects/data/…
mmm

2
@PostConstruct також не принесе вам великої користі, коли боб, який ви призначаєте, - це не власний клас, а якийсь третій клас
Джон Рікс,

102

Існує три різні підходи до розгляду, як описано в посиланні

Використовуйте атрибут init-method

Плюси:

  • Не потребує bean для реалізації інтерфейсу.

Мінуси:

  • Ніяких негайних вказівок цей спосіб не потрібен після побудови, щоб забезпечити правильність налаштування бобів.

Впровадити InitializingBean

Плюси:

  • Не потрібно вказувати метод init або вмикати обробку сканування / анотації компонентів.
  • Підходить для бобів, що постачаються з бібліотекою, де ми не хочемо, щоб програма, що використовує цю бібліотеку, стосувалася життєвого циклу квасолі.

Мінуси:

  • Більш інвазивний, ніж метод init.

Використовуйте анотацію життєвого циклу JSR-250 @PostConstruct

Плюси:

  • Корисно під час використання компонентного сканування для автоматичного виявлення бобів.
  • Пояснює, що для ініціалізації слід використовувати конкретний метод. Намір ближче до коду.

Мінуси:

  • Ініціалізація більше не вказується центрально в конфігурації.
  • Ви повинні пам'ятати, щоб увімкнути обробку анотацій (яку іноді можна забути)

4
Я думаю, що насправді корисно використовувати @PostConstructсаме те, що саме тому класу потрібен метод виклику в кінці обробки ініціалізації.
стипендіати

Якщо цей клас дійсно потрібен, і ви не можете це зробити в конструкторі, то я вважаю це запахом коду.
user482745

39

Ви спробували реалізувати InitializingBean? Це звучить як саме те, що ти шукаєш.

Мінус полягає в тому, що ваша квасоля стає весною, але в більшості застосувань це не так вже й погано.


2
Чи є причина, по якій ви б обрали реалізацію інтерфейсу над зазначенням методу init у XML?
Марк

4
Це питання смаку. Інтерфейс є частиною моделі компонентів Spring і служить цій цілі лише тому, що для методу, призначеного на замовлення, може бути не очевидно, що його потрібно викликати для завершення життєвого циклу компонентів. Тож це служить переважно спілкуванню. Звичайно, з недоліком введеної залежності до весняних рамок. Приємним способом між ними є використання @PostConstruct, оскільки вона має чітку семантику, але не вводить залежність ...
Олівер Дротбом

7
Олівер дає мені приємні виправдання, але насправді я просто забув про метод init :) Ще одна причина полягає в тому, що сам тип знає, що його потрібно "закінчити" після того, як всі властивості були встановлені - це не принципово те, що має бути в конфігурації.
Джон Скіт

8

Ви можете розгорнути спеціальний BeanPostProcessor в контексті програми, щоб це зробити. Або якщо ви не заперечуєте над тим, щоб реалізувати інтерфейс Spring у своєму файлі, ви можете використовувати інтерфейс InitializingBean або директиву "метод init" (те саме посилання)


Хто-небудь має деталі, як написати BeanPostProcessor. Це звучить як саме те, що мені потрібно. Ура :)
пік

Весняні кораблі з багатьма прикладами. Просто подивіться API JavaDoc для BeanPostProcessor, і ви знайдете посилання на багато класів реалізації. Потім подивіться на вихідний код для них.
Роб H

-7

Для подальшого очищення будь-якої плутанини щодо двох підходів, тобто використання

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

З особистого досвіду я зрозумів, що використання (1) працює лише в контейнері сервлетів, тоді як (2) працює в будь-якому середовищі, навіть у настільних додатках. Отже, якщо ви використовували б Spring в автономному додатку, вам доведеться використовувати (2) для виконання цього "виклику цього методу після ініціалізації.


4
Технічно @PostConstruct(при використанні у додатку на основі Spring) прив’язаний до тривалості життєвого контексту Spring. Такі контексти можуть використовуватися у всіляких додатках.
стипендіати

Таку поведінку я очікував, але не працював для мене.
Айорінде
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.