Panduan Untuk Menjalankan Logika pada Startup di Musim Semi

1. Perkenalan

Pada artikel ini kita akan fokus pada bagaimana menjalankan logika saat memulai aplikasi Spring .

2. Menjalankan Logika pada Startup

Menjalankan logika selama / setelah startup aplikasi Spring adalah skenario yang umum, tapi yang menyebabkan banyak masalah.

Untuk mendapatkan keuntungan dari Inverse of Control, secara alami kita perlu melepaskan kontrol parsial atas aliran aplikasi ke container - itulah mengapa instantiation, mengatur logika saat startup, dll membutuhkan perhatian khusus.

Kita tidak bisa begitu saja memasukkan logika kita dalam konstruktor kacang atau metode panggilan setelah pembuatan instance objek apa pun; kita tidak memegang kendali selama proses tersebut.

Mari kita lihat contoh kehidupan nyata:

@Component public class InvalidInitExampleBean { @Autowired private Environment env; public InvalidInitExampleBean() { env.getActiveProfiles(); } }

Di sini, kami mencoba mengakses bidang autowired di konstruktor. Ketika konstruktor dipanggil, kacang Spring belum diinisialisasi sepenuhnya. Hal ini bermasalah karena memanggil tidak ladang belum diinisialisasi tentu saja akan menghasilkan NullPointerException s .

Spring memberi kita beberapa cara untuk mengelola situasi ini.

2.1. The @PostConstruct Anotasi

Anotasi @PostConstruct Javax dapat digunakan untuk membuat anotasi metode yang harus dijalankan satu kali segera setelah inisialisasi kacang . Perlu diingat bahwa metode beranotasi akan dijalankan oleh Spring meskipun tidak ada yang perlu diinjeksi.

Inilah @PostConstruct dalam aksi:

@Component public class PostConstructExampleBean { private static final Logger LOG = Logger.getLogger(PostConstructExampleBean.class); @Autowired private Environment environment; @PostConstruct public void init() { LOG.info(Arrays.asList(environment.getDefaultProfiles())); } }

Pada contoh di atas, Anda dapat melihat bahwa instance Environment dimasukkan dengan aman dan kemudian dipanggil dalam metode beranotasi @PostConstruct tanpa memunculkan NullPointerException .

2.2. The InitializingBean Antarmuka

The InitializingBean pendekatan bekerja cukup sama dengan yang sebelumnya. Alih-alih membuat anotasi metode, Anda perlu mengimplementasikan antarmuka InitializingBean dan metode afterPropertiesSet () .

Di sini Anda dapat melihat contoh sebelumnya yang diimplementasikan menggunakan antarmuka InitializingBean :

@Component public class InitializingBeanExampleBean implements InitializingBean { private static final Logger LOG = Logger.getLogger(InitializingBeanExampleBean.class); @Autowired private Environment environment; @Override public void afterPropertiesSet() throws Exception { LOG.info(Arrays.asList(environment.getDefaultProfiles())); } }

2.3. sebuah ApplicationListener

Pendekatan ini dapat digunakan untuk menjalankan logika setelah konteks Spring diinisialisasi , jadi kami tidak berfokus pada bean tertentu, tetapi menunggu semuanya untuk diinisialisasi.

Untuk mencapai ini, Anda perlu membuat kacang yang mengimplementasikan antarmuka ApplicationListener :

@Component public class StartupApplicationListenerExample implements ApplicationListener { private static final Logger LOG = Logger.getLogger(StartupApplicationListenerExample.class); public static int counter; @Override public void onApplicationEvent(ContextRefreshedEvent event) { LOG.info("Increment counter"); counter++; } } 

Hasil yang sama dapat dicapai dengan menggunakan anotasi @EventListener yang baru diperkenalkan :

@Component public class EventListenerExampleBean { private static final Logger LOG = Logger.getLogger(EventListenerExampleBean.class); public static int counter; @EventListener public void onApplicationEvent(ContextRefreshedEvent event) { LOG.info("Increment counter"); counter++; } }

Dalam contoh ini kami memilih ContextRefreshedEvent. Pastikan untuk memilih acara yang sesuai dengan kebutuhan Anda.

2.4. The @Bean Initmethod Atribut

The initMethod properti dapat digunakan untuk melaksanakan metode setelah inisialisasi kacang ini.

Seperti inilah kacang itu:

public class InitMethodExampleBean { private static final Logger LOG = Logger.getLogger(InitMethodExampleBean.class); @Autowired private Environment environment; public void init() { LOG.info(Arrays.asList(environment.getDefaultProfiles())); } }

Anda dapat melihat bahwa tidak ada antarmuka khusus yang diterapkan atau penjelasan khusus yang digunakan.

Kemudian, kita dapat mendefinisikan kacang menggunakan anotasi @Bean :

@Bean(initMethod="init") public InitMethodExampleBean initMethodExampleBean() { return new InitMethodExampleBean(); }

Dan beginilah tampilan definisi kacang dalam konfigurasi XML:

2.5. Injeksi Konstruktor

Jika Anda memasukkan kolom menggunakan Constructor Injection, Anda cukup memasukkan logika Anda ke dalam konstruktor:

@Component public class LogicInConstructorExampleBean { private static final Logger LOG = Logger.getLogger(LogicInConstructorExampleBean.class); private final Environment environment; @Autowired public LogicInConstructorExampleBean(Environment environment) { this.environment = environment; LOG.info(Arrays.asList(environment.getDefaultProfiles())); } }

2.6. Spring Boot CommandLineRunner

Spring boot menyediakan antarmuka CommandLineRunner dengan metode callback run () yang bisa dipanggil saat aplikasi mulai setelah konteks aplikasi Spring dibuat.

Mari kita lihat contohnya:

@Component public class CommandLineAppStartupRunner implements CommandLineRunner { private static final Logger LOG = LoggerFactory.getLogger(CommandLineAppStartupRunner.class); public static int counter; @Override public void run(String...args) throws Exception { LOG.info("Increment counter"); counter++; } }

Catatan : Seperti disebutkan dalam dokumentasi, beberapa CommandLineRunner kacang dapat didefinisikan dalam konteks aplikasi yang sama dan dapat dipesan menggunakan @Ordered interface atau @Order penjelasan.

2.7. Aplikasi Spring BootRunner

Mirip dengan CommandLineRunner, Spring boot juga menyediakan antarmuka ApplicationRunner dengan metode run () yang akan dipanggil saat startup aplikasi. Namun, alih-alih argumen String mentah yang diteruskan ke metode callback, kami memiliki instance kelas ApplicationArguments .

The ApplicationArguments interface has methods to get argument values that are options and plain argument values. An argument that is prefixed with – – is an option argument.

Let's look at an example:

@Component public class AppStartupRunner implements ApplicationRunner { private static final Logger LOG = LoggerFactory.getLogger(AppStartupRunner.class); public static int counter; @Override public void run(ApplicationArguments args) throws Exception { LOG.info("Application started with option names : {}", args.getOptionNames()); LOG.info("Increment counter"); counter++; } }

3. Combining Mechanisms

In order to achieve full control over your beans, you might want to combine the above mechanisms together.

The order of execution is as follows:

  1. The constructor
  2. the @PostConstruct annotated methods
  3. the InitializingBean's afterPropertiesSet() method
  4. the initialization method specified as init-method in XML

Let's create a Spring bean that combines all mechanisms:

@Component @Scope(value = "prototype") public class AllStrategiesExampleBean implements InitializingBean { private static final Logger LOG = Logger.getLogger(AllStrategiesExampleBean.class); public AllStrategiesExampleBean() { LOG.info("Constructor"); } @Override public void afterPropertiesSet() throws Exception { LOG.info("InitializingBean"); } @PostConstruct public void postConstruct() { LOG.info("PostConstruct"); } public void init() { LOG.info("init-method"); } }

If you try to instantiate this bean, you will be able to see logs that match the order specified above:

[main] INFO o.b.startup.AllStrategiesExampleBean - Constructor [main] INFO o.b.startup.AllStrategiesExampleBean - PostConstruct [main] INFO o.b.startup.AllStrategiesExampleBean - InitializingBean [main] INFO o.b.startup.AllStrategiesExampleBean - init-method

4. Conclusion

Dalam artikel ini kami mengilustrasikan berbagai cara menjalankan logika pada startup aplikasi Spring.

Contoh kode dapat ditemukan di GitHub.