I have quartz job implementation using spring. My scheduler works fine and jobs are getting executed perfectly.
My question is how to bring this scheduler to standby? So that no jobs gets triggered once I decide to bring the scheduler to standby mode.
Below is the job class
public class MyJobClass extends QuartzJobBean {
//my job logic
}
Snippet from applicationContext_Scheduler.xml
<bean name="myJobBean"
class="org.springframework.scheduling.quartz.JobDetailFactoryBean">
<property name="jobClass" value="MyJobClass" />
</bean>
<bean id="rsHourlyJobCronTrigger"
class="org.springframework.scheduling.quartz.CronTriggerFactoryBean">
<property name="jobDetail" ref="myJobBean" />
<property name="cronExpression" value="00 0/1 * * * ?" />
</bean>
Instead of creating the scheduler bean in xml. I'd make it programatically as follows:
#Configuration
public class QuartzSchedulerConfiguration {
#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("Quartz Scheduler");
factory.setOverwriteExistingJobs(true);
factory.setJobFactory(jobFactory());
return factory;
}
}
#Component
public final class ApplicationContextHolder extends SpringBeanJobFactory implements ApplicationContextAware {
private static ApplicationContext context;
private transient AutowireCapableBeanFactory beanFactory;
#Override
public void setApplicationContext(ApplicationContext ctx) throws BeansException {
beanFactory = ctx.getAutowireCapableBeanFactory();
context = ctx;
}
#Override
protected Object createJobInstance(final TriggerFiredBundle bundle) throws Exception {
final Object job = super.createJobInstance(bundle);
beanFactory.autowireBean(job);
return job;
}
public static ApplicationContext getContext() {
return context;
}
}
This will create your quartz scheduler bean that is application context aware allowing you to autowire spring objects into your quartz jobs.
Then create some Scheduling service like:
#Service
public class SchedulerService {
#Autowired
private SchedulerFactoryBean schedulerFactory;
private Scheduler scheduler;
#PostConstruct
private void init() {
scheduler = schedulerFactory.getScheduler();
}
public void standBy() throws Exception {
if (scheduler != null && !scheduler.isInStandbyMode()) {
scheduler.standby();
}
}
}
Then add other methods that you need for scheduling.
Below are my classes and xml:
#Component
#Service("ApplicationService")
public class ApplicationServiceImpl implements ApplicationService{
public ApplicationDao getApplicationDao() {
return applicationDao;
}
public void setApplicationDao(ApplicationDao applicationDao) {
this.applicationDao = applicationDao;
}
#Autowired
private ApplicationDao applicationDao;
// some methods..
}
#Service
public interface ApplicationService {
// methods...
}
#Component
#Repository("ApplicationDao")
public class ApplicationDaoImpl implements ApplicationDao {
#Autowired
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
// other methods...
}
public interface ApplicationDao {
// methods...
}
xml file:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<tx:annotation-driven/>
<context:component-scan base-package="com" />
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<!-- <property name="dataSource" ref="dataSource" /> -->
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
</bean>
<bean id="ApplicationDao" class="com.dao.impl.ApplicationDaoImpl"/>
<bean id="ApplicationService" class="com.service.impl.ApplicationServiceImpl"/>
Here autowiring is not working.in ApplicationServiceImpl, I am getting applicationDao as null. Have not tested sessionFactory in ApplicationDaoImpl.
I know that if I am using #Component then bean declaration in xmnl is not required.
You should not instantiate service like that..
At the time of application loading, spring container will create all instances defined in spring.xml or annotated classes and it's dependencies..
So you have to access them with the following example code..
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
ApplicationService applicationService = (ApplicationService) applicationContext.getBean("ApplicationService");
Since ApplicationService is having property that is ApplicationServiceDAOImpl, it's already been created by spring container and will return you..
But in case of directly instantiating manually by you, you are just creating instance of ApplicationService but not for ApplicationServiceDAOImpl.. so it obviously returns null
I'm currently using this approach only to access beans or services..
update for comment
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext applicationContext;
#Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
applicationContext = arg0;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}
Hope it helps,
try a change like this:
import org.springframework.beans.factory.annotation.Qualifier;
#Autowired
#Qualifier("ApplicationDao")
private ApplicationDao applicationDao;
this give spring a hint.
If you are using annotations in your application, you should denote it using a tag :
<mvc:annotation-driven />
Add this line in application context xml above component scan tag.
Also, if you are using annotations, remove ApplicationDao and ApplicationService bean declarations from xml.
And don't mark you service and dao classes with both #Component and #Service or #Repository annotations. No need to mark them #Component there. Remove it.
I am using spring. I need to read values from properties file. This is internal properties file not the external properties file. Properties file can be as below.
some.properties ---file name. values are below.
abc = abc
def = dsd
ghi = weds
jil = sdd
I need to read those values from the properties file not in traditional way. How to achieve it? Is there any latest approach with spring 3.0?
Configure PropertyPlaceholder in your context:
<context:property-placeholder location="classpath*:my.properties"/>
Then you refer to the properties in your beans:
#Component
class MyClass {
#Value("${my.property.name}")
private String[] myValues;
}
To parse property with multiple comma-separated values:
my.property.name=aaa,bbb,ccc
If that doesn't work, you can define a bean with properties, inject and process it manually:
<bean id="myProperties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath*:my.properties</value>
</list>
</property>
</bean>
and the bean:
#Component
class MyClass {
#Resource(name="myProperties")
private Properties myProperties;
#PostConstruct
public void init() {
// do whatever you need with properties
}
}
There are various ways to achieve the same. Below are some commonly used ways in spring-
Using PropertyPlaceholderConfigurer
Using PropertySource
Using ResourceBundleMessageSource
Using PropertiesFactoryBean
and many more........................
Assuming ds.type is key in your property file.
Using PropertyPlaceholderConfigurer
Register PropertyPlaceholderConfigurer bean-
<context:property-placeholder location="classpath:path/filename.properties"/>
or
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath:path/filename.properties" ></property>
</bean>
or
#Configuration
public class SampleConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
//set locations as well.
}
}
After registering PropertySourcesPlaceholderConfigurer, you can access the value-
#Value("${ds.type}")private String attr;
Using PropertySource
In the latest spring version you don't need to register PropertyPlaceHolderConfigurer with #PropertySource, I found a good link to understand version compatibility-
#PropertySource("classpath:path/filename.properties")
#Component
public class BeanTester {
#Autowired Environment environment;
public void execute() {
String attr = this.environment.getProperty("ds.type");
}
}
Using ResourceBundleMessageSource
Register Bean-
<bean id="messageSource" class="org.springframework.context.support.ResourceBundleMessageSource">
<property name="basenames">
<list>
<value>classpath:path/filename.properties</value>
</list>
</property>
</bean>
Access Value-
((ApplicationContext)context).getMessage("ds.type", null, null);
or
#Component
public class BeanTester {
#Autowired MessageSource messageSource;
public void execute() {
String attr = this.messageSource.getMessage("ds.type", null, null);
}
}
Using PropertiesFactoryBean
Register Bean-
<bean id="properties"
class="org.springframework.beans.factory.config.PropertiesFactoryBean">
<property name="locations">
<list>
<value>classpath:path/filename.properties</value>
</list>
</property>
</bean>
Wire Properties instance into your class-
#Component
public class BeanTester {
#Autowired Properties properties;
public void execute() {
String attr = properties.getProperty("ds.type");
}
}
In configuration class
#Configuration
#PropertySource("classpath:/com/myco/app.properties")
public class AppConfig {
#Autowired
Environment env;
#Bean
public TestBean testBean() {
TestBean testBean = new TestBean();
testBean.setName(env.getProperty("testbean.name"));
return testBean;
}
}
Here is an additional answer that was also great help for me to understand how it worked : http://www.javacodegeeks.com/2013/07/spring-bean-and-propertyplaceholderconfigurer.html
any BeanFactoryPostProcessor beans have to be declared with a static, modifier
#Configuration
#PropertySource("classpath:root/test.props")
public class SampleConfig {
#Value("${test.prop}")
private String attr;
#Bean
public SampleService sampleService() {
return new SampleService(attr);
}
#Bean
public static PropertySourcesPlaceholderConfigurer placeHolderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
}
If you need to manually read a properties file without using #Value.
Thanks for the well written page by Lokesh Gupta : Blog
package utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.io.File;
public class Utils {
private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class.getName());
public static Properties fetchProperties(){
Properties properties = new Properties();
try {
File file = ResourceUtils.getFile("classpath:application.properties");
InputStream in = new FileInputStream(file);
properties.load(in);
} catch (IOException e) {
LOGGER.error(e.getMessage());
}
return properties;
}
}
Another way is using a ResourceBundle. Basically you get the bundle using its name without the '.properties'
private static final ResourceBundle resource = ResourceBundle.getBundle("config");
And you recover any value using this:
private final String prop = resource.getString("propName");
You need to put a PropertyPlaceholderConfigurer bean in your application context and set its location property.
See details here : http://www.zparacha.com/how-to-read-properties-file-in-spring/
You might have to modify your property file a bit for this thing to work.
Hope it helps.
I wanted an utility class which is not managed by spring, so no spring annotations like #Component, #Configuration etc. But I wanted the class to read from application.properties
I managed to get it working by getting the class to be aware of the Spring Context, hence is aware of Environment, and hence environment.getProperty() works as expected.
To be explicit, I have:
application.properties
mypath=somestring
Utils.java
import org.springframework.core.env.Environment;
// No spring annotations here
public class Utils {
public String execute(String cmd) {
// Making the class Spring context aware
ApplicationContextProvider appContext = new ApplicationContextProvider();
Environment env = appContext.getApplicationContext().getEnvironment();
// env.getProperty() works!!!
System.out.println(env.getProperty("mypath"))
}
}
ApplicationContextProvider.java (see Spring get current ApplicationContext)
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
#Component
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext CONTEXT;
public ApplicationContext getApplicationContext() {
return CONTEXT;
}
public void setApplicationContext(ApplicationContext context) throws BeansException {
CONTEXT = context;
}
public static Object getBean(String beanName) {
return CONTEXT.getBean(beanName);
}
}
[project structure]: http://i.stack.imgur.com/RAGX3.jpg
-------------------------------
package beans;
import java.util.Properties;
import java.util.Set;
public class PropertiesBeans {
private Properties properties;
public void setProperties(Properties properties) {
this.properties = properties;
}
public void getProperty(){
Set keys = properties.keySet();
for (Object key : keys) {
System.out.println(key+" : "+properties.getProperty(key.toString()));
}
}
}
----------------------------
package beans;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// TODO Auto-generated method stub
ApplicationContext ap = new ClassPathXmlApplicationContext("resource/spring.xml");
PropertiesBeans p = (PropertiesBeans)ap.getBean("p");
p.getProperty();
}
}
----------------------------
- driver.properties
Driver = com.mysql.jdbc.Driver
url = jdbc:mysql://localhost:3306/test
username = root
password = root
----------------------------
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.0.xsd">
<bean id="p" class="beans.PropertiesBeans">
<property name="properties">
<util:properties location="classpath:resource/driver.properties"/>
</property>
</bean>
</beans>
I'll recommend reading this link https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html from SpringBoot docs about injecting external configs. They didn't only talk about retrieving from a properties file but also YAML and even JSON files. I found it helpful. I hope you do too.
SampleBean:
package com.springexample;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class SampleBean {
private BeanTypeOne beanOne;
private BeanTypeTwo beanTwo;
public void init() {
System.out.println("This is from the init() method");
}
#PostConstruct
public void initAnnotation() {
System.out.println("This is from the initAnnotation() method");
}
and config file like this :
<bean id="SampleBean" class="com.springexample.SampleBean">
<property name="beanOne" ref="beanOneOne"></property>
<property name="beanTwo" ref="beanTwoOne"></property>
</bean>
And I don't have default-init-method attribute set on the beans tag.
Can any body tell why the #PostConstruct method does not get called.
You need <context:annotation-config/> (or <context:component-scan/>) to enable #PostConstruct handling.
Is there a way in Spring to create a collection, or array, of beans, based on a comma-separated list of classes. For example:
package mypackage;
public class Bla {
private Set<MyBean> beans;
public void setBeans(Set<MyBean> beans) {
this.beans = beans;
}
}
With the application context:
<bean id="bla" class="mypackage.Bla">
<property name="beans">
<set>
<bean class="mypackage.Bean1, mypackage.Bean2" />
</set>
</property>
</bean>
Preferably the beans are all initialized and wired from the context, leaving the code as simplistic as possible, is this possible?
Use a combination of ApplicationContextAware and ApplicationListener:
public class BeanInitializer implements ApplicationContextAware, ApplicationListener<ContextRefreshedEvent> {
private ApplicationContext context;
private List<Class<?>> beanClasses;
public void onApplicationEvent(final ContextRefreshedEvent event) {
final AutowireCapableBeanFactory beanFactory = this.context.getAutowireCapableBeanFactory();
for (final Class<?> beanClass : this.beanClasses) {
beanFactory.autowire(beanClass, AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
}
}
public void setApplicationContext(final ApplicationContext context) throws BeansException {
this.context = context;
}
public void setBeanClasses(final List<Class<?>> beanClasses) {
this.beanClasses = beanClasses;
}
}
in your spring config, do this:
<bean class="com.yourcompany.BeanInitializer">
<property name="beanClasses">
<list>
<value>com.yourcompany.Type1</value>
<value>com.yourcompany.Type2</value>
<value>com.yourcompany.Type3</value>
</list>
</property>
</bean>
Edited: Actually, if you want comma separated, it will probably be more like this:
<bean class="com.yourcompany.BeanInitializer">
<property name="beanClasses"
value="com.yourcompany.Type1,com.yourcompany.Type2,com.yourcompany.Type3" />
</bean>
I don't know if there is a built-in property editor that converts a comma delimited string to a list of classes but if not you can either create one yourself or change your setter method to accept a string and parse the string yourself