Spring - excluding a bean being scanned by a parent class' configuration - java

In Spring, is there a way to exclude a bean that is being scanned by some configuration in a parent class?
I have the following scenario:
#Configuration
#ComponentScan("com.foo")
public class Config {}
#ContextConfiguration(classes = Config.class)
public abstract class A {}
public class B extends A {}
The Config class is causing some bean com.foo.X to be scanned, but I want to exclude it in the context of class B.
In my specific scenario, A and B are test classes. I want my test class B to be able to extend A, and thus inherit the Config spring configuration, but I want to be able to exclude some specific classes from being scanned. Is this possible using Spring, or will I have to remove the #Component annotation from the classes I want to exclude?
I have tried attempting to override the configuration and using #ComponentScan(excludeFilters=...) but that did not work.

Related

Failing to import external jar containing bean

I'm a little new t working with Spring so any help provided would be great.
I have a SpringApplication class (annotated with #SpringBootApplication. In another class (within the same project), it contains a ServiceClass class. When the class is in the same project, it runs as expected.
When the ServiceClass is moved to an external jar, I get the following error.
Description:
Field service in
package-to-class.Comp required a
bean of type 'package-to-class.ServiceClass'
that could not be found.
The injection point has the following annotations:
#org.springframework.beans.factory.annotation.Autowired(required=true)
Action:
Consider defining a bean of type
'package-to-class.ServiceClass' in your
configuration.
I am trying to find what I need to do to inject (#AutoWired) into my project with the above error.
By default, Spring Boot's component scanning only looks in the same package as the #SpringBootApplication and its descendants.
The approach I would suggest is using #Import to import specific beans from outside the project, or use #ComponentScan to import all beans from a package in another project.
#SpringBootApplication
#Import(ServiceClass.class)
public class SpringApplication {
// ...
}
or
#SpringBootApplication
#ComponentScan(basePackages = "com.example.mylibrary")
public class SpringApplication {
// ...
}
Okey some basic things, you have mixed up your packages a bit.
#SpringBootApplication will scan all classes in packages below the class this is annotated on. This annotation is an alias for #EnableAutoConfiguration, #Configuration and #ComponentScan means that #ComponentScan(basePackages = {"com.springdi.example"}, basePackageClasses = DependencyBasePackageClass.class) is not needed.
com.springdi.example // class with #SpringBootApplication annotation
|
|
|
com.springdi.example.* // Will find all #Service, #Component, #Configuration
// in subpackages below the #SpringBootApplication
// annotation
You can read more about the annotation here SpringBootApplication
Since your other annotated classes are NOT in the same package structure as the #SpringBootApplication you need to define all the places you want to scan for annotations.
#SpringBootApplication(scanBasePackages = {"com.springdi.example", "com.dependency.example"})
will probably include all the packages that you want to scan through.

SpringBootApplication scanBasePackages is not reading subpackages

I have a common library published on nexus that has package id
x.xx.common
it contains sub packages of common feign clients proxy interfaces
The project that uses this library has package id.
x.xx.account
x.xx.device
each of these projects has its application class in the root
x.xx.account.AppClass
x.xx.device.AppClass
each of these class has
#SpringBootApplication(scanBasePackages = {"x.xx"})
for some reason both projects don't see any of the proxy interfaces under subpackages
x.xx.common.proxy
x.xx.common.configuration
I tried moved the proxy interfaces directly under main package
x.xx.common
but it also failed
Parameter 0 of constructor in x.xx.common.service.impl.AuditServiceImpl required a bean of type 'x.xx.common.LogProxy' that could not be found.
that error is given for every interface proxy
Add annotation to your sub packages class which you want to be scanned. Add the annotations like #Component, #Service or #Repository respectively to the class respectively.
For the annotation:
#SpringBootApplication(scanBasePackages = {"x.xx"})
Suppose there is a class named Abc in the subpackage x.xx, so add the annotation #Component to the class.
#Component
class Abc{}
This will help to read the sub packages class.
To know more about the difference between the above mention annotations: What's the difference between #Component, #Repository & #Service annotations in Spring?
I have figured it out, apparently the AppClass #EnableFeignClients need to have the base class added to it as well.
So for anyone that has the same problem my AppClass now has the following annotation
#SpringBootApplication(scanBasePackages = {"x.xx"})
#EnableFeignClients(basePackages= {"x.xx"})
public class AppClass {
}

How to #Autowire services in SpringBoot

Good day, guys. I have a question about autowiring services into my classes when using Springboot. All of the examples I have seen on the Internet as well as in the Springboot specification do something of the like (taking an excerpt from the Springboot version 1.5.7 specification):
package com.example.service;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
#Service
public class DatabaseAccountService implements AccountService {
private final RiskAssessor riskAssessor;
#Autowired
public DatabaseAccountService(RiskAssessor riskAssessor) {
this.riskAssessor = riskAssessor;
}
// ...
}
This is a class that injects a property through its constructor, by means of #Autowiring the constructor. Another form is to #Autowire the property like this:
#Autowired
private final RiskAssessor riskAssessor
But, where I work, for these two methods to work, I have been told that I need to use this method:
applicationContext.getAutowireCapableBeanFactory().autowireBean(Object.class)
They have told me that I need this in order for the #Autowired annotation to work.
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly? (Something like #AutowiredClass). The above method is too verbose and hard to remember, so surely there must be a better way to make #Autowired work on classes in order to inject services, just like we do in Grails where we just say def someService and it is automatically injected.
If you want properly use #Autowired in your spring-boot application, you must do next steps:
Add #SpringBootApplicationto your main class
Add #Service or #Component annotation to class you want inject
Use one of two ways that you describe in question, to autowire
If you don't have any wiered package structure and the main class package includes all other classes you want spring to instantiate (directly or in the subpackages) a simple annotation #ComponentScan on your main class will help you save all those boiler plate code. Then spring will do the magic, it will go and scan the package(and subpackages) and look for classes annotated with #Service, #Component etc and instantiate it.
Even better, use #SpringBootApplication in your main class, this will cover #Configuration as well. If it is a green field project , I would encourage to start from start.spring.io - a template generation/scaffolding tool for spring
Now my question to you is: why is there no simple annotation that allows the #Autowire to function correctly?
There is: #SpringBootApplication
If you put this at the root of your application (file that contains the main class) and as long as your services are at the same package or a sub-package, Spring will auto-discover, instantiate, and inject the proper classes.
There's an example in this walk-through: REST Service with Spring Boot
As described in that page:
#SpringBootApplication is a convenience annotation that adds all of the following:
#Configuration tags the class as a source of bean definitions for the application context.
#EnableAutoConfiguration tells Spring Boot to start adding beans based on classpath settings, other beans, and various property settings.
#ComponentScan tells Spring to look for other components, configurations, and services in the hello package, allowing it to find the controllers.
You need to annotate the implementation of RestService as a #Service or #Component so Spring would pick it up.
#Service
public class MyRiskAssessorImpl implements RiskAssessor {
///
}
#Autowired almost works out of the box. Just do your component scanning of the class you want to autowire and you are done. Just make sure your main class (or main configuration class) uses #ComponentScan("{com.example.app}") or #SpringBootApplication (main class). The docs explain this stuff pretty good

Spring - detect dependencies not annotated with #Component

With Guice, getting an instance of A will automatically resolve B even if I have not defined anything about B.
public class A {
#Inject B b;
}
public class B {
...
}
However, Spring seems to require that components are marked with #Component or another stereotype.
I have some common libraries that need to work with different CDI implementations. How can I get Spring to automatically construct instances without annotating with #Component or defining every single class in my #Configuration?

#PropertySource on a bean not picked up by Spring in JavaConfig

I've got 2 different maven projects: project A and project B, where A is a maven dependency of B. Project A has a class annotated with #PropertySource:
#Component
#PropertySource({"classpath:spring-files/resource.properties"})
public class BeanAImpl implements BeanA{
#Value("#{\'${list.of.some.properties}\'.split(\',\')}")
private String someProperties;
}
In project B, I want to be able to define BeanAImpl. So I define it in my JavaConfig class of project B:
#Configuration
public class ProjectBConfig{
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#Bean
public BeanA beanA() {
return new BeanAImpl();
}
I get a BeanCreationException, since the injection of the List into "someProperties" has failed. If I add to my #Configuration class (in project B) a component scan annotation for BeanAImpl's package, then the context will load successfully. Also, if I add the #PropertySource declaration to the config class - then it's going to work. But it seems that simply defining beanA in the configuration, does not take into account its annotations. I also tried changing beanA from #Component to #Configuration, which did not help.
Is there a way for me to have BeanAImpl inject the value from the properties by simply defining it as a bean, without needing to add extra configuration? Why is this happening?
#PropertySource annotation should be on class annotated with #Configuration, something similar to this:
#Configuration
#PropertySource({"classpath:spring-files/resource.properties"})
public class ProjectBConfig{
Or you can create separate configuration class in project A.
See javadoc for details of #PropertySource annotation.

Categories