How do I start a Spring Boot Web Application without using ComponentScan - java

I am trying to avoid component scanning to reduce start up time in our module tests, and in our web app in general.
When I replace #SpringBootApplication with #SpringBootConfiguration #EnableAutoConfiguration, I get the following error:
Unable to start EmbeddedWebApplicationContext due to missing EmbeddedServletContainerFactory bean
Can I manually import the EmbeddedServletContainerFactory somehow?

My suggestion is to first run your application with the debug flag on and write down all the activated auto-configurations. Then, disable auto-configuration and import those configurations by using #Import on your application class.
Alternatively, you can look at each of those configuration classes and see what Spring Boot configures for you and decide if you want to provide your own configurations instead - you can just mimic the auto-configuration classes and everything should work the same way.

Miloš and Pieter provided the means to find the answer. A minimal Spring Boot Web Application can be started with the following:
#SpringBootConfiguration
#Import({EmbeddedServletContainerAutoConfiguration.class})
public class Application extends SpringBootServletInitializer {
...
}
ServerPropertiesAutoConfiguration.class might also be handy to pick up things like port number for the application.

Related

Spring boot configuration issues with sonar

'ABCService' is not reachable by #ComponentsScan or #SpringBootApplication. Either move it to a package configured in #ComponentsScan or update your #ComponentsScan configuration.
This the error message I get in 9 critical bugs in Sonarqube analysis, one for each Service and Controller.
Though #Autowire and dependency injection is working fine but still Sonar seems to be complaining.
The rule in question causing the issue is:
Spring beans should be considered by "#ComponentScan"
Spring beans belonging to packages that are not included in a
#ComponentScan configuration will not be accessible in the Spring
Application Context. Therefore, it's likely to be a configuration
mistake that will be detected by this rule. Note: the #ComponentScan
is implicit in the #SpringBootApplication annotation, case in which
Spring Boot will auto scan for components in the package containing
the Spring Boot main class and its sub-packages.
Since #SpringBootApplication is has component scan which scans main class package and all it's sub packages as well this issue shouldn't come.
This is a SonarQube bug, it doesn't handle SpringBootApplication properly. You should report it here : https://community.sonarsource.com/c/bug
To quote from Rules from Sonar,
#ComponentScan is used to determine which Spring Beans are available
in the application context. The packages to scan can be configured
thanks to the basePackageClasses or basePackages (or its alias value)
parameters. If neither parameter is configured, #ComponentScan will
consider only the package of the class annotated with it. When
#ComponentScan is used on a class belonging to the default package,
the entire classpath will be scanned.
This will slow-down the start-up of the application and it is likely
the application will fail to start with an
BeanDefinitionStoreException because you ended up scanning the Spring
Framework package itself.
Find below the link and tehy have also mentioned how to write compliant code.
https://rules.sonarsource.com/java/RSPEC-4602

Autowired service null in AspectJ aspect on a Spring Boot / Swing standalone app

I currently have a Swing application running on Spring Boot, launched with the following code :
SpringApplication application = new SpringApplication(Something.class);
application.setWebApplicationType(WebApplicationType.NONE);
application.run(args);
I have enabled the java agents for aspectjweaver and spring-instrument and enabled load-time weaving since i need to target private methods. My aspect is for logging so i need to autowire a logging service that writes entries to a log table in the database. The aspect class is annotated with #Aspect and #Component. I am trying to autowire the service with the #Autowired annotation but the value is null when any pointcut executes. I assume this has to do with some sort of other mechanism than the Spring context instantiating these aspects but i cannot figure out how to correctly autowire my required service. I tried implementing the ApplicationContextAware interface but it did not work either.
Does anyone have experience with autowiring services into AspectJ aspects on a Swing application? I have another project that runs on Spring Boot and Spring MVC and this works out of the box.
Thanks
My issue turned out to be partly multi-threading related but what I was mostly missing was this :
#Bean
public MessagingLogger messagingLogger(LogEntryService logEntryService)
{
MessagingLogger aspect = Aspects.aspectOf(MessagingLogger.class);
aspect.setLogEntryService(logEntryService);
return aspect;
}
This is how I was able to "inject" my service into my aspect. The second part of my issue turned out to be that i wasn't careful enough in my multi-threading setup (lots of background processes in this app) and i was trying to use the aspect while Spring wasn't even done creating all the services.

Adding a conditional external PropertySource in a spring boot application

I'm currently using an EnvironmentPostProcessor to add my external PropertySource, the code looks like this :
public class ExternalPropertySourceEnvironmentPostProcessor implements EnvironmentPostProcessor
{
private static final String EXTERNAL_PROPERTY_SOURCE_NAME = "ExternalPropertySource";
#Override
public void postProcessEnvironment(ConfigurableEnvironment environment, SpringApplication application)
{
if (environment.acceptsProfiles(Profiles.EXTERNAL_PROPERTY_SOURCE_ENABLED_PROFILE)) {
environment.getPropertySources()
.addLast(new ExternalPropertySource(EXTERNAL_PROPERTY_SOURCE_NAME, new ExternalSource()));
}
}
}
A spring.factories is also used to register this EnvironmentPostProcessor.
This code actually works if the profile is set in the vm environment variables, but if it is added in src/main/resources/application.yml, the profile doesn't seem to be injected yet in the environment and is not returned by the environment.getActiveProfiles(). I've tried using the interface Ordered with the lowest precedence, but it doesn't help.
To add a bit of context around what I'm trying to achieve, this class is in a small library that adds an external property source like a database. Then we can use it in some other spring boot applications. Something like Spring Cloud Config does.
I'd like a clean way to enable or disable this property source depending on the environment where the code runs. I don't mind using something else then profiles or even another way to inject the property source, I just want something clean that doesn't depend on several factors to work.
The main problem in my code right now is that I'm using spring boot's property sources to make my own property source configurable.
UPDATE : I used a Spring Cloud app to debug this, and was confusing the bootstrap context with the normal spring boot context. See my answer below.
Further investigation made me figure out the problem appeared only with a Spring Cloud application.
In fact the breakpoint I had in this code was triggered twice, once after the bootstrap context initialization and once after the spring boot context initialization. I was only debugging the profiles in the first occurence. At that point, only the bootstrap.yml properties are loaded and not the ones from the application.yml file. The second occurence obviously had the profiles from my application.yml file.
My code worked as expected with a vanilla Spring Boot application. As the documentation states :
The Environment has already been prepared with all the usual property
sources that Spring Boot loads by default.
I was confused by the behaviour of my app which seemed to be different from that statement, but it was Spring Cloud's bootstrap that was messing with my debugging.
Since I need a PropertySource that has the highest precedence, I need to add it in the post bootstrap initialization for Spring Cloud apps. I used an init flag on my EnvironmentPostProcessor so it doesn't get executed twice and used the bootstrap.yml on Spring Cloud apps to set the profile.
TL;DR :
With Spring Cloud, an EnvironmentPostProcessor gets called twice: once after the bootstrap init and once after the normal Spring Boot context init. If you need injected properties and are targeting the Spring Cloud's post bootstrap initialization, use the bootstrap.yml instead of application.yml.

Importing spring boot jar into another app without #ComponentScan and Xml Configurations

I'm looking for a generic/clean solution to import a spring boot jar application into another spring boot application without doing #ComponentScan(package name of the application), without the xml configuration.
If I didn't say #Componentscan in the base application, #Autowired is not working, which is quite understandable.
So in general writing libraries with spring boot is not a ideal way?
Finally, I went with #Import(ApplicationConfiguration)which I find it quite neat.
I had a multi-level project structure so on each of the sub-module created a configuration file which initiate the required beans and then in the parent module, I have used #Import.

Spring interceptors using #configuration

I'v mostly used XML based configuration for applicationContexts. I have a requirement where I need to use #configuration to create my beans using #Bean now.
Brief description of why ?
weblogic deploys a spring web-app "A". A makes calls to B(not spring,not web app-no WEB_INF). B just contains common service calls to external servers. Hence B.jar is bundled into A and A is then deployed on web-logic.
Now i need to use spring beans in B.)
So the options available at this point:
Bundle applicationContext.xml and all the property files into B.jar. (keep in mind it is a very complex build process with 20 property files and 100s of beans. So I also need to register propertymanager bean etc..). Then initialize appcontext in a static initializer block and look for appcontext within B.jar.
Use #configuration to register an Appconfig.class instead of an XML. (no changes to build process here).
With this option i need to use a clientInterceptor. Could you provide me with the #Bean definition of this.
How do I configure clientInterceptor in #appconfig.class.
*please let me know if there any other options.
Spring-ws-core - 2.1.4.release
spring-core-3.2.4
expression,context,beans - 3.0.5
spring-oxm-1.0.3
weblogic - 12c
jdk - 1.7
This is my first post here. Any suggestions would be welcome and appreciated. Apologize for any forum faux paus.

Categories

Resources