Is #Configuration a singleton - java

I was doing my daily staff and I've realized despite I use #Configuration oftenly I don't know how it works exactly, after reading the spring.io documentations I can't tell for sure if #Configuration is a way of making a class a singleton.
So.... I guess my question is:
What should I use to proper make a singleton #Configuration or #Component? and why's that'?
I've been investigating about this 2 options with 2 examples like this:
1st example
#Configuration
public static class Config {
#Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
#Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
2nd example
#Component
public static class Config {
#Bean
public SimpleBean simpleBean() {
return new SimpleBean();
}
#Bean
public SimpleBeanConsumer simpleBeanConsumer() {
return new SimpleBeanConsumer(simpleBean());
}
}
The first piece of code works fine, and as expected, SimpleBeanConsumer will get a link to singleton SimpleBean. But unfortunately, it doesn’t work in a signed enviroment.
The second configuration is totally incorrect because spring will create a singleton bean of SimpleBean, but SimpleBeanConsumer will obtain another instance of SimpleBean which is out of the spring context control.
The reason for this behaviour can be explained as follows:
If you use #Configuration, all methods marked as #Bean will be wrapped into a CGLIB wrapper which works as if it’s the first call of this method, then the original method’s body will be executed and the resulting object will be registered in the spring context. All further calls just return the bean retrieved from the context.
So I guess I've answered my own question but not sure if I'm missing something.

Related

Spring profile annotation multiple beans

Let's say I have a library (I cannot change it). There is a class Consumer that uses a spring component of class A.
#Component
public class Consumer{
#Autowired
private A a;
}
In my configuration class I want to define two beans of same class A depending on the profile.
#Configuration
public class Config {
#Bean
#Profile("!dev")
A a1(){
return new A();
}
#Bean
#Profile("dev")
A a2(){
return new A();
}
}
But when I start the app, I get next exception
Parameter 1 of constructor in sample.Consumer required a single bean, but 2 were found:
I can't get how to fix that. I've tried to create 2 separate configs for that with profile annotation and single bean there, but it also did not work.
Marking one bean #Primary also does not help.
Do you guys know how to fix that? Thanks!
UPD.
Let me make it more specific. That class is a part of dynamodb spring starter. Consumer - DynamoDBMapperFactory. My bean - DynamoDBMapperConfig. So I want to have 2 versions of DynamoDBMapperConfig in my app.
You need to stop scanning package where Consumer declared.
#Profile behaves differently if it's applied to the #Bean annotated method.
From Profile doc.:
Use distinct Java method names pointing to the same bean name if you'd like to define alternative beans with different profile conditions
This means, you should do:
#Configuration
public class Config {
#Bean("a")
#Profile("!dev")
A a1(){
return new A();
}
#Bean("a")
#Profile("dev")
A a2(){
return new A();
}
}
Note the same bean names.

Cannot Inject Service in HandlerInterceptorAdapter, Getting NullPointerException

I have a service-client project which is in normal spring application , not spring boot .its used for mainly logging related things.which contains Interceptor , loggingservice impl class and some model classes for logging. I have added this module as a dependency to main application in pom.xml.and i was able to inject and use the loggingService beans within the service layers of the main application.
Am getting NullPointerException while auto-wiring loggingService within the interceptor .The bean is not available within the interceptor.but like i said it can be injected and used within the main application.
Also am not able to read properties using #Value within the interceptor.
This is my Interceptor class .
#Component
public class LoggingInterceptor extends HandlerInterceptorAdapter {
#Autowired
LoggingService loggingService;
#Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object object) throws Exception {
loggingService.info("Am in prehandle");
return true;
}
}
This is my configuration class where i register the interceptor with the main application
#Component
public class LoggingConfig implements WebMvcConfigurer {
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(getLoginInterceptor());
}
#Bean
public LoggingInterceptor getLoginInterceptor() {
return new LoggingInterceptor();
}
}
My question is almost similar to this post Cannot Autowire Service in HandlerInterceptorAdapter , but its different like am referring the interceptor from another module , and like they suggested i tried to create the bean from the application.
But the issues am facing right now is
getting NullPointerException while injecting loggingService within interceptor, but its working in main application
#Value annotation also return null, not able to read from properties
You have 2 possible solutions.
Mark your LoggingConfig as #Configuration instead of #Copmponent
Inject the LoggingInterceptor instead of referencing the #Bean method
Option 1: LoggingConfig as #Configuration
Your LoggingConfig is marked as an #Component whereas it should be marked as an #Configuration. The difference is that whilst it is allowed to have an #Bean method on an #Component it operates in a so-called lite mode. Meaning you cannot use method references to get the instance of a bean (this is due to no special proxy being created). This will lead to just a new instance of the LoggingInterceptor being created but it isn't a bean.
So in short what you are doing is equivalent to registry.addInterceptor(new LoggingInterceptor()); which just creates an instance without Spring knowing about it.
When marking the LoggingConfig as an #Configuration a special proxy will be created which will make the LoggingInterceptor a proper singleton bean, due to the method call being intercepted. This will register the bean in Spring and you will be able call the method.
NOTE: You actually endup with 2 instances of the LoggingInterceptor one due to the #Component on it the other through the #Bean. Remove the #Component.
Option 2: Inject the LoggingInterceptor.
As your LoggingInterceptor is marked as an #Component Spring will already create an instance (you actually have 2 instances of it created in your current setup). This instance you can inject into your LoggingConfig.
#Component
public class LoggingConfig implements WebMvcConfigurer {
private LoggingInterceptor loggingInterceptor;
#Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(loggingInterceptor);
}
}
With this you can remove the #Bean method as you will get the proper one injected into your LoggingConfig class. The class can also remain an #Component in this case. Although I would recommend using #Configuration as to also properly stereotype it.
NOTE: If you are on a recent Spring version you can use #Configuration(proxyBeanMethods=false). This will make a lite-configuration (just like an #Component) but it is still marked properly as a configuration class.

Spring Boot: #TestConfiguration Not Overriding Bean During Integration Test

I have a Bean defined in a class decorated with #Configuration:
#Configuration
public class MyBeanConfig {
#Bean
public String configPath() {
return "../production/environment/path";
}
}
I have a class decorated with #TestConfiguration that should override this Bean:
#TestConfiguration
public class MyTestConfiguration {
#Bean
#Primary
public String configPath() {
return "/test/environment/path";
}
}
The configPath bean is used to set the path to an external file containing a registration code that must be read during startup. It is used in an #Component class:
#Component
public class MyParsingComponent {
private String CONFIG_PATH;
#Autowired
public void setCONFIG_PATH(String configPath) {
this.CONFIG_PATH = configPath;
}
}
While trying to debug this I set a breakpoint inside each method as well as the constructor of the test config class. The #TestConfiguration's constructor breakpoint is hit, so i know that my test configuration class instantiates, however the configPath method of that class is never hit. Instead, the configPath method of the normal #Configuration class is hit and the #Autowired String in MyParsingComponent is always ../production/environment/path rather than the expected /test/environment/path.
Not sure why this is happening. Any thoughts would be greatly appreciated.
As documented in the Detecting Test Configuration section of the Spring Boot reference manual, any beans configured in a top-level class annotated with #TestConfiguration will not be picked up via component scanning. So you have to explicitly register your #TestConfiguration class.
You can do that either via #Import(MyTestConfiguration.class) or #ContextConfiguration(classes = MyTestConfiguration.class) on your test class.
On the other hand, if your class annotated with #TestConfiguration were a static nested class within your test class, it would be registered automatically.
Make sure that the method name of your #Bean factory method does not match any existing bean name. I had issues with method names like config() or (in my case)
prometheusConfig() which collided with existing bean names. Spring skips those factory methods silently and simply does not call them / does not instantiate the beans.
If you want to override a bean definition in your test, use the bean name explicitly as string parameter in your #Bean("beanName") annotation.
Test configuration has to be explicitly imported in the test via #Import({MyTestConfiguration.class}).
The name of the #Bean methods in #Configuration and #TestConfiguration have to be different. At least it makes difference in Spring Boot v2.2.
Also make sure spring.main.allow-bean-definition-overriding=true otherwise the bean could not be overriden.
For me worked this code:
#TestConfiguration // 1. necessary
public class TestMessagesConfig {
#Bean
#Primary // 2. necessary
public MessageSource testMessageSource() { // 3. different method name than in production code e.g. add test prefix
}
}
I struggled with a related problem, whereby even though I was using an inner static class, my test bean was not being registered.
It turns out, You still need to add your inner static class to the #ContextConfiguration class array, otherwise the beans inside the #TestConfiguration doesn't get picked up.
public interface Foo {
String execute();
}
public class FooService {
private final Foo foo;
FooService(Foo foo) {
this.foo = foo;
}
public String execute() {
return foo.execute();
}
}
#ExtendWith(SpringExtension.class)
#ContextConfiguration(classes = {FooService.class, FooTest.FooTestConfig.class})
public class FooTest {
#Autowired
FooService fooService;
#Test
void test() {
Assertions.assertEquals("MY_TEST_BEAN", fooService.execute());
}
#TestConfiguration
static class FooTestConfig {
#Bean
public Foo getFooBean() {
return () -> "MY_TEST_BEAN";
}
}
}
I came across a similar issue recently and got it sorted out by annotating my testing bean with #Primary as well as #Bean. Not sure why it's required, which seems not documented in the Spring doc. The version of my SpringBoot is 2.0.3.
In my case it was an issue with #RunWith(SpringRunner.class), I'm not exactly sure why it wasn't working, I was following this - Testing in Spring Boot
But after replacing that with #ExtendWith(SpringExtension.class) the inner static #TestConfiguration class created the beans as expected.
Maybe a version mismatch - I'm using Spring Boot 2.7.2.
In my case replacing #Import(TestConfig.class) with #ContextConfiguration(classes=TestConfig.class) did the trick. For some reason, some of the beans from TestConfig but 1 wasn't until I replaced #Import with #ContextConfiguration.
This was also mentioned in some comments that were hidden because they had no upvotes.
I found it odd how several answers stated that the names of the #Beans have to be different from each other. How would that make one override the other?
There wasn't one specific answer that worked for me, but I've solved the issue by combining some of their advices.
Here's what worked for me.
Main configuration class:
#Configuration
public class SpringConfiguration {
#Bean
BeanInterface myBean() {
return new BeanImplementation();
}
#Bean
OtherClass otherBean() {
return new OtherClass();
}
}
Test configuration class:
#TestConfiguration
public class TestSpringConfiguration {
#Bean
#Primary
BeanInterface myBean() {
return new TestBeanImplementation();
}
}
Test class:
#SpringBootTest(classes = TestSpringConfiguration.class,
properties = "spring.main.allow-bean-definition-overriding=true")
public class Tests {
#Test
public void test() {
// do stuff
}
}
In this way, the "myBean" bean instance is the one defined in the TestSpringConfiguration class, while "otherBean" is the one defined in the SpringConfiguration class, since it's not overridden.
If I gave two different names to the "myBean" beans, the "real" one would still be initialized and, in my case, would give an error during tests, since it needs something that's only available at runtime in its proper environment.
Once I gave both the same name, Spring would throw an error saying that they were conflicting. Hence why I had to specify the property spring.main.allow-bean-definition-overriding=true in the #SpringBootTest annotation of the test class.
By the way, if you're NOT using Spring Boot, I guess these alternative annotations could work for you:
#ExtendWith(value = SpringExtension.class)
#ContextConfiguration(loader = AnnotationConfigContextLoader.class, // <- not sure about this one
classes = { SpringConfiguration.class, TestSpringConfiguration.class })
public class Tests {
#Test
public void test() {
// do stuff
}
}
Then, you would still have to set the property spring.main.allow-bean-definition-overriding=true in the test application.yml or application.properties file, or in some other way via code on startup.
Note: I'm not 100% sure that you would need the loader = AnnotationConfigContextLoader.class thing. Try without it, first. I needed it in a project of mine which had Spring without Boot, but I can't remember whether it's a standard thing to set or I needed it for some specific reason.

Why do I not need #Autowired on #Bean methods in a Spring configuration class?

Why does this work:
#Configuration
public class MyConfig {
#Bean
public A getA() {
return new A();
}
#Bean // <-- Shouldn't I need #Autowired here?
public B getB(A a) {
return new B(a);
}
}
Thanks!
#Autowire lets you inject beans from context to "outside world" where outside world is your application.
Since with #Configuration classes you are within "context world ", there is no need to explicitly autowire (lookup bean from context).
Think of analogy like when accessing method from a given instance. While you are within the instance scope there is no need to write this to access instance method, but outside world would have to use instance reference.
Edit
When you write #Configuration class, you are specifying meta data for beans which will be created by IOC.
#Autowire annotation on the other hand lets you inject initialized beans, not meta-data, in application. So, there is no need for explicit injection because you are not working with Beans when inside Configuration class.
Hi Jan your question is marked as answered over 4 years ago but I've found a better source:
https://www.logicbig.com/tutorials/spring-framework/spring-core/javaconfig-methods-inter-dependency.html
here's another article with the same idea:
https://dzone.com/articles/spring-configuration-and, it also states that such usage is not well documented which I found true. (?)
so basically if beanA's initialization depends on beanB, spring will wire them without explicit #Autowired annotation as long as you declare these two beans in the application context (i.e. #Configuartion class).
A class with #Configuration annotation is where you're defining your beans for the context. But a spring bean should define its own dependencies. Four your case B class should be defining it's own dependencies in class definition. For example if your B class depends on your A class than it should be like below:
public class B
{
#Autowired
A aInstance;
public A getA()
{
return aInstance;
}
public void setA(A a)
{
this.aInstance = a;
}
}
In above case while spring is building its context it looks for the bean which's type is A which is also defined as a Bean at your configuration class and Autowires it to B at runtime so that B can use it when required.

Why in Spring I am not allowed to annotate a final class with #Configuration?

I am studying for the Spring Core certification and I have some doubts related to the answer of this question founded on the study material stuff.
Why are you not allowed to annotate a final class with #Configuration
My reasoning is the following one for substantiate this assertion:
Consider the following configuration class:
#Bean
public AccountRepository accountRepository() {
return new JdbcAccountRepository();
}
#Bean
public TransferService transferService() {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(accountRepository());
return service;
}
#Bean
public AccountService accountService() {
return new AccountServiceImpl(accountRepository());
}
At first look this situation could appear strange because the first method (accountRepository()) instantiates an JdbcAccountRepository object as a bean having id=AccountRepository that, following the Spring default behavior, is a singleton
The second and the third method call twice more time the accountRepository() method that should instantiate twice more JdbcAccountRepository objects and this is not possibile because it is singleton !!!
So, to solve this situation Spring use the Inheritance-based Proxies strategy that expect to create a child class of my configuration class (the one annoted by #Configuration) and it is does:
For each bean, an instance is cached in the child class
Child class only calls super at first instantiation
So the child class is the entry point because the following behavior is implemented by this child class:
public class AppConfig$$EnhancerByCGLIB$ extends AppConfig {
public AccountRepository accountRepository() {
// if bean is in the applicationContext
// return bean
// else call super.accountRepository() and store bean in context
}
public TransferService transferService() {
// if bean is in the applicationContext, return bean
// else call super.transferService() and store bean in context
}
.....................................................
.....................................................
.....................................................
}
So if I annotate a configuration class with final Spring can't have this behavior because in Java a final class cannot be subclassed
Is it correct?
Using the same reasoning can I also assert that in Spring I can't have a final method annoted with #Bean annotation?
Because, as shown in the previous example, I have that when at startup time is created the child class (the proxy) of my configuration class happens that for each bean, an instance is cached in the child class and if it is final it is not possible (but I am absolutly not sure about this assertion)
Am I missing something? Can you give me the exact explaination?
Tnx
Spring creates dynamic proxies for classes annotated with #Configuration classes. Spring uses CGLIB to extend your class to create proxy. Hence, configuration classes cannot be final.
Regarding accountRepository() being invoked twice:
If you invoke accountRepository() method to create an instance, it is no more a Spring managed bean. Spring will not have any idea of the instances created in this manner. Hence, you will end up with multiple instances of JdbcAccountRepository
You can preserve the singleton behavior if you configure as below:
#Bean
public TransferService transferService(JdbcAccountRepository jdbcAcctRepo) {
TransferServiceImpl service = new TransferServiceImpl();
service.setAccountRepository(jdbcAcctRepo);
return service;
}
#Bean
public AccountService accountService(JdbcAccountRepository jdbcAcctRepo) {
return new AccountServiceImpl(jdbcAcctRepo);
}

Categories

Resources