Panduan Menjalankan Logik pada Permulaan pada Musim Bunga

1. Pengenalan

Dalam artikel ini kita akan memfokuskan cara menjalankan logik pada permulaan aplikasi Spring .

2. Menjalankan Logik pada Permulaan

Menjalankan logik semasa / selepas permulaan aplikasi Spring adalah senario yang biasa, tetapi yang menyebabkan banyak masalah.

Untuk mendapat keuntungan dari Inverse of Control, kita semestinya harus melepaskan kawalan separa ke atas aliran aplikasi ke wadah - itulah sebabnya instansiasi, logik persediaan semasa memulakan, dan lain-lain memerlukan perhatian khusus.

Kita tidak boleh memasukkan logik kita dalam kaedah pembuatan kacang atau kaedah panggilan setelah menunjukkan objek; kita tidak terkawal semasa proses tersebut.

Mari lihat contoh kehidupan sebenar:

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

Di sini, kami cuba mengakses medan autowired di konstruktor. Apabila pembina dipanggil, kacang Spring belum dimulakan sepenuhnya. Ini bermasalah kerana panggilan yang belum diinisialkan lapangan tentu akan menghasilkan NullPointerException s .

Spring memberi kita beberapa cara untuk menguruskan keadaan ini.

2.1. The @PostConstruct Anotasi

Javax ini @PostConstruct anotasi boleh digunakan untuk menganotasi satu kaedah yang perlu dijalankan sekali selepas pengawalan kacang ini . Perlu diingat bahawa kaedah anotasi akan dilaksanakan oleh Spring walaupun tidak ada yang perlu disuntik.

Inilah @PostConstruct dalam tindakan:

@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())); } }

Dalam contoh di atas anda dapat melihat bahawa contoh Lingkungan disuntik dengan selamat dan kemudian dipanggil dalam kaedah anotasi @PostConstruct tanpa membuang NullPointerException .

2.2. The InitializingBean Interface

The InitializingBean pendekatan berfungsi dengan sama dengan yang sebelumnya. Daripada menganotasi kaedah, anda perlu melaksanakan antara muka InitializingBean dan kaedah afterPropertiesSet () .

Di sini anda dapat melihat contoh sebelumnya yang dilaksanakan menggunakan antara muka 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. An ApplicationListener

Pendekatan ini dapat digunakan untuk menjalankan logika setelah konteks Musim Semi diinisialisasi , jadi kami tidak memfokuskan pada kacang tertentu, tetapi menunggu semuanya dimulai.

Untuk mencapai ini, anda perlu membuat kacang yang menggunakan antara muka 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 memilih acara yang sesuai dengan keperluan anda.

2.4. The @Bean Initmethod Atribut

The initMethod harta boleh digunakan untuk melaksanakan kaedah yang selepas pengawalan kacang ini.

Inilah rupa kacang:

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 bahawa tidak ada antara muka khas yang dilaksanakan atau anotasi khas yang digunakan.

Kemudian, kita dapat menentukan kacang menggunakan anotasi @Bean :

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

Dan ini adalah bagaimana definisi kacang kelihatan dalam konfigurasi XML:

2.5. Suntikan Pembina

Sekiranya anda menyuntik medan menggunakan Constructor Injection, anda boleh memasukkan logik anda 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 antara muka CommandLineRunner dengan kaedah callback run () yang boleh dipanggil semasa permulaan aplikasi setelah konteks aplikasi Spring dibuat.

Mari lihat contoh:

@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 yang disebutkan dalam dokumentasi, beberapa biji CommandLineRunner dapat ditentukan dalam konteks aplikasi yang sama dan boleh dipesan menggunakan antarmuka @Ordered atau anotasi @Order .

2.7. Aplikasi Spring BootRunner

Mirip dengan CommandLineRunner, boot Spring juga menyediakan antara muka ApplicationRunner dengan kaedah run () yang akan digunakan semasa permulaan aplikasi. Namun, daripada argumen String mentah yang diteruskan ke kaedah panggilan balik, kami mempunyai contoh 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 menggambarkan banyak cara melaksanakan logik pada permulaan aplikasi Spring.

Contoh kod boleh didapati di GitHub.