Enabling Non-Spring Libraries to Access Spring Boot Components: Difference between revisions

From NovaOrdis Knowledge Base
Jump to navigation Jump to search
Line 55: Line 55:
}
}
</syntaxhighlight>
</syntaxhighlight>
Finally, the non-spring dependency should explicitly pull the component it needs from the application context, with getBean(). That will trigger bean initialization and will kick off necessary dependency injection.
<syntaxhighlight lang='java'>
public class Dependency {
  private DependencySpringComponentA springComponent;
  public Dependency() {
    configureAccessToSpringComponent();
  }
  public void run() {
    System.out.println(this + " is running with Spring component " + springComponent);;
  }
/**
  * Use this method in the constructor to explicitly pull the bean from the context.
  *
  * @throws IllegalStateException if we encounter bad state because the initialization was not performed.
  */
private void configureAccessToSpringComponent() throws IllegalStateException {
  if (SpringApplicationContextAccess.APPLICATION_CONTEXT == null) {
    throw new IllegalStateException("access to Spring ApplicationContext has not been configured");
  }
  springComponent = SpringApplicationContextAccess.APPLICATION_CONTEXT.getBean(DependencySpringComponentA.class);
  if (springComponent == null) {
      throw new IllegalStateException(
            "a component of type " + DependencySpringComponentA.class + " not found in application context");
  }
}
}
</syntaxhighlight>
Obviously, DependencySpringComponentA must exist and be a valid Spring component.

Revision as of 18:13, 2 November 2018

Internal

Overview

This article describes a possible approach to give non-Spring libraries access to Spring Boot runtime components.

Playground Example

https://github.com/ovidiuf/playground/tree/master/spring/spring-boot/spring-boot-with-dependency

Approach

The Spring Boot runtime should implement a Spring component whose job is to configure a dedicated class in the dependency package. This solution assumes that the dependency package "cooperates" and we can write code in it. The dedicated class in the dependency package is conventionally named SpringApplicationContextAccess:

package playground.springboot.dependency;

import org.springframework.context.ApplicationContext;

public class SpringApplicationContextAccess {

    public static ApplicationContext APPLICATION_CONTEXT;

}

Note that the dependency project should be configured with "compile only" access to Spring Framework API packages "org.springframework:spring-beans" and "org.springframework:spring-context". A way to do this that does not involve Spring Boot dependency management is described here: Spring dependency-management Plugin for Gradle.

The Spring Boot runtime is supposed to configured SpringApplicationContextAccess for the dependency, via a SpringApplicationContextConfiguratorForDependencies component., early in its life cycle. The simplest way to do this is when the component is initialized so it has access to the application context:

@Component
public class SpringApplicationContextConfiguratorForDependencies {

  @Autowired
  public SpringApplicationContextConfiguratorForDependencies(ApplicationContext applicationContext) {

     SpringApplicationContextAccess.APPLICATION_CONTEXT = applicationContext;
  }
}

The SpringApplicationContextConfiguratorForDependencies component should be autowired into the Spring Boot application to trigger configuration.

@SpringBootApplication
public class MainApplication  {

    @Autowired
    private SpringApplicationContextConfiguratorForDependencies springBootstrap;

   ...
}

Finally, the non-spring dependency should explicitly pull the component it needs from the application context, with getBean(). That will trigger bean initialization and will kick off necessary dependency injection.

public class Dependency {

  private DependencySpringComponentA springComponent;

  public Dependency() {

    configureAccessToSpringComponent();
  }

  public void run() {

    System.out.println(this + " is running with Spring component " + springComponent);;
  }

 /**
   * Use this method in the constructor to explicitly pull the bean from the context.
   *
   * @throws IllegalStateException if we encounter bad state because the initialization was not performed.
   */
 private void configureAccessToSpringComponent() throws IllegalStateException {

  if (SpringApplicationContextAccess.APPLICATION_CONTEXT == null) {

     throw new IllegalStateException("access to Spring ApplicationContext has not been configured");
  }

  springComponent = SpringApplicationContextAccess.APPLICATION_CONTEXT.getBean(DependencySpringComponentA.class);

  if (springComponent == null) {

       throw new IllegalStateException(
             "a component of type " + DependencySpringComponentA.class + " not found in application context");
   }
 }
}

Obviously, DependencySpringComponentA must exist and be a valid Spring component.