I'm getting back into Spring (currently v4). It's all wonderful now with #SpringBootApplication and the other annotations but all the documentation seems to forget to mention how I define other beans in XML!
For example I'd like to create an "SFTP Session Factory" as defined at:
http://docs.spring.io/spring-integration/reference/html/sftp.html
There is a nice bit of XML to define the bean but where on earth do I put it and how do I link it in? Previously I did a:
ApplicationContext context = new ClassPathXmlApplicationContext(
"classpath:applicationContext.xml");
to specify the file name and location but now that I'm trying to use:
ApplicationContext ctx = SpringApplication.run(Application.class);
Where do I put the XML file? Is there a magic spring name to call it?
As long as you're starting with a base #Configuration class to begin with, which it maybe sounds like you are with #SpringBootApplication, you can use the #ImportResource annotation to include an XML configuration file as well.
#SpringBootApplication
#ImportResource("classpath:spring-sftp-config.xml")
public class SpringConfiguration {
//
}
You also can translate the XML config to a Java config. In your case it would look like:
#Bean
public DefaultSftpSessionFactory sftpSessionFactory() {
DefaultSftpSessionFactory factory = new DefaultSftpSessionFactory();
factory.setHost("localhost");
factory.setPrivateKey(new ClassPathResource("classpath:META-INF/keys/sftpTest"));
factory.setPrivateKeyPassphrase("springIntegration");
factory.setPort(22);
factory.setUser("kermit");
return factory;
}
You can put this method in the class with the #SpringBootApplication annotation.
Spring boot ideal concept is avoid xml file. but if you want to keep xml bean, you can just add #ImportResource("classPath:beanFileName.xml").
I would recommend remove the spring-sftp-config.xml file. And, convert this file to spring annotation based bean. So, whatever class has been created as bean. Just write #Service or #Component annotation before class name. for example:
XML based:
<bean ID="id name" class="com.example.Employee">
Annotation:
#Service or #Component
class Employee{
}
And, add #ComponentScan("Give the package name"). This is the best approach.
Related
I tried to make a #ConfigurationProperties bean without setters so I used #ConstructorBinding. Let's call this class PropertiesFromYml.java.
This works fine, bean is created perfectly by the properties from the yml file.
The configuration class has the necessary setup:
#Configuration
#ConfigurationPropertiesScan("com.my.package") // this is where PropertiesFromYml.java is stored
public class MyConfig
I wanted to add the #StepScope to that PropertiesFromYml.java because my SpringBoot application will run scheduled batch jobs, so I don't want to initiate this class, but only when the job needs it.
BUT: Unfortunately, the bean is always created during startup. I guess this is because of the #ConfigurationPropertiesScan annotation on MyConfig.java class. But how can I tell to create the bean only when necessary, like with #StepScope?
Configuration will be created at the start of your application. Instead what you may want to do is split your class into 2. The actual configuration part and the schedule part: SchedularConfiguration, SchedularComponent. And then inject the configuration into the component.
#StepScope
#Component
class SchedularComponent {
#Autowired
SchedularConfiguration config;
}
That will allow you to have the scope you want. Usually you wouldn't have a whole other class for configuration of a component (but your requirements may vary) and use directly the #Value annotation to select what application property you want: #Value("${schedular.cron}").
The Spring Boot documentation says that to use the #ConfigurationProperties annotation
You also need to list the properties classes to register in the
#EnableConfigurationProperties annotation, as shown in the following
example:
and gives this code:
#Configuration
#EnableConfigurationProperties(AcmeProperties.class)
public class MyConfiguration {
}
But in the very next paragraph says:
Even if the preceding configuration creates a regular bean for
AcmeProperties, we recommend that #ConfigurationProperties only deal
with the environment and, in particular, does not inject other beans
from the context. Having said that, the #EnableConfigurationProperties
annotation is also automatically applied to your project so that any
existing bean annotated with #ConfigurationProperties is configured
from the Environment.
Suggesting that listing a #ConfigurationProperties bean under an #EnableConfigurationProperties annotation is not necessary.
So which is it? Experimentally, I've seen that if I annotate a bean with #ConfigurationProperties it gets properties injected to it as expected without needing to list it in #EnableConfigurationProperties, but if this is the case then why list anything that has a #ConfigurationProperties annotation under #EnableConfigurationProperties, as is shown in the documentation? Does it make any kind of difference?
As M. Deinum referred #EnableConfigurationProperties Is for enabling support of #ConfigurationProperties. If you take a look to the annotation Java Doc you can see:
Enable support for ConfigurationProperties annotated beans. ConfigurationProperties beans can be registered in the standard way (for example using Bean #Bean methods) or, for convenience, can be specified directly on this annotation. [...]
For example, let's say you have a class whose responsibility is to read and store information from your application.yml / application.properties that is required to make a connection to different databases. You annotate it with #ConfigurationProperties.
Then, you typically have a #Configuration annotated class that provides a DataSource #Bean to your application. You can use the #EnableConfigurationProperties to link it to the #ConfigurationProperties class and init your data sources accordingly.
Here is a small example:
application.yml
data-sources:
db1:
url: "jdbc:postgresql://localhost:5432}/db1"
username: test
password: test
db2:
url: "jdbc:postgresql://localhost:5432}/db2"
username: test
password: test
DataSourcesConfiguration
#ConfigurationProperties
public class DataSourcesConfiguration {
private Map<String, BasicDataSource> dataSources;
public void setDataSources(Map<String, BasicDataSource> dataSources) {
this.dataSources = dataSources;
}
Map<String, BasicDataSource > getDataSources() {
return dataSources;
}
}
DataSourceConnectionConfiguration
#Configuration
#EnableConfigurationProperties(DataSourcesConfiguration.class)
public class DatabaseConnectionConfiguration implements Provider<Connection> {
private DataSourcesConfiguration dataSourcesConfiguration;
public DatabaseConnectionConfiguration(DataSourcesConfiguration dataSourcesConfiguration) {
this.dataSourcesConfiguration = dataSourcesConfiguration;
}
#Bean
public DataSource dataSource() {
// Use dataSourcesConfiguration to create application data source. E.g., a AbstractRoutingDataSource..
}
}
It took me a while to reach to this post but would like to add here so that others may get benefited.
#ConfigurationProperties - Used to bind a class with an externalized property file. Very powerful and must be used to separate out bean classes with configuration entity class.
#Configuration - Creates a Spring bean of configuration stereotype.
#EnableConfigurationProperties - Creates a binding between a configuration entity class and Spring configuration stereotype so that after injection within a service properties can be retrieved easily.
If we look at the code below:
#Configuration #EnableConfigurationProperties #ConfigurationProperties(prefix="ar1")
public class ar1Settings { }
#Configuration tells Spring to treat this as a configuration class and register it as a Bean
#EnableConfigurationProperties tells Spring to treat this class as a consumer of application.yml/properties values
#ConfigurationProperties tells Spring what section this class represents.
My understanding is that if you don't need to specify the section of the property file, then #ConfigurationProperties can be omitted.
#EnableConfigurationProperties imports EnableConfigurationPropertiesRegistrar which enables support for #ConfigurationProperties annotated beans.
#ConfigurationProperties is an annotation for externalized configuration, it is to be applied to a bean configuration class or method annotated with #Bean eg
#ConfigurationProperties(prefix = "some-prefix")
public SomePrefix prefixBean() {
return new SomePrefix();
}
To load the properties and bind them to properties within the method or the class that match the prefix.
ps: some-prefix binds to SomePrefix because of spring's support for Relaxed binding.
Before springboot 2.2, You could do either of the following:
#Configuration
#ConfigurationProperties(prefix = "some-prefix")
public class ConfigProperties {
//...some code
}
or
#Configuration
#EnableConfigurationProperties(SomeClassToBeBounded.class)
public class ConfigProperties {
along with
#ConfigurationProperties(prefix = "some-prefix")
public class SomeClassToBeBounded{
//...some code
}
From springboot 2.2
You can do it in a much easier way:
#ConfigurationProperties(prefix = "some-prefix")
#ConfigurationPropertiesScan
public class ConfigProperties {
//...some code
}
With this, the classpath scanner enabled by #SpringBootApplication finds the ConfigProperties class, even though we didn't annotate this class with #Component.
Anybody know if #RefreshScope, applied to class for reloading properties/yml files dinamically works with a configuration class annotated only with #PropertySource?
I have to refresh an external configuration file, but i cant do something like :
#Bean
#RefreshScope
public FileProperties refreshListConfig() {
return new FileProperties(); //why ?
}
#Configuration //Configuration or new instance as above?
#PropertySource("file:${path.properties}")
#ConfigurationProperties(prefix="multitenancy")
public class FileProperties {
private List<DirProps> dir =new ArrayList<DirProps>();
private String tenantsFilePath;
..
class DirProps { ..}
...
}
I know that #RefreshScope doesn't work with #Configuration, but can I use #PropertySource without #Configuration?
Javadoc :
Annotation providing a convenient and declarative mechanism for adding a PropertySource to Spring's Environment. To be used in conjunction with #Configuration classes.
So, can't i use #RefreshScope without move external properties in application properties and removing #PropertySource and #Configuration annotations from FileProperties class? Do you know if exists a working approach without move the properties?
Thanks
I noticed a strange behaviour when using #Value with CamelConfiguration
Having an example properties file:
test.list=foo,bar,baz
and having a PropertySourcesPlaceholderConfigurer, a ConversionService and when referencing the property in some regular Spring configuration:
#Configuration
#PropertySource(value = "file:example.properties")
public class RegularConfig {
#Value("${test.list}")
List<String> testList;
}
Everything works as intended (testList contains three values: foo, bar, and baz), but when the configuration class extends org.apache.camel.spring.javaconfig.CamelConfiguration:
#Configuration
#PropertySource(value = "file:example.properties")
public class RegularConfig extends CamelConfiguration {
#Value("${test.list}")
List<String> testList;
}
(see minimal running example for both cases at https://github.com/michalmela/stackoverflow-questions/tree/master/35719697)
the testList contains one, joined value: foo,bar,baz.
Is this a misconfiguration on my side? Or some kind of bug (or feature)?
(I know the obvious workaround is to split the values manually, which is what I already went with, but I'd just like to understand what is going on here)
CamelConfiguration declare a BeanPostProcessor (camelBeanPostProcessor). BeanPostProcessor-s are instantiated by spring at first (because they have to see all others beans instantiation).
When Spring instantiate this camelBeanPostProcessor, it creates an instance of your class extending CamelConfiguration, inject the properties, and invoke camelBeanPostProcessor().
So, properties injected in this instance are injected at the beginning of the Spring ApplicationContext initialization. At this time, your ConversionService is not yet registered: The default converter is used, instead of the StringToCollectionConverter.
As a workaround, you can register explicitly a ConversionService before refreshing the applicationContext :
AnnotationConfigApplicationContext ctxt = new AnnotationConfigApplicationContext();
ctxt.getBeanFactory().setConversionService(new DefaultConversionService());
ctxt.register(...);
I know it may sound stupid but are you sure the configuration worked correctly before extending CamelConfiguration class? It doesn't look to me that #Value without using SpEL will split the list. I would use this configuration
#Value(value = "#{'${test.list}'.split(',')}")
Which version of Spring are you using?. Thanks
I'm new to Spring. I read something about #Autowired. In the document, it seems when I use #Autowired, I have to modify the XML file, such as applicationContext.xml.
However, I read the code, and I just saw #Autowired in Java code, but I didn't see XML file at all. And it works well. How to use #Autowired, do I still need xml, if needed, how to use it?
Spring application can be configured using java. In that case you dont need application.xml.
#Configuration
public class AppConfig {
#Autowired
Environment env;
#Bean
public MyBean myBean(){
return new MyBean()
}
}
Here #Configuration bean enables the #autowired. Following is another good example on using autowiring
http://www.mkyong.com/spring/spring-auto-wiring-beans-with-autowired-annotation/
Hope it helps