Why does Spring Autowire fail when I move #SpringBootApplication? - java

I'm completely new to Spring/Spring Boot so I need some help. I didn't notice any documentation that indicated that the #SpringBootApplication or #ComponentScan had to be in a particular spot:
Working folder structures
Not working

I suppose your Application class is a typical Spring Boot Application like following:
#SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
SpringBootApplication is just a composed annotation of:
// Others
#Configuration
#EnableAutoConfiguration
#ComponentScan
public #interface SpringBootApplication { .. }
That ComponentScan with no explicit base package, would use the package of Application class as its base package for scanning. So, when you put this class in your root package, any annotated class in root package and under it would be scanned by the component scanner and your app would successfully work.
But when you move your Application into app package, that very same component scanner wouldn't scan those beans in hello package and Spring would fail to wire some beans together.
Spring Boot does not require any specific code layout to work, however, there are some best practices that help. You can read about those best practices in Spring Boot Documentation.

Related

How can I use a rest controller from a different package in Spring?

What's going on
I am using Java, Springboot
I am trying to create a simple API.
I have a package called Example.
I have two sub-packages called config and rest.
In config is the class Application, which is my spring app.
In rest is the class TheController which is the rest controller
Currently when i run the app, Application and try and go to one of the get mappings i get a white label error page.
However if i move theController to the config package i do not get this error and it's plain sailing.
What I have tried
I have tried using an import statement.
com.Example.rest.* and com.Example.rest.TheControllerwith no results.
Any help would be appreciated :)
Add a #ComponentScan on your application class.
package com.example.config;
#SpringBootApplication
#ComponentScan(basePackages = "com.example")
public class SpringBootComponentScanApp {
}
I personally think it's a good idea to put your configuration in a sub-package "com.example.config" and not in the parent package "com.example", but you need to override Spring Boot's default component scan for that case.
See also https://www.baeldung.com/spring-component-scanning
Spring Boot will only scan for components (controllers, services, repositories, ...) starting from the package of the application class (annotated with #SpringBootApplication) and below.
So best to use com.example.Application, then you can use com.example.rest.TheController and things should work.

Disable DataSourceAutoConfiguration Spring boot

I have a library that makes use of spring-jdbc, the library contains common utility methods that need to be standardized across multiple projects.
The library when used in other spring boot application causes the project to fail with no bean on type DataSourceConfuguration Exception.
I have read tips to exclude DataSourceConfiguration on #SpringBootApplication but that would mean making change on every application that uses the library regardless of whether the application needs a datasource or not.
#Configuration
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}
The other option is to exclude DataSourceConfiguration in spring.factories of the library itself, but then it would stop the autoconfig ability of any application using the library and will have to manually define DataSource.
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
Is there a possible way to make this situation work for the library and any other project that wants to use the library but doesn't have to define a datasource and still function like a normal Spring Boot Application ?
The below is from Spring Documentation
import org.springframework.boot.autoconfigure.*;
import org.springframework.boot.autoconfigure.jdbc.*;
import org.springframework.context.annotation.*;
#Configuration
#EnableAutoConfiguration(exclude={DataSourceAutoConfiguration.class})
public class MyConfiguration {
}
https://docs.spring.io/spring-boot/docs/1.3.8.RELEASE/reference/html/using-boot-auto-configuration.html

How to prevent spring boot from auto creating instance of bean 'entityManagerFactory' at startup?

I am working on a Spring boot application that uses Spring JPA with PostgreSQL. I am using #SpringBootTest(classes = <my package>.Application.class) to initialize my unit test for a controller class.
The problem is that this is causing the entityManagerFactory bean (and many other objects related to jpa, datasource, jdbc, etc.) to be created which is not needed for unit tests. Is there a way to prevent Spring from automatically creating these objects till they are actually used the first time?
I spent a lot of time trying to load up only the beans I need for my unit test but ran into many errors. I am relatively new to Spring and I am hoping someone else has run into this before...and can help. I can post code snippets if needed.
Update: I am not sure if I should edit or answer my own question...choosing to edit since I ended up changing my approach to unit tests. I added this to my test config class.
#Configuration
#ComponentScan(basePackages = {"api.controller", "api.config", "api.utils"})
public class TestControllerConfig {
}
and I mocked out the service and repository classes.
You can disable auto configuration in spring-boot using exclude attribute of #EnableAutoConfiguration, as follows:
#Configuration
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, HibernateJpaAutoConfiguration.class})
public class TestConfig {
}
From #EnableAutoConfiguration documentation:
If the class is not on the classpath, you can use the excludeName attribute of the annotation and specify the fully qualified name instead. Finally, you can also control the list of auto-configuration classes to exclude via the spring.autoconfigure.exclude property.

How are the components scanned in spring boot

How does spring boot take care of component scan? We do not specify <component-scan> tag in spring boot in some web.xml file. We do not write any dispatcher servlet in spring boot. So where does spring boot do a component scan and how does it register all the controllers, services? What is the entry point for the spring boot web services micro-service? Note: Since it is a web-project I may not want to use the main method here.
There is an implicit one for the same package and sub-packages if you take a look at the annotation:
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Inherited
#Configuration
#EnableAutoConfiguration
#ComponentScan
public #interface SpringBootApplication {...
Of course, it will be executed after the run method:
public static void main(String[] args) {
SpringApplication.run(Main.class, args);
}
The question was: we do not specify component-scan and this is not true. It is declared in the Spring Boot annotation.
Edit 1: Spring MVC alternative
However, <component-scan> is a Spring annotation not just Spring Boot. You could configure your WAR web app with Spring MVC and you will not need Spring Boot libraries at all. Take a look at: http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#mvc-config-customize
#Configuration
#EnableWebMvc
public class ConfigWebMVC extends WebMvcConfigurerAdapter
{
...
}
Additionally, for better understanding of #ComponentScan I would like to highlight some points of the documentation:
About bean lifecycle:
By default, ApplicationContext implementations eagerly create and
configure all singleton beans as part of the initialization process..
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-factory-lazy-init
About Component scanning:
By default, classes annotated with #Component, #Repository, #Service,
#Controller, or a custom annotation that itself is annotated with
#Component are the only detected candidate components. However, you
can modify and extend this behavior simply by applying custom filters.
Add them as includeFilters or excludeFilters parameters of the
#ComponentScan annotation (or as include-filter or exclude-filter
sub-elements of the component-scan element)
http://docs.spring.io/spring/docs/current/spring-framework-reference/htmlsingle/#beans-scanning-filters

Spring Boot : Integration Test not excluding my Application configuration class

I have an application which connects to a zookeeper to perform operations on HBase. However, for Integration Tests, I have a class to create in-memory tables, and perform tests without trying to connect to said zookeeper.
I have defined a IntegrationTestAppConfig.class as follows:
#EnableAutoConfiguration(exclude = { AppConfig.class})
#ComponentScan
#Configuration
#EnableAsync
public class IntegrationTestAppConfig{
..... //this is where I create a bean for my HBaseConnectionManager to use my in-memory table environment
}
And, in my integration test class, I have the following:
#RunWith(SpringJUnit4ClassRunner.class)
#SpringApplicationConfiguration(classes = IntegrationTestAppConfig.class)
public class AHCLIManagerIT {
#Test
.....
}
Based on what I've read from the Spring-boot documentation, the integration test class should use IntegrationTestAppConfig.class for the application configuration.
However, when I run the Integration Test, I get an error saying connection to zookeeper timed out. In the stack trace, I see that the error occurred in AppConfig.java (my main class for app configuration), where it tries to create a HBaseConnection to the zookeeper.
I don't understand why my application is not using the App config class that I've defined in the annotations.
Is your AopConfig class actually an autoconfiguration class? Autoconfiguration classes are loaded by naming them in a spring.factories file in META-INF. The exclude attribute would only apply to those I believe. Auto configuration happens after regular app configuration anyways.
Also you have #ComponentScan on your config. If you really need to exclude AopConfig that would be the annotation I'd expect it to be on.
Though IMHO something doesn't seem right for doing a component scan in your tests

Categories