I have created a spring boot application to implement Quartz scheduler. In Job class, I want to use some property from application.properties. How to inject that?
I have tried below but getting null:
#Component
public class ScheduleJob implements org.quartz.Job {
private static final Logger LOGGER = LogManager.getLogger(ScheduleJob.class);
public ScheduleJob() {
}
#Value("${ijobs.service.url}")
private String ijobsUrl;
public void execute(JobExecutionContext context) throws JobExecutionException {
LOGGER.info("Job exceution starts--->");
System.out.println("-------------------"+ijobsUrl);
Spring requires annotating the class with #Component for it to manage it (including loading any properties into the class). If you use "new" to create the object, then it is outside Spring's control and it won't inject the dependencies/values into it.
On side note, there is native support for Quartz if using Spring Boot: https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-quartz.html
Firstly, the ScheduleJob class should be annotated with #Component for spring to manage it. Secondly, if you want any property to be injected you could do it in a similar way to how you are injecting value of ijobsUrl.
put your required property in application.properties
#Value("${my.property}")
private String myProperty
Related
I have a configuration properties class that I want to inject into a custom log4j2 RewritePolicy.
e.g.
#Plugin(name = "MyPolicy", category = "Core", elementType = "rewritePolicy", printObject = true)
public class MyPolicy implements RewritePolicy {
private MyPolicyProperties myPolicyProperties; // <-- want to inject/autowire this
public MyPolicy() {}
#PluginFactory
public static MyPolicy createPolicy() {
return new MyPolicy();
}
#Override
public LogEvent rewrite(LogEvent logEvent) {
// do something with myPolicyProperties here
return Log4jLogEvent.newBuilder()
.setLoggerName(logEvent.getLoggerName())
.setMarker(logEvent.getMarker())
.setLoggerFqcn(logEvent.getLoggerFqcn())
// ... etc
.build();
}
}
#ConfigurationProperties("app.mypolicy")
#Getter
#Setter
public class MyPolicyProperties {
private String property1;
private int property2;
// ... etc
}
I've tried implementing an ApplicationListener to reconfigure log4j as described here but was can't seem to get the appender and/or rewritepolicy to configure. Also tried implementing ApplicationContextAware described here but also didn't work.
Is there anyway to access the MyPolicyProperties in MyPolicy?
It can be done but it is almost never pretty. This is because Log4j Plugins are loaded by Log4j's plugin system while Spring Beans are loaded by Spring. Furthermore, they are not instantiated at the same time.
If you are using Spring Boot the very first thing that will happen is for Log4j2 to initialize because SpringApplication requests a Logger. So there would be no way to resolve the Spring Bean at that point as it doesn't exist. Later, Spring's bootstrap process will initialize Log4j again and then during application setup it will initialize once or twice more. During these subsequent initializations the bean may be available.
Depending on the type of application you are using you may be able to locate Spring's ApplicationContext so that you can call getBean() and inject it.
There is no automatic way to do this via an annotation or something similar.
The simplest way to do it is to either add a static method in the target class that gets initialized to reference itself when Spring is initialized or to create another class with a method that initializes a static method to reference the Spring created bean. So Spring will cause these static methods to reference the bean it creates. Then have your Log4j plugin call that static method to get the bean reference. Once it is non-null you can save it in the plugin and after that it should function as you want.
I'm following a tutorial and they #Service a class which in my mind should make it available to the whole application.
Why are the #Autowire-ing the class in Application?
Application:
#Configuration
#EnableAutoConfiguration // todo why not #SpringBootApplication
#ComponentScan
public class QuoteAppWsApplication implements CommandLineRunner {
public static void main(String[] args) {
SpringApplication.run(QuoteAppWsApplication.class, args);
}
#Autowired
private EventBus eventBus; //
#Autowired // todo This is #Service...why is it be Autowired
private NotificationConsumer notificationConsumer;
NotificationConsumer:
#Service
public class NotificationConsumer implements Consumer<Event<NotificationData>> {
#Autowired
private NotificationService notificationService;
#Override
public void accept(Event<NotificationData> notificationDataEvent) { // .getData() belongs to Event<>
NotificationData notificationData = notificationDataEvent.getData(); //TODO Gets data from Event
try {
notificationService.initiateNotification(notificationData);
} catch (InterruptedException e) {
// ignore
}
}
}
#Service is a specialization of #Component. It is an annotation that tells Spring to include this class as a Bean in the Spring context. You can think of this as telling Spring what to pick up and put into the context during component scanning.
#Autowired is Spring's annotation to inject something from the context. You can think of this as you declaring what you want to get out of Spring. In general, you need to use this annotation on any field, constructor, or setter that you want Spring to invoke to supply you with the object that it's managing for the given type.
To answer your question, yes, you need both to declare what you want put into the context and when you want something out of the context.
Also, your first three annotations can be replaced with #SpringBootApplication. This annotation is a meta-annotation, meaning it's an annotation that it shorthand for including a series of other annotations. It's documented to include, among other things, all three of your annotations.
#Component
#PropertySources({ #PropertySource("classpath:mail.properties") })
public class A implements B {
#Value("${mail.team.address}")
private String teamAddress;
// has getter and setters .not shown for brevity.
Now when i call the class i get the value of teamAddress as NULL .But in the property file mail.team.address has some value.
My property file is present under src/main/resource folder
Making a call
A a = new A ();
a.someMethodinClassA();
You can not create instance of class by yourself when you want Spring to resolve #Value annotation.
See documentation:
Note that actual processing of the #Value annotation is performed by a BeanPostProcessor which in turn means that you cannot use #Value within BeanPostProcessor or BeanFactoryPostProcessor types. Please consult the javadoc for the AutowiredAnnotationBeanPostProcessor class (which, by default, checks for the presence of this annotation).
Simple solution for you: just annotate class with any #Component annotation and let Spring to create an instance of your class.
You can't create (with a "new" keywoard) for spring bean. If you do it like this, spring doesn't participate in the object creation and configuration, which means that there is no autowiring, the bean is not in Application Context, etc. And of course, #Value annotation won't be processed among other things
The better way is to inject the class A to the code that you used in your example:
A a = new A ();
a.someMethodinClassA();
Show become:
#Component
public class SomeClass {
private final A a;
public SomeClass(A a) {
this.a = a;
}
public void foo() {
a.someMethodinClassA();
}
}
You should read some basics around spring dependency injection. The class that you have autowired with #Component is scanned via component scanning and its object is created by spring container for you.
that is the reason you should not create the object yourself using new keyword.
wherever in your new class you want to use your class A object you can autowire it as below:
#Component
public class TestC{
private A a; // this object will be injected by spring for you
}
I have a Hibernate Search ClassBridge where I want to use #Inject to inject a Spring 4.1 managed DAO/Service class. I have annotated the ClassBridge with #Configurable. I noticed that Spring 4.2 adds some additional lifecycle methods that might do the trick, but I'm on Spring 4.1
The goal of this is to store a custom field into the index document based on a query result.
However, since the DAO, depends on the SessionFactory getting initialized, it doesn't get injected because it doesn't exist yet when the #Configurable bean gets processed.
Any suggestions on how to achieve this?
You might try to create a custom field bridge provider, which could get hold of the Spring application context through some static method. When provideFieldBridge() is called you may return a Spring-ified instance of that from the application context, assuming the timing is better and the DAO bean is available by then.
Not sure whether it'd fly, but it may be worth trying.
Hibernate Search 5.8.0 includes support for bean injection. You can see the issue https://hibernate.atlassian.net/browse/HSEARCH-1316.
However I couldn't make it work in my application and I had implemented a workaround.
I have created an application context provider to obtain the Spring application context.
public class ApplicationContextProvider implements ApplicationContextAware {
private static ApplicationContext context;
public static ApplicationContext getApplicationContext() {
return context;
}
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
ApplicationContextProvider.context = context;
}
}
I have added it to the configuration class.
#Configuration
public class RootConfig {
#Bean
public ApplicationContextProvider applicationContextProvider() {
return new ApplicationContextProvider();
}
}
Finally I have used it in a bridge to retrieve the spring beans.
public class AttachmentTikaBridge extends TikaBridge {
#Override
public void set(String name, Object value, Document document, LuceneOptions luceneOptions) {
// get service bean from the application context provider (to be replaced when HS bridges support beans injection)
ApplicationContext applicationContext = ApplicationContextProvider.getApplicationContext();
ExampleService exampleService = applicationContext.getBean(ExampleService .class);
// use exampleService ...
super.set(name, content, document, luceneOptions);
}
}
I think this workaround it's quite simple in comparision with other solutions and it doesn't have any big side effect except the bean injection happens in runtime.
I have this HTTP listener subclass
public class MigificSessionListener implements HttpSessionListener {
#Autowired
#Qualifier("notificationThread")
private NotificationThread notificationThread;
#Override
public void sessionDestroyed(HttpSessionEvent hse) {
// here notificationThread value is null
}
}
Value of notificationThread inside sessionDestroyed() is null.
How can i autowire sessionDestroyed inside this class ?
Your MigificSessionListener in not in your spring conext, spring even do not know it exists.
You can use WebApplicationContextUtils to get your spring context from ServletContext
WebApplicationContextUtils.getWebApplicationContext(sessionEvent.getSession().getServletContext())
You can enable Spring AOP with #EnableSpringConfigured and annotate your class with #Configurable. This let spring manage instances which are created outside the spring context with new. You will also need to enable either load-time weaving or compile-time weaving. This is documented in 9.8.1 Using AspectJ to dependency inject domain objects with Spring.
#Configuration
#EnableSpringConfigured
public class AppConfig {
}
#Configurable
public class MigificSessionListener implements HttpSessionListener {
#Autowired
#Qualifier("notificationThread")
private NotificationThread notificationThread;
//...
}
Convert your non-Spring managed class MigificSessionListener into a Spring-managed one by annotating it with #Configurable.
For this annotation to be recognised you need <context:spring-configured/> in your Spring XML config or #EnableSpringConfigured if you are using Spring Java config.
The #Autowired or injection of other dependencies will then succeed.