Is #EnableTransactionManagement required in Spring Boot?
I did some research. Some folks say you don't need it, as Spring Boot has it already enabled, others say you do have to use it explicitly. So how is it?
Probably you're also using Spring Data. Calls on Spring Data repositories are by default surrounded by a transaction, even without #EnableTransactionManagement. If Spring Data finds an existing transaction, the existing transaction will be re-used, otherwise a new transaction is created.
#Transactional annotations within your own code, however, are only evaluated when you have #EnableTransactionManagement activated (or configured transaction handling some other way).
You can easily trace transaction behavior by adding the following property to your application.properties:
logging.level.org.springframework.transaction.interceptor=TRACE
(see Showing a Spring transaction in log)
According to > https://spring.io/guides/gs/managing-transactions/
Spring Boot will detect spring-jdbc on the classpath and h2 and will create a DataSource and a JdbcTemplate for you automatically. Because such infrastructure is now available and you have no dedicated configuration, a DataSourceTransactionManager will also be created for you: this is the component that intercepts the #Transactional annotated method.
You can also use spring-boot-starter-actuator to list your beans created in your context and you will find it
bean": "transactionManager"
Little old post but the answers given previously were not straight forward when I was searching for it.
#EnableTransactionManagement is optional in Spring boot, provided that spring-data* or spring-tx are found in classpath. How it works? As below:
Spring boot adds a spring-boot-autoconfigure.jar in the classpath. Go to the META-INF's spring.factories file and you can see org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration entry there. This initializes the transaction auto configuration for you.
Note that the class has following lines: (snippet)
#Configuration
#ConditionalOnClass({PlatformTransactionManager.class})
#AutoConfigureAfter({JtaAutoConfiguration.class, HibernateJpaAutoConfiguration.class, DataSourceTransactionManagerAutoConfiguration.class, Neo4jDataAutoConfiguration.class})
#EnableConfigurationProperties({TransactionProperties.class})
public class TransactionAutoConfiguration {
..
}
Have a look at TransactionAutoConfiguration to see that it enables transaction support if the PlatformTransactionManager is available in classpath. EnableTransactionManagementConfiguration is also configured there.
No. #EnableTransactionManagement is on by default, see that: https://github.com/jkubrynski/spring-boot/commit/9d219ef7a004c58a88bbbef82a520a22961c9402
#EnableTransactionManagement is conditionally turned on/off based of the dependency jars we add in the classpath. If we use spring data jpa starter it is turned on.
In the class org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration, there is such code(Spring Boot 1.5+):
#Configuration
#EnableTransactionManagement(proxyTargetClass = false)
#ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "false", matchIfMissing = false)
public static class JdkDynamicAutoProxyConfiguration {
}
#Configuration
#EnableTransactionManagement(proxyTargetClass = true)
#ConditionalOnProperty(prefix = "spring.aop", name = "proxy-target-class", havingValue = "true", matchIfMissing = true)
public static class CglibAutoProxyConfiguration {
}
The default is spring.aop.proxy-target-class=true, enabling CGLIB proxy by default.
If you want to use JDK proxy, set spring.aop.proxy-target-class=false instead.
Related
I have a custom starter that other projects depends on, and that starter applies some configurations including a PropertySource
#Configuration
#PropertySource(value = "classpath:application-geoip.yml", factory = YamlPropertySourceFactory.class)
public class CustomStarterAutoConfiguration
{...}
application-geoip.yml contains properties specific to it's business and an enablement value
...
geoip2:
enabled: true
...
The starter provides the geoip beans with condition to above enabled parameter.
#Configuration
#ConfigurationProperties(prefix = "geoip2")
#ConditionalOnProperty(prefix = "geoip2", name = "enabled", havingValue = "true")
public class GeoIP2ConfigurationProperties {...}
#Configuration
#ConditionalOnProperty(prefix = "geoip2", name = "enabled", havingValue = "true")
public class GeoIPConfig {
// define required beans here with dependency to config from above #Configuration bean
}
I ship my starter with this and then create a project depending on this starter.
In my project, when I check above beans (even the property already set to true) in the context I can not see the beans initiated.
Debugged a bit and see that; While annotation ConditionalOnProperty is being processed, the context does not have the geoip2.enabled set. But If I wait until the app start and listen the ApplicationStartedEvent event. I can see the property is there.
event.getApplicationContext().getEnvironment().getProperty("geoip2.enabled") returns true.
so If I am assuming it correct, the PropertySource annotation seems to processed after ConditionalOnProperty annotation. Not always, but mostly. Depends on who wins the race.
Why I am trying this, I would like to carry the property from core with a default value. then using projects can override it in their own application.yaml files. I treid to add the property on simple project's application.yaml file and this time the property picked up and beans initiated as expected.
Rather than using #PropertySource, your custom starter should provide an EnvironmentPostProcessor implementation that's registered in META-INF/spring.factories. This post-processor is called once the Environment has been created but before the application context is refreshed and any beans are created. It should add a PropertySource to the environment that contains the geoip2 properties. If you position your PropertySource appropriately, these properties could then be overridden by those in the user's application.yaml file.
You can learn more in the reference documentation.
I'm using Spring Boot 2.2.5.RELEASE and would like to split my application.properties into separate files. There are already similar questions on StackOverflow but none of them seem to work for configuring Jackson.
My current non working solution is the following:
root/
- application.properties (without Jackson configuration)
- jackson-configuration.properties (includes Jackson configuration)
Jackson configuration class:
#Configuration
#PropertySource("/jackson-configuration.properties")
public class JacksonConfiguration {
}
Please note, I've tried different ways to specify the path including:
"/jackson-configuration.properties"
"jackson-configuration.properties"
"classpath:/jackson-configuration.properties"
"classpath:jackson-configuration.properties"
Spring Boot does not seem to use the configuration. If I copy it over into the application.properties - it works.
Content of jackson-configuration.properties:
spring.jackson.property-naming-strategy=SNAKE_CASE
spring.jackson.mapper.sort-properties-alphabetically=true
spring.jackson.deserialization.fail-on-unknown-properties=true
spring.jackson.parser.strict-duplicate-detection=true
spring.jackson.time-zone=Europe/Zurich
My application is annotated with #SpringBootApplication , so it should scan for additional properties.
/edit
I just realized the problem is the testing, not the productive code itself. If I start the application it works. What doess not work is testing with #JsonTest. I can fix this problem by adding the following line to my tests #ContextConfiguration(classes = {JacksonConfiguration.class}). But in turn, this causes the annotation #JsonComponent to stop working but only for the #JsonTest annotated classes.
See the documentation here. Here is an excerpt from the documentation
In order to resolve ${...} placeholders in definitions or
#Value annotations using properties from a PropertySource, you must
ensure that an appropriate embedded value resolver is registered in
the BeanFactory used by the ApplicationContext. This happens
automatically when using in XML. When
using #Configuration classes this can be achieved by explicitly
registering a PropertySourcesPlaceholderConfigurer via a static #Bean
method.
You need to create a bean like this
#Bean
public static PropertySourcesPlaceholderConfigurer devPropertyPlaceholderConfigurer() throws IOException {
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocations(new PathMatchingResourcePatternResolver().getResources("file:pathtToFile"));
configurer.setIgnoreUnresolvablePlaceholders(true);
return configurer;
}
I have the following dependency in my project and have #SpringBootApplication in my main class
spring-boot-starter-data-jpa
Is there any way to conditionally enable the spring boot datasourceautoconfiguration class based only when a Env property/System property is present.
Thanks
It appears that if you define the property "spring.datasource.initialize" to false, the initialization logic will be skipped.
If you look at the DataSourceAutoConfiguration definition, it loads in configuration properties...
That DataSourceProperties has an attribute named "initialize", and it appears this is referenced in the DataSourceInitializer default implementation...
I read that as being able to use a property to skip datasource initialization.
Hope this helps
How about extending DataSourceAutoConfiguration with annotation #ConditionalOnProperty? You can exclude the original DataSourceAutoConfiguration from spring and make your own implementation part of your application. Such as,
#Configuration
#ConditiaonalOnProperty(value = "datasource.property.anything",matccchIfMissing==true)
public class DataSourceInit extends DataSourceAutoConfiguartion {
}
Add exclude on your spring application class as:
#EnableAutoConfiguration(exclude = {DataSourceAutoConfiguration.class})
You can exclude auto-configurations using the spring.autoconfigure.exclude property. You could set that property using a system property:
-Dspring.autoconfigure.exclude=org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration
You could also set it using the SPRING_AUTOCONFIGURE_EXCLUDE environment variable.
We have a use case to not use Spring session, i.e. not have #EnableRedisHttpSession annotation even though Spring Session and Spring boot are in the classpath. We used to do that by having a custom property spring.session.enabled and having a #ConditionalOnProperty on the class that had the #EnableRedisHttpSession annotation. This worked in Spring boot 1.2.7. However with Spring Boot 1.3.0, the SessionAutoConfiguration class has a #EnableRedisHttpSession annotation on it.
Is there a way to disable the class from being used?
To disable Spring Boot Auto-Configuration of Spring Session:
#SpringBootApplication(exclude = {SessionAutoConfiguration.class})
public class Application
{
...
}
Then, to enable Spring Session depending on a property (for example, you may want it disabled when in development but enabled in production):
#Configuration
#ConditionalOnProperty(value = "spring.session.enabled", havingValue = "true", matchIfMissing = false)
#EnableRedisHttpSession
public class HttpSessionConfig
{
...
}
I had the same question and through the comments, I was able to get my answer so I'm putting this down here so the question is marked as answered:
In my spring boot application i configure two different instances of MQQueueConnectionFactory (different id) as it is a need of the application. For that i have added ibm client jars.
I have also added spring-jms dependency in my code as i wanted JmsTemplate etc classes. After adding this dependency, JmsAutoConfiguration finds JmsTemplate in classpath and tries to configure beans. In this process, it tries to inject bean of type ConnectionFactory and this is where the code fails and i start getting the error. Below is the code from JmsAutoConfiguration
#Configuration
#ConditionalOnClass(JmsTemplate.class)
#ConditionalOnBean(ConnectionFactory.class)
#EnableConfigurationProperties(JmsProperties.class)
#Import(JmsAnnotationDrivenConfiguration.class)
public class JmsAutoConfiguration {
#Autowired
private JmsProperties properties;
#Autowired
private ConnectionFactory connectionFactory;
#Autowired(required = false)
private DestinationResolver destinationResolver;
Do i have a facility to switch off JmsAutoconfiguration feature of spring boot by any chance? If not then what is the alternative solution for this?
You can add the auto configurations, which you want to disable, to the SpringBootApplication annotation:
#SpringBootApplication(exclude = JmsAutoConfiguration.class)
FYI, use this to disable ActiveMQ
#SpringBootApplication(exclude = ActiveMQAutoConfiguration.class)
if want to control it via the properties (in this case a application.yml) then you can do something like this.
spring:
autoconfigure:
exclude: org.springframework.boot.autoconfigure.jms.JmsAutoConfiguration
In my case it worked after excluding both classes :
#EnableAutoConfiguration(exclude={JmsAutoConfiguration.class, ActiveMQAutoConfiguration.class})