Adding auto-configuration support

When starting a Spring Boot application with @AcrossApplication all auto-configuration classes detected will be considered. If Across is unsure about what to do with them, you should see the AutoConfiguration Report printed in the logs:

 --- Across AutoConfiguration Report ---
 The following 2 auto-configuration classes have unknown Across support and were not added:
 - org.springframework.boot.autoconfigure.admin.SpringApplicationAdminJmxAutoConfiguration
 - org.springframework.boot.autoconfigure.aop.AopAutoConfiguration
 Consider adding them to a META-INF/across.configuration.
 --- End Across AutoConfiguration Report ---

This gives you an indication of which classes require a compatibility adapter if you want to use them. Across will skip these auto-configuration classes but will continue bootstrapping. If you add a compatible configuration in the right way the warning will disappear, see META-INF/across.configuration.

There is a difference between a not-supported auto-configuration class, and one with unknown support. The latter should print out the warning in the AutoConfiguration report, the former should be present in an across.configuration so the warning disappears.

Auto-configuration problems

The most common problems to solve have to do with where to put the actual auto-configuration class and which components to expose.

  • if it only provides components for direct use by other modules (eg. components from the modules want to inject them)

    • leave the configuration on application level or move it to a module starting before the modules wishing to use those components

    • when moving to a module, expose the components that other modules want to inject

    • IMPORTANT: if your configuration uses Spring conditionals depending on components defined inside other modules, it can never remain on the application level as those conditions would never match

  • if it only uses components provided by other modules

    • expose those components in the other modules

    • if it does not work when injecting on application level, consider moving to one of the last modules (eg. the AcrossContextPostProcessorModule

      • this depends on how the components it needs are looked for, if it does not look up the parent ApplicationContext it would still not detect exposed beans on the application level

  • if it does more than one of the above cases

    • you will need to create a custom configuration class

Some auto-configuration classes need to setup infrastructure in more than one module. In that case you will also need a custom configuration class that injects the required code in the relevant modules (usually all of them in a case like this).

AcrossContextInfrastructureModule

Every Across context contains a placeholder module called AcrossContextInfrastructureModule. It usually starts as the very first module. It can be used as an extension point to move configuration classes to that need to be available for all other modules.

If no configuration has been added to the module, it will be skipped and not bootstrap.

AcrossContextPostProcessorModule

Every Across context contains a placeholder module called AcrossContextPostProcessorModule. It usually starts as the very last module, after the application module. It can be used to move configuration classes to that need to rely on components defined by all other modules.

If no configuration has been added to the module, it will be skipped and not bootstrap.

META-INF/across.configuration

The across.configuration file allows you to move auto-configuration, exposed additional beans and provide alternative configuration classes. Every JAR file can contain a single across.configuration and all data from them will be merged together.

As only Across interprets these files, existing libraries can add them to support both Across- and non-Across-based application. The across.configuration should always be located in the META-INF folder in the root of your package.

A across.configuration is a properties file supporting 3 property keys that can have comma-separated values:

com.foreach.across.Exposed

List of class names for components that should always be exposed by every module. Class name can be specific or abstract class, interface or annotation. In case of an annotation, any component with that annotation will be exposed.

com.foreach.across.AutoConfigurationDisabled

List of configuration classes that should be rejected when requested through Spring Boot auto-configuration. You will only be able to add these configuration classes directly to your application.

com.foreach.across.AutoConfigurationEnabled

List of configuration classes that are allowed when requested through Spring Boot auto-configuration.

The com.foreach.across.AutoConfigurationEnabled values support multiple options:

  • If only the class name is given, the configuration will be added to the application level as is the default Spring Boot behaviour.

  • A replacement class can be specified using : after the class name. In this case the replacement class will be added to the application level instead of the original class. This is useful for providing an AcrossBootstrapConfigurer.

  • A module name can be specified using after the class name. In this case the configuration will not be added to the application level but to the module specified. You can use DynamicApplicationModule as a placeholder name to indicate the configuration should be added to the application module.

    com.foreach.across.IllegalConfiguration

    List of class names that are not allowed to be present in a module or context. These will be validated during startup and if one of these is present, the application will not start up and throw an error.

The com.foreach.across.IllegalConfiguration values support multiple options:

  • If only a class name is given, the configuration may not be used in the AcrossContext, which is the root context of the application. This means that the configuration is not allowed on the level of the *Application class.

  • A module name can be specified using after the class name. This means that the configuration is not allowed for the specified module(s). It is also possible to make a configuration illegal in all modules or in the across application context.

    • If the module name is equal to AcrossContext, beans of the provided type name may not be present in the across application context.

    • If the module name is equal to AcrossModule, beans of the provided type may not be present in ANY module

    • If the module name is prefixed by an exclamation mark ( ! ), it is allowed in that specific module.

    • Multiple module names can be specified using a pipe ( | ). As an example, org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport→AcrossContext|AcrossModule|!MyModule, means that the configuration may not be used in the across context or in any module, except for MyModule. By default as soon as a module has been specified, the specified type may not be used in any module except those specified. So the former example is per se equal to org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport→!MyModule,

    • The illegal configuration can be suffixed by a colon ( : ) followed by a message key. This key can then be used to specify more information about why beans of that type are not allowed, as well as the action(s) that should be taken. This is done through the use of the following entries in the across.configuration file:

      • com.foreach.across.IllegalConfiguration[MESSAGE_KEY].description= Why this is an illegal configuration

      • com.foreach.across.IllegalConfiguration[MESSAGE_KEY].action= A possible resolution or steps to take

Example META-INF/across.configuration
#
# Lists the classes (or annotations) of components that should always be exposed
#
com.foreach.across.Exposed=\
  org.springframework.stereotype.Service
#
# List of AutoConfiguration classes that should never be allowed.
# Once a class has been added here, it can only ever be added manually to the application.
#
com.foreach.across.AutoConfigurationDisabled=\
  my.IncompatibleAutoConfiguration
#
#
# List of AutoConfiguration classes that are supported on the application level, these will be allowed unless disabled.
# Optionally an adapter class name or a module target can be specified.
#
com.foreach.across.AutoConfigurationEnabled=\
  my.CompatibleAutoConfiguration,\
  my.ReplacedIncompatibleAutoConfiguration:my.AcrossAnotherIncompatibleAutoConfigurationAdapter,\
  my.ApplicationModuleInjectedAutoConfiguration->DynamicApplicationModule,\
  my.PostProcessorModuleInjectedAutoConfiguration->AcrossContextPostProcessorModule

#
# List of AutoConfiguration classes or bean types that are not allowed to be present (in the specified modules).
#
com.foreach.across.IllegalConfiguration=\
  my.SimpleConfiguration->AcrossContext:mydescriptionlabel
  my.SomeBean->!AcrossContextPostProcessorModule

#
# List of illegal configuration descriptions.
#
com.foreach.across.IllegalConfiguration[mydescriptionlabel].description=This configuration is not allowed to be present on the AcrossContext.
com.foreach.across.IllegalConfiguration[mydescriptionlabel].action=Remove this configuration on the AcrossApplication level.
Some auto-configuration classes use the AutoConfigurationPackage for scanning components. In an Across application, only the package of the application module is automatically registered as an AutoConfigurationPackage. In a regular Spring Boot application, it would be the package that contains the @SpringBootApplication class.

AcrossBootstrapConfigurer