How to use multiple spring configuration files - java

I have a java spring configuration defined like so,
#Configuration
public class FirstConfiguration {
#Bean
FirstController firstController() {
return new FirstController(firstService());
}
#Bean
FirstService firstService() {
return new FirstServiceImpl(secondService());
}
}
Now the beans in this configuration depend on SecondConfiguration defined like so,
#Configuration
public class SecondConfiguration {
#Bean
SecondController SecondController() {
return new SecondController(SecondService());
}
#Bean
SecondService secondService() {
return new SecondServiceImpl();
}
}
How can I make use of the secondService() bean in my FirstConfiguration?

Since the SecondService is a bean, you could inject it into the firstService method to configure another bean:
#Bean
FirstService firstService(#Autowired SecondService secondService) {
return new FirstServiceImpl(secondService);
}

You can inject the firstService like this :
#Autowired
SecondService secondService

You can refer the method secondService() directly when you import the configuration.
#Configuration
#Import(SecondConfiguration.class)
public class FirstConfiguration {
#Bean
FirstController firstController() {
return new FirstController(firstService());
}
#Bean
SomeController someController() {
return new SomeController(secondService());
}
}
Refer the Spring config import

Related

spring boot boostrap bean override

In my spring.factories I have such a definition:
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
MyBootstrapConfiguration
In MyBootstrapConfiguration I have :
#Configuration
public class MyBootstrapConfiguration {
#Bean
#ConditionalOnMissingBean
public ApiClient apiClient() {
return someClient;
}
}
Now in my test (junit-5 and #SpringBootTest), I would like to override this bean. Notice the #ConditionalOnMissingBean... If I can hook somehow to a "before" my bootstrap is started, to provide that ApiClient, that method apiClient would obviously not be called and I would be happy.
Please notice that MyBootstrapConfiguration is not something I have control of - its an invariant to me. For non-bootstrap configuration this is easily doable, but is there a way to do this for bootstrap?
Given a test configuration class:
#Configuration
public class TestBootstrapConfiguration implements Ordered {
#Bean
public ApiClient testApiClient() {
return testApiClient;
}
#Override
public int getOrder() {
return Ordered.HIGHEST_PRECEDENCE;
}
}
In src/test/resources/META-INF/spring.factories
org.springframework.cloud.bootstrap.BootstrapConfiguration=\
TestBootstrapConfiguration

Spring inject a bean into another bean

I am trying to inject a bean into another bean that uses it. How can I do this?
public class MySpringConfig{
#Bean
public MyObject getMyObject() {
//.....
return MyObjectInstance;
}
#Bean
public SomeObject getSomeObject(MyObject myObject) {
//.....
return SomeObjectInstance;
}
}
I think you can do this with this way, this is working in my project.
#Configuration
public class AppConfig {
#Bean
public Bean1 foo(#Qualifier("bean2") Bean2 bean2) {
return new Bean1(bean2);
}
}
i think that might work!
#Configuration
public class AppConfig {
#Bean
public Bean2 bean2() {
return new Bean2();
}
#Bean
#DependsOn({"bean2"})
public Bean1 foo(#Autowired Bean2 bean2) {
return new Bean1(bean2); // or your can write new Bean1(bean2());
}
}
Parameters don't work exactly in the same way in #Bean and #Component.
For a class annotated with #Component, specifying them is required for the autowired constructor but in a #Bean declaration you don't need to provide a parameter to specify the MyObject dependency to use (while it will work) if that is accessible in the current class, which is your case.
So you want to inject directly the bean by invoking getMyObject() in the #Bean definition.
For example to pass it a constructor arg :
#Bean
public SomeObject getSomeObject() {
//....
// you injected MyObject in the current bean to create
SomeObject object = new SomeObject(getMyObject());
//...
return SomeObjectInstance;
}
And don't forget to annotate the class with #Configuration to make it considered by Spring.

Spring read values for #Bean class from properties file

I am trying to create Spring beans using only annotations. I am not able to load values for my #Bean class from properties file.
Here is my code:
This is my main class
public class AnnotationDI {
public static void main(String[] args) {
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigurationProvider.class);
ApplicationProperties properties = (ApplicationProperties)context.getBean(ApplicationProperties.class);
System.out.println(properties);
}}
Configuration class
#Configuration
public class ConfigurationProvider {
private ApplicationProperties m_applicationProperties;
#Bean
public ApplicationProperties getApplicationProperties() {
return new ApplicationProperties();
}
}
Bean class
#PropertySource(value = { "classpath:application.properties" })
public class ApplicationProperties {
#Value("${longThreadCount}")
private String m_longProcessThread;
#Value("${routeTimeout}")
private String m_routeTimeout;
#Value("${updateDirectoryPath}")
private String m_updateDirectoryPath;
public String getLongProcessThread() {
return m_longProcessThread;
}
#Override
public String toString() {
return "ApplicationProperties [m_longProcessThread=" +m_longProcessThread"]";
}
}
when i run this program, I get following output
m_longProcessThread=${longThreadCount}
Any idea what am i doing wrong?
To be able to have #Value with placeholders resolved you need to register a PropertySourcesPlaceholderConfigurer. As this is a BeanFactoryPostProcessor it needs to be registered as a static bean so that it can be detected early on in the process.
#Bean
public static PropertySourcesPlaceholderConfigurer placeholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
#PropertySource annotation has to be used in conjunction with #Configuration annotation like so,
#Configuration
#PropertySource(value = { "classpath:application.properties" })
public class ApplicationProperties {
...
}
Adding #Configuration annotation would solve the issue in this case.

Spring #Profile works on class, but not on #Bean

I'm unable to get #Profile to work on a #Bean, but it works fine on the #Configuration class. In my module tests I correctly get the MyServiceStub autowired in the first example, but not in the second.
Does anyone know why?
This works:
MyConfig.java
#Configuration
#Import({StubConfig.class, RealConfig.class}
public class MyConfig {}
StubConfig.java
#Profile({"featureTest", "moduleTest"})
#Configuration
public class StubConfig {
#Bean
public MyService myService() {
return new MyServiceStub();
}
}
RealConfig.java
#Profile({"!featureTest", "!moduleTest"})
#Configuration
public class RealConfig {
#Bean
public MyService myService() {
return new MyService();
}
}
But this doesn't work:
MyConfig.java
#Configuration
public class MyConfig {
#Bean
#Profile({"featureTest", "moduleTest"})
public MyService myServiceStub() {
return new MyServiceStub();
}
#Bean
#Profile({"!featureTest", "!moduleTest"})
public MyService myService() {
return new MyService();
}
}
Instead of using #Profile approach, you could try using the #Conditional to have conditional bean creation.
Or have an explicit if-stmt to check what is the activeProfile. And you can create the Bean instance depending on the activeProfile. This approach I think would mirror what could be done in Spring XML using their expression language. But the #Conditional seems better fit for you.

Using prototype beans defined in a different java-based Spring config file

Assume we have two spring config files: ConfigA.java and ConfigB.java.
Here's how ConfigA.java may look like:
#Configuration
class ConfigA {
#Scope("prototype")
#Bean public Foo fooPrototype() {
return new Foo(params);
}
}
And now I want to inject a few instances of Foo to a number of singleton-scoped beans declared in ConfigB.java:
#Configuration
#Import(ConfigA.class)
class ConfigB {
#Bean public Bar bar() {
return new Bar(*** how to inject Foo instance here? ***);
}
#Bean public Buzz buzz() {
return new Buzz(*** how to inject Foo instance here? ***);
}
}
If I had a single configuration file, I would simply replace the blocks enclosed in asterisks with fooPrototype().
But, how to inject different Foo instances to bar() and buzz() beans provided fooPrototype() is declared in a different configuration file?
This looks similar to the example in the Spring documentation ยง5.12.5 Composing Java-based configurations.
This same page gives a solution: You can autowire the configuration beans.
#Configuration
#Import(ConfigA.class)
class ConfigB {
#Autowired ConfigA configA;
#Bean public Bar bar() {
return new Bar(configA.fooPrototype());
}
#Bean public Buzz buzz() {
return new Buzz(configA.fooPrototype());
}
}
Can't you just pass fooPrototype as a method arg? E.g.:
#Bean public Bar bar(Foo fooPrototype) {
return new Bar(fooPrototype);
}
#Bean public Buzz buzz(Foo fooPrototype) {
return new Buzz(fooPrototype);
}

Categories