We can externalize properties using <context:property-placeholder> and we can override the Spring bean properties by configuring <context:property-override> as follows:
<context:property-placeholder location="classpath:application.properties"/>
<context:property-override location="classpath:override.properties"/>
I want to move my XML config to JavaConfig.
#Configuration
#ComponentScan
#PropertySource("classpath:application.properties")
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
But how to configure my override properties using Annotation?
PS:
I have a bean say MyBean as follows:
#Component
public class MyBean {
#Value("${someProp}")
private String someProp;
}
In my application.properties I have
someProp=TestValue
and in my override.properties i am overriding someProp value as
myBean.someProp=RealValue
No, It isn't.
But you could create a bean of type PropertyOverrideConfigurer in the configuration class whit the same result.
Update
For example:
#Bean public static PropertyOverrideConfigurer propertyOverrideConfigurer() {
PropertyOverrideConfigurer overrideConfigurer = new PropertyOverrideConfigurer();
overrideConfigurer.setLocation(new ClassPathResource("override.properties"));
return overrideConfigurer;
}
Note the static modifier, this is because BFPP should be instantiated early in the container lifecycle.
see http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/annotation/Bean.html for more info.
Related
I have two different beans for the same class with different configurations depending on the given profile.
#Bean
#Profile("!local")
public VaultPropertySource vaultPropertySource(ConfigurableApplicationContext context)
#Bean
#Profile("local")
public VaultPropertySource vaultPropertySourceLocal(ConfigurableApplicationContext context)
I have another bean that depends on VaultPropertySource instance.
#Component
#RequiredArgsConstructor
#DependsOn({"vaultPropertySource"})
public class VaultPropertyReader {
private final VaultPropertySource vaultPropertySource;
The problem is bean names are different and it only works on the first instance. How can I make it work on both profiles? Can I make it depend on the bean class instead of bean name?
Separate the profiles not on the bean but on the configuration class:
#Configuration
#Profile("!local")
class VaultConfiguration {
#Bean
public VaultPropertySource vaultPropertySource(ConfigurableApplicationContext context) {
// return real PropertySource
}
}
#Configuration
#Profile("local")
class LocalVaultConfiguration {
#Bean
public VaultPropertySource vaultPropertySource(ConfigurableApplicationContext context) {
// return local PropertySource
}
}
That probably helps.
How can I set this attribute in my JavaConfig application context?
<beans default-lazy-init="true">
<!-- no beans will be pre-instantiated... -->
</beans>
The Spring org.springframework.context.annotation.Lazy annotation indicates whether a bean is to be lazily initialized.
You can add it to a #Configuration class, a #Bean method or a #Component (for example #Service annotated class)
Example for a single bean:
#Configuration
public class MyConfig {
#Bean
#Lazy
public Example myLayzBean() {
return new Example();
}
}
Example for all beans in one configuration class
#Configuration
#Lazy
public class MyConfig {
#Bean
public Example1 myLayzBean1() {
return new Example1();
}
#Bean
public Example2 myLayzBean2() {
return new Example2();
}
}
Example for bean found by component scan
#Service
#Lazy
public class Example3 {
}
In Spring Framework is it possible to eliminate the entire Spring.xml and use a configuration class with #Configuration and #Bean annotation for creating bean, and for all other purpose use a spring.xml?
Yes, you can have pure java configuration in Spring. You have to create a class and annotate it with #Configuration. We annotate methods with #Bean and instantiate the Spring bean and return it from that method.
#Configuration
public class SomeClass {
#Bean
public SomeBean someBean() {
return new SomeBean();
}
}
If you want to enable component scanning, then you can give #ComponentScan(basePackages="specify_your_package") under the #Configuration. Also the method name as someBean serves as bean id. Also if you have to inject a dependency, you can use constructor injection and do as following:
#Configuration
public class SomeClass {
#Bean
public SomeDependency someDependency() {
return new SomeDependency();
}
#Bean
public SomeBean someBean() {
return new SomeBean(someDependency());
}
}
Yes,most of (maybe all of)official guides uses absolutely no xml configuration file,just annotations.
I'm not sure if I understand it correctly, but from what I got, is that I can use #Value annotations to read values from my application.properties.
As I figured out this works only for Beans.
I defined such a bean like this
#Service
public class DBConfigBean {
#Value("${spring.datasource.username}")
private String userName;
#Bean
public String getName() {
return this.userName;
}
}
When the application starts I'm able to retrieve the username, however - how can I access this value at runtime?
Whenever I do
DBConfigBean conf = new DBConfigBean()
conf.getName();
* EDIT *
Due to the comments I'm able to use this config DBConfigBean - but my initial problem still remains, when I want to use it in another class
#Configurable
public SomeOtherClass {
#Autowired
private DBConfigBean dbConfig; // IS NULL
public void DoStuff() {
// read the config value from dbConfig
}
}
How can I read the DBConfig in a some helper class which I can define as a bean
Thanks
As Eirini already mentioned you must inject your beans.
The #Value annotation only works on Spring beans.
There is another way of accessing configuration with #ConfigurationProperties.
There you define a class that holds the configuration.
The main advantage is, that this is typesafe and the configuration is in one place.
Read more about this:
https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config-vs-value
You shouldn't instantiate your service with the new operator. You should inject it, for example
#Autowired
private DBConfigBean dbConfig;
and then dbConfig.getName();
Also you don't need any #Bean decorator in your getName() method
You just need to tell spring where to search for your annotated beans. So in your configuration you could add the following:
#ComponentScan(basePackages = {"a.package.containing.the.service",
"another.package.containing.the.service"})
EDIT
The #Value, #Autowired etc annotations can only work with beans, that spring is aware of.
Declare your SomeOtherClass as a bean and add the package config in your #Configuration class
#Bean
private SomeOtherClass someOtherClass;
and then
#Configuration
#ComponentScan(basePackages = {"a.package.containing.the.service"
"some.other.class.package"})
public class AppConfiguration {
//By the way you can also define beans like:
#Bean
public AwesomeService service() {
return new AwesomeService();
}
}
Wrap your DBConfig with #Component annotation and inject it using #Autowired :
#Autowired
private DBConfig dbConfig;
Just add below annotation to your DBConfigBean class:
#PropertySource(value = {"classpath:application.properties"})
How to read properties file in Controller using annotations only?
Properties file contains (env.properties):
document.portal.path=http://flana.gost.com/service
Spring Controller:
#Controller
#RequestMapping("/kap/*")
#SessionAttributes({"user", "KapForm", "activity"})
public class KapController {
#Value("${document.portal.path}")
private String URL;
}
Nothing else is done. In XML, we use to use placeholder, which i am not getting how to introduce in it. So I am getting exception.
Injection of autowired dependencies failed;
You can achieve it in two ways
Option 1
In config class put #PropertySource and define a bean for PropertySourcesPlaceholderConfigurer as below -
#Configuration
#PropertySource("classpath:someFile.properties")
public class SampleConfig {
// other configs...
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
Option 2
In config class directly specify the bean for PropertyPlaceholderConfigurer and supply the name of property file as ClassPathResource
#Configuration
public class SampleConfig {
// other configs...
#Bean
public static PropertyPlaceholderConfigurer placeHolderConfigurer(){
PropertyPlaceholderConfigurer placeHolderConfigurer = new PropertyPlaceholderConfigurer();
ClassPathResource[] cpResources = new ClassPathResource[]
{ new ClassPathResource( "someFile.properties" ) };
placeHolderConfigurer.setLocations(cpResources);
placeHolderConfigurer.setIgnoreUnresolvablePlaceholders(true);
return placeHolderConfigurer;
}
}
Do note that the bean definition for place holder need to be static as per java docs (excerpts below)
Special consideration must be taken for #Bean methods that return Spring BeanFactoryPostProcessor (BFPP) types. Because BFPP objects must be instantiated very early in the container lifecycle, they can interfere with processing of annotations such as #Autowired, #Value, and #PostConstruct within #Configuration classes. To avoid these lifecycle issues, mark BFPP-returning #Bean methods as static.
Another way out found is
import org.springframework.context.MessageSource;
#Autowired
private MessageSource messageSource;
cutiePie = messageSource.getMessage("cutie.pie.property", new Object[] {},"cutie.pie.property", LocaleContextHolder.getLocale());