In Spring, beans can be configured to be lazily initialized. Spring Batch jobs are also (Spring-managed) beans. That is, when I configure something like
<sb:job id="dummyJob" job-repository="jobRepository">
<sb:step id="dummyStep">
<sb:tasklet ref="dummyTasklet" />
</sb:step>
</sb:job>
I actually configure a new (Job-typed) bean inside the Spring container.
My issue is I really want my Job beans to be lazily initialized. As they are regular Spring-managed beans, I'd expect I can instruct the Spring context to make them lazy. This is because I have a large number of beans and there are many cases in which, during one execution of my Spring-based application, I only run one job.
But there's no lazy-init property I can set on my <sb:job... \> configuration. Is there any way I can force lazy initialization? If I configure my <beans\> root with default-lazy-init="true", will this also apply to the Job beans?
You have two options here:
Configure your job manually. This would allow you to use the regular lazy-init attributes Spring exposes.
Use the JobScope now available in Spring Batch 3. Spring Batch 3 will be available soon, but the JobScope was available in the last milestone.
Just to elaborate on Michael Minella's answer.
I had a similar requirement to lazy initialize the job repository.
I am working with Spring Batch 2.1.9.
The following is working for me.
<bean id="jobRepository"
class="org.springframework.batch.core.repository.support.JobRepositoryFactoryBean"
lazy-init="true">
<property name="dataSource" ref="jobDataSource"/>
<property name="transactionManager" ref="jobTransactionManager"/>
</bean>
Note one pitfall I had run into: do not set the databaseType i.e. avoid the following:
<property name="databaseType" value="SQLSERVER"/>
This is bad because it disable the auto-discovery of the database type and breaked my JUnits that works on H2.
Related
I have an issue in the process of migrating an existing spring web application to Spring Boot 1.5.13. I've handled almost everything, but I can't managed to have the good persistence unit injected to WebMvcAutoConfiguration. I actually have 3 different entity manager factory that are imported from the classpath (provided as .xml file by 3 different internal libraries, I have no way to change them). Each of them is splitted in this way:
<sqe-db:jpa-emf database-definition-name="db-name" embedded-datasource="false"/>
and
<bean id="transaction-mnanager-name" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="jpa-lib-name" />
</bean>
The datasources configuration is provided by tomcat at the moment, but I will externalize them to application.properties for the dev environment
After my migration, I didn't find any way to specify the right bean to WebMvcAutoConfiguration, and this is leading to the following error:
Method requestMappingHandlerMapping in org.springframework.boot.autoconfigure.web.WebMvcAutoConfiguration$EnableWebMvcConfiguration required a single bean, but 3 were found:
- jpa-lib1-name1: defined in null
- jpa-lib1-name2: defined in null
- jpa-lib1-name3: defined in null
My goal at this point is to have the following configuration in place:
have the application both runnable as a SpringApplication and deployable as a WAR (and I think I already did it properly)
having a way to use Spring Boot autoconfiguration for web apps, even with multiple entity factory in the classpath
use my own datasources for the "dev" profile, but leave the tomcat one for the other environment.
my requisites are, more or less:
- minimize the changes needed to the existing application
- continue to use the .xml provided by the libraries
An easy option would be to rewrite the configuration, using a more modern annotation driven configuration, but I would prefer to stick to the existing implementation, so that I don't have to change it when a new library is released.
Any way to declare the #Primary bean without touching the existing xml file?
Any ideas, or different approaches are very welcome
After a good night of sleep, I was able to find the easiest of the solution.
I added this to my configuration class:
#Autowired
#Qualifier("name-of-default-factory")
private EntityManagerFactory entityManagerFactory;
#Bean
#Primary
public EntityManagerFactory getEntityManagerFactory() {
return entityManagerFactory;
}
And it will now have the primary bean correctly injected.
First a bit of setup info:
I have a multi-tenant spring based application. The multi-tenant enabling library is an in-house developed tool where I work that I have to use. How it works is that there is an interceptor that sets in front of the servlet for the application. Upon a request hitting the servlet it loads a tenant specific spring config for "stuff" needed for the tenant specified on the url hitting the servlet.
As stated, the above is just a bit of background. Now to the issue/question:
What I want to do is to create, in the tenant configuration that is loaded, a value that I can use to inject where I need. So, is there a way I can just define a constant in a spring config and then reference it via #Value or #Resource in java code?
There will be no bean implementation behind it, it would just be purely and only a key/value that I can reference where needed in my application by name. So, something to the effect of:
<bean name="MyIdentifier">
<property name="theId" value="1001" />
</bean>
And then can I do something like?
#Value{MyIdentifier.theId}
String theId;
And have Spring be aware of and inject the value. The problem is that doing something like above Spring complains there is no implementation for the bean. Notice, no class specified for the bean. The reason I want to do this is every tenant config file will contain this bean, but the actual value will vary per tenant.
Is there some other type to use in the config to do this? If so, what schemas have to be on the config?
I am guessing I am either trying to make Spring do something not intended, or, this is so simple I cannot see it since I have stared at it too long. Anyway, thanks for the help.
You can not create bean tag in configuration file without providing class implementation. If you want to inject the value of fields, you have to go for properties file instead.
Create property file as below:
application.properties
theId=1001
Load property file in your configuration:
<bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer">
<property name="ignoreUnresolvablePlaceholders" value="true"/>
<property name="locations">
<list>
<value>classpath:application.properties</value>
</list>
</property>
</bean>
And access the property in your concrete class:
#Value("${theId}")
String theId;
I'm writing an app that may talk to multiple database and web services. I'd like to use Spring's #Transactional annotation so that a failure in any one can rollback them all.
I'm not clear about how I should do this, and I can't find any examples of it either after searching.
One thought I have is to create a bean that is a custom aspect and use that to intercept the methods, adding my own custom code to rollback problems. But I'm sure there must be a way to do this in a standardised fashion.
Thank you!
Alex
The most straightforward way to implement distributed transactions is JTA, but I don't think it's feasible in your case, because you also need to cover web services.
However, you can implement a "best effort" solution manually by registering TransactionSynchronizations for your transactional resources. This way you can integrate them with #Transactional.
See TransactionSynchronizationManager.
you should have something like below declared in your spring config xml for each of the datasource to be able to use #Transactional in your application:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
I am trying to use JtaTransactionManager in spring/hibernate. I have below configuration.
<bean id="transactionManager" class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="userTransactionName" value="java:comp/UserTransaction"></property>
</bean>
Now can i mark my service methods with #Transactional ? or do i need any extra configuration to use #Transactional ? do i need to add ?
An annotation is nothing more then metadata, so only slapping an annotation on there and expect it to magically work isn't going to happen.
To make #Transactional work you need to tell spring that you want to use annotation to drive your transactions. For this add the <tx:annotation-driven /> tag to your configuration.
However that probably isn't going to be all there is needed as you also need to configure hibernate appropriately for JTA.
A small tip instead of defining the bean, use the shorter <tx:jta-transaction-manager />. This will do some detection on which app server you are running and configure the appropriate transaction manager for you. See http://docs.spring.io/spring/docs/current/spring-framework-reference/html/transaction.html#transaction-application-server-integration for more information.
when using #transactional do i need to use jpatemplate/hibernatetemplate ?
No, you don't. Spring has a built-in transaction manager that can be used for simple transactions, e.g. if you don't need to track transactions across more than one DataSource. The configuration should be as simple as this:
<tx:annotation-driven transaction-manager="txManager"/>
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
Where the bean named "dataSource" is some DataSource bean configured elsewhere in your XML file.
However if you're using JPA or Hibernate, it would be a good idea to use the JPATransactionManager or HibernateTransactionManager, respectively.
If you really wanted to you could also use JTA, which is Sun's standard transaction implementation. I think the spring class is called JTATransactionManager.
Using transaction managers other than Spring's out-of-the-box one (the one defined in the XML config above) will give you the ability to use transactions across multiple DataSources.
The answer depends on the what version of Hibernate you are using. With later versions the simple answer is no you don't need the templates. See here for a comprehensive discussion:
http://blog.springsource.com/2007/06/26/so-should-you-still-use-springs-hibernatetemplate-andor-jpatemplate/
I came across an article that explains the process of implementing TxManager using #Transactional in depth. If you are interested, you can check this article here. I tried and this works!