We are currently migrating from xml configuration to complete annotation with java configuration based Spring application. With the annotation approach #Transactional we can achieve but the we need to write for each and every method.
In XML we configured (OLD).
<bean id="txProxyTemplate" abstract="true"
class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
<property name="transactionManager">
<ref bean="transactionManager" />
</property>
<property name="transactionAttributes">
<props>
<prop key="delete*">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED</prop>
<prop key="update*">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED</prop>
<prop key="save*">PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED</prop>
<prop key="get*">PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITTED,readOnly</prop>
<prop key="is*">PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITTED,readOnly</prop>
<!--<prop key="*">PROPAGATION_REQUIRED</prop> -->
</props>
</property>
</bean>
transactionManager is org.springframework.orm.hibernate3.HibernateTransactionManager
<bean id="xxxxSVC" parent="txProxyTemplate">
<property name="target">
<bean class="XXX.XXX.XXX.SVCImpl">
<property name="xxxxDao" ref="xxxDao"></property>
</bean>
</property>
</bean>
txProxyTemplate is parent class of each service class.
So, please suggest how to configure similar code in java configuration. Thanks for your valuable time spent and support us.
#Barath Comment
Bean
#Bean
public TransactionProxyFactoryBean setTransactionProperties() throws IOException {
TransactionProxyFactoryBean transactionProxyFactoryBean = new TransactionProxyFactoryBean();
transactionProxyFactoryBean.setTransactionManager(transactionManager(sessionFactory()));
Properties transactionAttributesProps = new Properties();
transactionAttributesProps.setProperty("delete*", "PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED");
transactionAttributesProps.setProperty("update*", "PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED");
transactionAttributesProps.setProperty("save*", "PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED");
transactionAttributesProps.setProperty("get*", "PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITTED,readOnly");
transactionAttributesProps.setProperty("is*", "PROPAGATION_SUPPORTS,ISOLATION_READ_COMMITTED,readOnly");
transactionProxyFactoryBean.setTransactionAttributes(transactionAttributesProps);
transactionProxyFactoryBean.afterPropertiesSet();
return transactionProxyFactoryBean;
}
How to configure with each service implementation class, we can use it for single as a service layer may contain N classes. There is a method setTarget(Object target). Now how can we configure all the N classes. Please sugggest how can we configure.
A sample configuration for this case :
#Bean
public TransactionProxyFactoryBean txProxyTemplate(){
TransactionProxyFactoryBean txFactory=new TransactionProxyFactoryBean();
txFactory.setTransactionManager(new JpaTransactionManager()); // any transcation manager
txFactory.setTransactionAttributes(properties());
return txFactory;
}
#Bean
Properties properties(){
Properties properties=new Properties();
properties.put("delete*", "PROPAGATION_REQUIRED,ISOLATION_READ_COMMITTED");
//set al lthe properties
return properties;
}
#Bean
public TransactionProxyFactoryBean xxxxSVC(TransactionProxyFactoryBean txFactory){
txFactory.setTarget(testEntity());
return txFactory;
}
#Bean
TestEntity testEntity(){
return new TestEntity();
}
Related
I am working on Spring MVC web application which is using JDBC Quartz Scheduler to execute jobs. This web application has multiple services each of which is packaged as an jar and has associated jobs. I have one quartz configuration which is in web project, under which I have created beans for jobs, triggers and scheduler. Under scheduler configuration, i specify a list of triggers. This was good when we started our project. As we started adding features, number of jobs increased and its now around 100+. It has become difficult to maintain this file. Is there any approach available make it modular so that the jobs/trigger/associating trigger to scheduler are not defined in the one single file.
<bean name="incidentAutoClosure" class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="itsm.scheduler.task.IncidentAutoClosureTask"/>
</bean>
<bean id="incidentAutoClosureTrigger" class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="incidentAutoClosure" />
<property name="cronExpression" value="0 0 12 1/1 * ? *" />
</bean>
<bean id="quartzJdbcScheduler"
class="org.springframework.scheduling.quartz.SchedulerFactoryBean"
p:waitForJobsToCompleteOnShutdown="true">
<property name="autoStartup" value="true" />
<property name="startupDelay" value="0" />
<property name="overwriteExistingJobs" value="false" />
<property name="quartzProperties">
<props>
<prop key="org.quartz.scheduler.instanceName">mvcJdbcScheduler</prop>
<prop key="org.quartz.jobStore.class">org.quartz.impl.jdbcjobstore.JobStoreTX</prop>
<prop key="org.quartz.jobStore.driverDelegateClass">org.quartz.impl.jdbcjobstore.PostgreSQLDelegate</prop>
<prop key="org.quartz.jobStore.tablePrefix">QRTZ_</prop>
<prop key="org.quartz.threadPool.class">org.quartz.simpl.SimpleThreadPool</prop>
<prop key="org.quartz.threadPool.threadCount">${quartz.async.threadCount}</prop>
<prop key="org.quartz.threadPool.threadPriority">${quartz.async.threadPriority}</prop>
<prop key="org.quartz.jobStore.misfireThreshold">${quartz.async.misfireThreshold}</prop>
<prop key="org.quartz.jobStore.isClustered">true</prop>
<prop key="org.quartz.scheduler.threadsInheritContextClassLoaderOfInitializer">true</prop>
<prop key="org.quartz.plugin.jobHistory.class">org.quartz.plugins.history.LoggingJobHistoryPlugin</prop>
<prop key="org.quartz.plugin.jobHistory.jobToBeFiredMessage">${quartz.async.initTriggerFormat}</prop>
<prop key="org.quartz.plugin.jobHistory.jobSuccessMessage">${quartz.async.endTriggerFormat}</prop>
</props>
</property>
<property name="triggers">
<list>
<ref bean="incidentAutoClosureTrigger" />
<!-- List of 100 Jobs -->
</list>
</property>
</bean>
Few things, Are you using spring boot? A good approach to this problem would be to create auto configuration class where you can have a list of combinations. Here is a sample:
#Configuration
#ConditionalOnBean(SomeClassDependency.class)
public class JobConfig {
#Bean
#ConditionalOnProperty(....)
public SchedulerFactoryBean config1() {
....
}
#Bean
#ConditionalOnProperty(....)
public SchedulerFactoryBean config2() {
....
}
#Bean
#ConditionalOnProperty(....)
public SchedulerFactoryBean config3() {
....
}
}
public class MyDependency {
private final SchedulerFactoryBean schedulerFactoryBean;
public MyDependency(#Qualifier("config2") SchedulerFactoryBean schedulerFactoryBean) {
this.schedulerFactoryBean = schedulerFactoryBean
}
}
you can do it programmatically through a configuration class that will automatically configure your bean instead of using an xml file;
here is what I used. Note: having the applicationContext added to the jobFactory allows Quartz schedule jobs to be aware of spring autowired classes when the job executes otherwise you'll get a null autowire
#Configuration
public class PortalQuartzSchedulerConfiguration {
#Autowired
private ApplicationContext applicationContext;
#Bean
public JobFactory jobFactory() {
ApplicationContextHolder jobFactory = new ApplicationContextHolder();
jobFactory.setApplicationContext(applicationContext);
return jobFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactory() {
SchedulerFactoryBean factory = new SchedulerFactoryBean();
factory.setAutoStartup(true);
factory.setSchedulerName("Portal scheduler");
factory.setOverwriteExistingJobs(true);
factory.setJobFactory(jobFactory());
return factory;
}
}
I want to be able to read the properties from certain bean definitions that are configured in my Spring configuration file (i.e. the one set by contextConfigLocation in my web.xml) at run time. I want to do this so that I can log property values so that I when I receive the log files for diagnosis I can see how the system integrators have set up the application.
Looking at the Spring debug logs I can see that they are read from the config file by the class XmlBeanDefinitionReader. I'm guessing there is a way that Spring provides for accessing the resulting bean definitions, but I can't find it.
By way of example these are the sort of bean definitions that for which I would like to read configurations.
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close">
<property name="driverClass">
<value>com.mysql.jdbc.Driver</value>
</property>
<property name="jdbcUrl">
<value>jdbc:mysql://localhost:3306/an_example_db</value>
</property>
<property name="user">
<value>exampleuser</value>
</property>
<property name="password">
<value>examplepwd</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="packagesToScan" value="com.my.example.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.id.new_generator_mappings">true</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.query.substitutions">true 1, false 0, yes 'Y', no 'N'</prop>
</props>
</property>
</bean>
Please note that these are examples only. I'd like to be able to read properties for any bean definition if that is possible.
You can create a bean that plugs in the post-construction phase of all beans created at which point you can perform you logging. This can be done by a bean that implements BeanPostProcessor.
Example:
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;
#Component
public class BeanPostProcessorAuditChecker implements BeanPostProcessor {
#Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
return bean;
}
#Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean: " + beanName + " initialized with props: " + bean);
return bean;
}
}
Things to note:
This bean can be defined using annotations (as depicted above) or XML config as usual.
The interface is intercepting all bean constructions.
The interface method implementations are expecting you to return the bean object.
In my example I just System.out.println but you really want to SLF4J or otherwise log. Also I'm trusting that the toString() method is implemented properly exposing the properties you are interested in.
If you want to filter the logging to happen only on a subset of beans and not for all beans you'll have to do that yourself in the body of the method with reflection
Snippet:
if(bean instanceof DataSource ||
bean instanceof SessionFactory) { log.debug("{}",bean); }
Since your business domain is not known some alternatives provided:
If you can pointcut your domain you want to plugin AOP is another alternative proxy approach.
You could expose JMX on the beans and consume externally (decoupled approach)
Another decoupled approach is publishing Events using ApplicationEventPublisher. This is fyi since not advisable in your case - you are interested in construction only state properties.
Before Edit
The beans you are demonstrating are 1) singletons (by virtue of Spring default scope) and 2) properties are not likely to be changing after bean setup (via set method calls).
Under these assumptions why aren't you amassing these properties values in a props file
database.driverClass=com.mysql.jdbc.Driver
database.user=exampleuser
...
inject them in the context definition
...
<property name="user" value="#{database.user}"/>
...
and use the PropertyPlaceholderConfigurer to check the values.
I am using the Spring configuration to test Spring-Hibernate Transactions.
<beans ...>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- hibernate 4 onwards annotationsessionfactorybean is replaced with localsessionfactory bean -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.fg.arch.test.transaction.Foo</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<!-- <prop key="hibernate.current_session_context_class">org.hibernate.context.internal.ThreadLocalSessionContext</prop> -->
</props>
</property>
</bean>
</beans>
My service layer is annotated with #Transactional.
This is my DAO:
public class FooHibernateDaoImpl implements FooDao {
private SessionFactory sessionFactory;
public void testFoo(Foo foo) throws Throwable {
System.out.println(" --- ");
sessionFactory.openSession().save(foo);
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
}
Explicitly opening the session using the openSession() method does not cause a problem however when I change to getCurrentSession() I am getting an exception.
I have two questions.
Is it good practice to call openSession() in every DAO method.
How can I make getCurrentSession() work so that it will not give me an exception like no active transaction present ?
Thanks.
To answer your questions:
No, its not. The #Transactional annotation that should be on your service class method calling testFoo() is opening the session for you. You should use getCurrentSession() in the DAO to get this session.
You can, but you shouldn't. That's the entire point of using the Hibernate SessionFactory with annotation based transaction management. As long as you are marking your service methods transactional, you shouldn't have a problem.
As a side note, why are you not Autowiring your SessionFactory? Don't use setters to set something that should be Autowired. Otherwise you may as well not use Spring.
I have a question how to inject values into implemented by spring class I don't want use xml to define that values like in this piece
<bean id="mailSender" class="org.springframework.mail.javamail.JavaMailSenderImpl">
<property name="host" value="your.smtphost.com"/>
<property name="port" value="25"/>
<property name="username" value="yourusername"/>
<property name="password" value="yourpassword"/>
<property name="javaMailProperties">
<props>
<!-- Use SMTP-AUTH to authenticate to SMTP server -->
<prop key="mail.smtp.auth">true</prop>
<!-- Use TLS to encrypt communication with SMTP server -->
<prop key="mail.smtp.starttls.enable">true</prop>
</props>
</property>
I would like to do it by annotation. I know there is method to extend that class but maybe there is another?
You can use annotation driven spring configuration for this as shown below
#Configuration
class SpringConfiguration {
#Bean
public JavaMailSenderImpl mailSender(){
JavaMailSenderImpl object = new JavaMailSenderImpl();
object.setXXX(ABC);
.....
return object;
}
}
Scenario: In the application I have language-dependent property files which are used as templates to generate emails:
email-subscription_en.properties:
email.subject=You are successfully subscribed to list {0}
email.body=...
email-cancellation_en.properties:
email.subject=You are successfully unsubscribed from list {0}
email.body=...
and so on. Now in Spring context I would like to have these bundles:
<bean id="subscriptionMailProperties" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="org.company.email-subscription" />
</bean>
<bean id="cancellationMailProperties" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="org.company.email-cancellation" />
</bean>
be merged with these common language-independent properties which I would like to be declared in context:
<util:properties id="commonMailProperties">
<prop key="email.from">noreply#company.org</prop>
<prop key="email.to">{0}#company.org</prop>
</util:properties>
How is it possible?
As far as I know there is no support for this. You are trying to mix configuration with resource bundles. I feel what you currently have is right. If you do not have luxury of keeping it as it is, here is a way(more of a hack)
Implement org.springframework.context.MessageSource with 'commonMailProperties'(java.util.Properties) as dependency and say the bean id as 'commonMessageSource'.
In 'getMessage' implementations get the value from 'commonMailProperties'.
Inject 'commonMessageSource' to 'subscriptionMailProperties' and 'cancellationMailProperties', for 'parentMessageSource' property.
If somebody got interested in complete solution:
Create class PropertiesMessageSource:
/**
* {#link org.springframework.context.MessageSource} implementation that resolves messages via underlying
* {#link Properties}.
*/
public class PropertiesMessageSource extends AbstractMessageSource {
private Properties properties;
/**
* Set properties to use.
*/
public void setProperties(Properties properties) {
this.properties = properties;
}
#Override
protected MessageFormat resolveCode(String code, Locale locale) {
String property = properties.getProperty(code);
if (property == null) {
return null;
}
return createMessageFormat(property, locale);
}
}
Use it:
<bean id="commonMailProperties" class="org.company.PropertiesMessageSource">
<property name="properties">
<props>
<prop key="email.from">noreply#company.org</prop>
<prop key="email.to">{0}#company.org</prop>
</props>
</property>
</bean>
<bean id="subscriptionMailProperties" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="org.company.email-subscription" />
<property name="parentMessageSource">
<ref bean="commonMailProperties"/>
</property>
</bean>
ResourceBundleMessageSource (more exactly: all descendants of AbstractMessageSource) now has commonMessages property which can hold locale-independent values. For example while you want to have mail subject and body locale-dependant, some properties (mail from and mail to) are common across all bundles (check SPR-10291):
<bean id="mailProperties" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basename" value="org.mycompany.email" />
<property name="commonMessages">
<props>
<prop key="email.from">empty#mydomain.org</prop>
<prop key="email.to">%s#mydomain.org</prop>
</props>
</property>
</bean>