Why does Spring #Scheduled not work with #Bean - spring

I am using Spring Boot and Scheduling.
In Spring, why does this work properly (the method gets called every 5 seconds) -
//#Bean
#Scheduled(fixedRate = 5000)
public void foo() {
System.out.println("bar");
}
But this does not (the method does not get called every 5 seconds) -
#Bean
#Scheduled(fixedRate = 5000)
public void foo() {
System.out.println("bar");
}

A #Bean annotation is used for Java-based configuration to annotate a method, that constructs a bean. It's just wrong annotation and should not be there.

The #Bean annotation is used to define bean instances and must return a result. The #Scheduled annotation belongs on a bean method, not the bean itself, and that method must return void. Also, don't forget to enable scheduling by putting #EnableScheduling on one of your #Configuration classes. For example:
MyConfig.java
#Configuration
#EnableScheduling
public class MyConfig
{
}
MyScheduledJob.java
#Component
public class MyScheduledJob
{
#Scheduled(fixedRate = 5000)
public void doSomething() // Note: Should only return void
{
System.out.println(Instant.now() + ": MyScheduledJob.doSomething() invoked.");
}
}
Output:
2017-01-28T03:08:04.760Z: MyScheduledJob.doSomething() invoked.
2017-01-28T03:08:09.756Z: MyScheduledJob.doSomething() invoked.
2017-01-28T03:08:14.755Z: MyScheduledJob.doSomething() invoked.
2017-01-28T03:08:19.758Z: MyScheduledJob.doSomething() invoked.

The two annotations that you are putting on that method do not make much sense to put together.
#Bean is used to create a singleton for autowiring depdencies across your application. http://docs.spring.io/spring-javaconfig/docs/1.0.0.M4/reference/html/ch02s02.html
#Scheduled is used for scheduling tasks for rerunning.
https://docs.spring.io/spring/docs/current/spring-framework-reference/html/scheduling.html
The reason that this does not make sense is that, generally, your Beans are created at application startup and autowired into their dependencies (done once). In contrast, Schedule implies that you would want this to happen on a regular cadence.

Related

How to call #Scheduled method in only one instance using #PostConstruct

There is job that needs to be done on cron schedule
The same logic as in the job must be performed at the start of the spring boot application, therefore #PostConstruct method is used
Shedlock is used, since it is planned to run the application in multiple instances
The question is: how to make the logic from the #PostConstruct method be called in only one instance and not called in others?
An example of my code:
#Component
#AllArgsConstructor
public class TestJob {
private TestService testService;
#PostConstruct
public void init() {
testService.upload();
}
#Scheduled(cron = "${cron}")
#SchedulerLock(name = "uploadJob", lockAtMostFor = "${lockAtMostFor}")
public void execute() {
testService.upload();
}
}
It should work if you put the #PostConstruct method to a different service and call the execute() method.
The reason is that ShedLock by default uses Spring AOP which wraps each method marked by #SchedulerLock in an aspect that does the locking. And Spring AOP usually does not get applied if you call another method in the same class.

Scheduled method in Spring Boot

I want to send a post request within a period. I created my method like this ;
#Scheduled(cron = "0 0 */6 * *")
#PostMapping
public List<TagsRes> getTags(Date date) {
return null;
}
#Scheduled(cron = "0 0 5 * * ?")
#PostMapping
public List<TagsRes> getAll() {
return null;
}
Should i use #Scheduled in my controller ? Is there any better way to do it?
Thanks!
Controllers are meant to receive web requests, not to post anything.
You can think about them as endpoints exposed by your application and called by external service from time to time.
Now, the Controller abstraction by itself should do any business logic. You may want to validate some parameters received in the request, maybe convert the request parameters to java object with some customization and then call the class (usually mentioned as Service in spring universe) that actually executes your business logic.
Now back to your question.
I suspect you should not "POST a request" but should invoke some piece of code "as if someone called the controller's method (endpoint)". But this time not the external "user" will cause the code execution but an internal scheduler.
If so you can slightly refactor your code to achieve the better clarity:
Create a service that will execute the code
Do not put any scheduling related stuff on controller
From controller call the service
Create a bean and put a "#Scheduled" method on it. The bean will have the service injected and will call it just like the controller does.
Don't forget to put #EnableScheduling annotation - otherwise the scheduled code won't run.
public class MyService {
public void doBusinessLogic(){ ... }
}
#RestController
public class MyController {
#Autowired
private MyService service;
public void myPostMethod(...) {
service.doBusinessLogic(...);
}
}
public class MyScheduledInvoker {
#Autowired
private MyService service;
#Scheduled(...cron expression or whatever...)
public void invokeScheduled() {
service.doBusinessLogic(...);
}
}
#SpringBootApplication
#EnableScheduling
public class MyApp {
public static void main(String [] args) { .... run the app ...}
}
To schedule a job in spring boot application to run periodically, spring boot provides #EnableScheduling and #Scheduled annotations. In my opinion, since spring boot provides the annotation and functionality for scheduler using it will make more sense
Add #EnableScheduling annotation to your spring boot application class.#EnableScheduling is a Spring Context module annotation. It internally imports the SchedulingConfiguration via the #Import(SchedulingConfiguration.class) instruction
#SpringBootApplication
#EnableScheduling
public class SpringBootWebApplication {
}
Now you can add #Scheduled annotations on methods that you want to schedule. The only condition is that methods should be without arguments.
ScheduledAnnotationBeanPostProcessor that will be created by the
imported SchedulingConfiguration scans all declared beans for the
presence of the #Scheduled annotations.
For every annotated method without arguments, the appropriate executor thread pool will be created. This thread pool will manage the scheduled invocation of the annotated method.
#Scheduled(initialDelay = 1000, fixedRate = 10000)
public void run() {
logger.info("Current time is :: " + Calendar.getInstance().getTime());
}
Source: https://howtodoinjava.com/spring-boot/enable-scheduling-scheduled-job-example/

Mockito mock does not work as expected in Spring MockMvc test

In an Spring mockmvc test I want to replace a bean by a mock implementation which is configured using Mockito.when() definitions. The definitions are indeed respected at the time the mock is configured, as well as at the time the mock is injected into a depending bean (a controller advice in my case) during application context startup. However, when the mock is used during a certain test, all when definitions are gone.
Why?
Some remarks:
The mock is completely new code, so it is impossible that I am not aware of any call to Mockito.reset().
the mock at the time of usage is the same as at the time of creation.
a bypassing solution to the problem is to configure the mock in a #BeforeEach method in AbstractTest. However, I want to understand why it does not work without.
Here a simplified and anonymized example
#Component
public class MyBean {
private String property;
...
public String getProperty() {
return property;
}
}
#ControllerAdvice
public class MyControllerAdvice() {
private MyBean myBean;
#Autowired
public MyControllerAdvice(MyBean myBean) {
this.myBean = myBean;
System.out.println(this.myBean.getProperty()); // --> outputs "FOOBAR"
}
#ModelAttribute
public String getMyBeanProperty() {
return myBean.getProperty(); // --> returns null
}
}
public class AbstractTest {
#Configuration
static class Config {
#Bean
public MyBean () {
MyBean myBean = Mockito.mock(MyBean.class, "I am a mock of MyBean");
when(myBean.getProperty()).thenReturn("FOOBAR");
}
}
}
That's not a problem of Mockito. I think you simplified the example a lot and we don't see the full picture, but I can say that main cause - 2 different beans MyBean: one is initialized with Spring's #Component, second is in configuration class with #Bean.
Why do you use #Component for POJO/DO?
#Bean in the configuration class is being initialized lazy so better way to use #PostConstruct
If you want to leave both beans mark MyBean in the configuration class as #Primary

Where to write Common code in spring boot

I want to write common code which should be execute before every method,
Where can I place this code in spring.
Thanks in advance.
What you ask is not trivial but Aspect Oriented Programming (AoP) is one way to achieve that. This description assumes that you are somewhat familiar with the Proxy class, the InvocationHandler interface and the Interceptor pattern in general. As I said, not a totally trivial matter.
Define the logic that you what to be executed before every method, or some method or whatever. Usually it is some kind of Interceptor, this is an example:
public class TimeProfilerInterceptor implements MethodInterceptor {
#Getter
private final TimeStatistics statistics = new TimeStatistics();
#Override
public Object invoke(MethodInvocation invocation) throws Throwable {
StopWatch watch = new StopWatch();
try {
watch.start();
Object returnValue = invocation.proceed();
return returnValue;
}
finally {
// etc...
}
}
}
Define a place where your logic is wired to your methods. In this example, the place is a Spring component that extends AbstractBeanFactoryAwareAdvisingPostProcessor and implements InitializingBean. The afterPropertiesSet method is called by Spring once the initialization of the bean is done. The method uses the Advice class from spring-aop to identify the pointcuts i.e. the methods that must be wrapped by the interceptor. In this case, it is an annotation based pointcut, meaning that it matches every method that has a certain custom annotation on it (TimeProfiled).
#Component
public class TimeProfiledAnnotationPostProcessor
extends AbstractBeanFactoryAwareAdvisingPostProcessor
implements InitializingBean {
#Autowired
TimeProfilerInterceptor timeProfilerInterceptor;
#Override
public void afterPropertiesSet() throws Exception {
this.setProxyTargetClass(true);
Advice advice = timeProfilerInterceptor;
Pointcut pointcut = new AnnotationMatchingPointcut(null, TimeProfiled.class);
this.advisor = new DefaultPointcutAdvisor(pointcut, advice);
}
}
Define your custom annotation to use where needed.
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface TimeProfiled {
}
Tell Spring to initiate the wrapping mechanism at startup via the following annotation upon a Spring Configuration or a SpringBootApplication:
#ComponentScan(basePackageClasses = TimeProfiledAnnotationPostProcessor.class)
#EnableAspectJAutoProxy(proxyTargetClass = true)
You can change the pointcut so that it matches other methods with other criteria, there is an entire syntax to do that, a world in itself, this is just a small example...
You should have a look at Spring AOP. With Spring AOP you can write Aspects which can be common code which is executed before/after a method. The following example is a simple Aspect:
#Aspect
public class EmployeeAspect {
#Before("execution(public String getName())")
public void getNameAdvice(){
System.out.println("Executing Advice on getName()");
}
#Before("execution(* your.package.name.*.get*())")
public void getAllAdvice(){
System.out.println("Service method getter called");
}
}
Within the #Before() annotation you can specify the exact method which is surrounded with the Aspect or you use the wildcard * to specify more methods. For this, you should be familiar with Pointcut expressions.

#Bean annotation on a static method

Can anyone explain me why a #Bean on a static method is returning 2 different instances ?
I can understand that #Bean on a method non static like the class A is returning the same instance because default scope is singleton.
And If I try to inject the class B with #Autowire in a Service it won't work, so it looks like it's not load by the Spring App Context. So using a class like D will be similar !?
I think not because for #PropertySource we need to use in addition (used for the placeholder):
#Bean
public static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
return new PropertySourcesPlaceholderConfigurer();
}
and if we remove #Bean from this, it won't work.
Is there other use case where it would be useful to use #Bean on a static method?
EXAMPLE:
when I run:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {Conf.class})
public class Test {
#org.junit.Test
public void test(){
}
}
for
#Configuration
#ComponentScan
public class Conf {
#Bean
public A aaa(){
return new A();
}
#Bean
public static B bbb(){
return new B();
}
#Bean
#Scope("prototype")
public C ccc(){
return new C();
}
public static D ddd(){
return new D();
}
#PostConstruct
public void post(){
System.out.println(aaa());
System.out.println(aaa());
System.out.println(bbb());
System.out.println(bbb());
System.out.println(ccc());
System.out.println(ccc());
System.out.println(ddd());
System.out.println(ddd());
}
}
public class A {
}
public class B {
}
public class C {
}
public class D {
}
I get:
uk.co.xxx.unit.A#6caf0677
uk.co.xxx.unit.A#6caf0677
uk.co.xxx.unit.B#413d1baf
uk.co.xxx.unit.B#16eb3ea3
uk.co.xxx.unit.C#353352b6
uk.co.xxx.unit.C#4681c175
uk.co.xxx.unit.D#57a78e3
uk.co.xxx.unit.D#402c4085
Because you create a new object for every method call to bbb(). Inter-bean dependencies (if you just call the bean producing method) work in that way, that a proxy is created for your configuration class, and the proxy intercepts method calls to the bean methods to deliver the correct bean (singleton, prototype etc.). However, static methods are not proxied, so when you call the static method, Spring doesn't know about it and you just get the regular Java object. With the PropertySourcesPlaceholderConfigurer it is different, because that method isn't directly called in that class, the bean will only be injected where it is used.
#Bean annotated methods get proxied in order to provide the correct bean instance. Static methods do not get proxied. Hence in your case bbb() invocation each time gives a new instance of B.
PropertySourcesPlaceholderConfigurer class is a special kind of bean since it implements BeanFactoryPostProcessor. In the container lifecycle, a BeanFactoryPostProcessor object must be instantiated earlier than an object of #Configuration-annotated class. Also you don't need to call this static method.
See Bootstrapping section in the java doc : [http://docs.spring.io/spring/docs/4.2.x/javadoc-api/org/springframework/context/annotation/Bean.html][1]
Special consideration must be taken for #Bean methods that return
Spring BeanFactoryPostProcessor (BFPP) types. Because BFPP objects
must be instantiated very early in the container lifecycle, they can
interfere with processing of annotations such as #Autowired, #Value,
and #PostConstruct within #Configuration classes. To avoid these
lifecycle issues, mark BFPP-returning #Bean methods as static

Resources