How does Spring Boot recognize #Scheduled on a subclass' method? - java

Let's take an example of a simple Spring Boot program:
Application.java
#SpringBootApplication
#EnableScheduling
public class Application {
public static void main(String[] args) throws Exception {
SpringApplication.run(Application.class);
}
}
SuperClass.java
public abstract class SuperClass {
#Scheduled(fixedRate = 5000)
public void printSomething() {
System.out.println("this is the super method");
}
}
SubClass.java
#Component
public class SubClass extends SuperClass {
}
According to this answer, only annotations annotated by #Inherited are inherited by subclasses, and #Scheduled does not have such an annotation. So how come this is working?

#Inherited only applies to class types, not methods.
Note that this meta-annotation type has no effect if the annotated
type is used to annotate anything other than a class. Note also that
this meta-annotation only causes annotations to be inherited from
superclasses; annotations on implemented interfaces have no effect.
When Spring scans beans for the #Scheduled annotation (or others), it looks for all methods in the bean class. SubClass has a printSomething so Spring decides it can enhance it with the scheduling behavior.
Spring handles #Scheduled a little differently than the standard proxying mechanism and is able to invoke private methods annotated with it.
Had you overriden the printSomething method in the subclass and omitted the #Scheduled annotation on that declaration, Spring would not have applied the scheduling behavior.

Related

How does spring create proxy for a final class?

Maybe I have some outdated knowledge but it is the same as described here
https://stackoverflow.com/a/2657465/2674303
But now I noticed that this example works without any exceptions:
#Service
#EnableScheduling
public final class MyService {
#PostConstruct
public void init(){
System.out.println("MyService started");
}
#Scheduled(fixedDelay= 1000)
public void scheduleCall() {
System.out.println("scheduleCall");
}
}
Could you pease provide how does it work ?
#Scheduled annotation does not require proxy creation. The mechanism is different. After bean initialization Spring called post-processor ScheduledAnnotationBeanPostProcessor. Post processor searches for all methods annotated with #Scheduled and registers them to TaskScheduller for execution. Method execution will be performed via reflection.
See ScheduledAnnotationBeanPostProcessor source code.
#Scheduled
Processing of #Scheduled annotations is performed by registering a
ScheduledAnnotationBeanPostProcessor. This can be done manually or,
more conveniently, through the task:annotation-driven/ XML element
or #EnableScheduling annotation.
ScheduledAnnotationBeanPostProcessor
Bean post-processor that registers methods annotated with #Scheduled
to be invoked by a TaskScheduler according to the "fixedRate",
"fixedDelay", or "cron" expression provided via the annotation. This
post-processor is automatically registered by Spring's
task:annotation-driven XML element, and also by the
#EnableScheduling annotation.
Autodetects any SchedulingConfigurer instances in the container,
allowing for customization of the scheduler to be used or for
fine-grained control over task registration (e.g. registration of
Trigger tasks). See the #EnableScheduling javadocs for complete usage
details.
#PostConstruct also implemented via post-processor InitDestroyAnnotationBeanPostProcessor when dependency injection performed for bean, method which marked #PostConstruct will be executed thru reflection without proxy.
See InitDestroyAnnotationBeanPostProcessor source code
Summary:
In your example, Spring will create bean without proxy.
In case you will add a proxy-specific annotation, for example, #Transactional you will get an exception that proxy can not be created due to final class java.lang.IllegalArgumentException: Cannot subclass final class com.test.services.MyService
#Service
#EnableScheduling
public final class MyService {
#PostConstruct
public void init(){
System.out.println("MyService started");
}
#Scheduled(fixedDelay= 1000)
#Transactional
public void scheduleCall() {
System.out.println("scheduleCall");
}
}
But the current problem you also can solve to force use JDK dynamic proxy. We need to create an interface for class and set property spring.aop.proxy-target-class = false according to Proxying mechanisms

Spring AspectJ AOP methods not executing

I am trying to add some pre-processing logic using AspectJ in my Spring MVC project. I have a #Before method and the corresponding PointCut in place. However, this method is not getting invoked at all when I invoke any of the methods matching the PointCut.
Here are my classes:
#Aspect
#Configuration
public class ConcurrencyAspectConfig {
#Before("execution(public * com.test.wms.service.dto.PackingDtoApi.*(..))")
public void adviceMethod(JoinPoint joinPoint) {
System.out.println("**** ASPECT START");
}
}
#EnableAspectJAutoProxy
#Configuration
#ComponentScan({SpringConstants.PACKAGE_SPRING})
public class AppConfig {
}
When executing any of the public methods in PackingDtoApi, I am expecting to see the **** ASPECT START message on the console. However, it seems that the Advice method never gets invoked. What could be the reason?
There could be mainly two reasons for your implementation to not work:
Wrong Pointcut expression - Double check your pointcut expression
PackingDtoApi is not a spring bean - Annotate the class with a stereotype annotation like #Component
Note: If this doesn't solve your issue, please share the code for
PackingDtoApi class

Custom Annotation works only for ElementType.METHOD

I'm practising with customs annotations and I want to create a custom annotation that set a Math.random() value to an #Entity field (I know that I can do this in the constructor but I want to do with an annotation)
My Annotation:
#Retention(RetentionPolicy.RUNTIME)
#Target(ElementType.CONSTRUCTOR)
public #interface SetRandomPin {}
2.My Aspect
#Around("#annotation(com.testingAnnotations.annotattions.SetRandomPin)")
public void setUserPin(ProceedingJoinPoint joinPoint) throws NoSuchMethodException {....}
}
In my #Entity when I put #SetRandomPin in the constructor, the method setUserPin is not firing.
Only If I change to ElementType.METHOD and I move my annotation to the UserService.class the method is firing.
I'm stuck here and I can't understand why is working with an ElmentType but not with another one.
Default Spring AOP doesn't offer constructor interception or private/protected methods. You can do it using AspectJ.
From docs
If your interception needs include method calls or even constructors within the target class, consider the use of Spring-driven native AspectJ weaving instead of Spring’s proxy-based AOP framework.

Interfaces are annotated with #Component annotation in spring IoC/DI. What could be the reason?

Some times interfaces are annotated with #Component annotation. Then my obvious reasoning was that classes that implement such interface will be treated as components as well. But if I am right that is not the case.
So what is the purpose of #Component annotation on interfaces.
Annotating an interface with #Component is common for Spring classes, particularly for some Spring stereotype annotations :
package org.springframework.stereotype;
...
#Component
public #interface Service {...}
or :
package org.springframework.boot.test.context;
...
#Component
public #interface TestComponent {...}
#Component is not declared as an inherited annotation :
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
public #interface Component {...}
But whatever, during loading of the context, Spring discovers beans by considering the hierarchy of the annotation declared in the candidate class.
In the org.springframework.boot.BeanDefinitionLoader class (included in the Spring Boot dependency) that loads bean definitions from underlying sources, you can see an example of
org.springframework.core.annotation.AnnotationUtils.findAnnotation() that Spring uses to retrieve annotations in the whole hierarchy of the annotation:
class BeanDefinitionLoader {
...
private boolean isComponent(Class<?> type) {
// This has to be a bit of a guess. The only way to be sure that this type is
// eligible is to make a bean definition out of it and try to instantiate it.
if (AnnotationUtils.findAnnotation(type, Component.class) != null) {
return true;
}
// Nested anonymous classes are not eligible for registration, nor are groovy
// closures
if (type.getName().matches(".*\\$_.*closure.*") || type.isAnonymousClass()
|| type.getConstructors() == null || type.getConstructors().length == 0) {
return false;
}
return true;
}
...
}
Concretely, it means as the #Service annotation is itself annotated with #Component, Spring will consider a candidate class annotated with #Service as a bean to instantiate.
So, your guesswork is right :
Classes that implement such interface will be treated as components as
well.
But this works only for interfaces (such as #Service) that are Java annotations and not for plain interfaces.
For Spring classes, this way of doing makes sense (enriching actual stereotype for example) but for your own beans, using #Component for the interface rather than the implementation will not work and would bring more drawbacks than advantages :
it defeats in a same way the purpose of an interface that is above all a contract. It couples it to Spring and it supposes that you will always have a single implementation of the class. In this case, why using an interface ?
it scatters the reading of the class at two places while the interface doesn't need to have any Spring stereotype.
That is not the case there is no need to adding #component on an interface because it is not a bean as we can't create reference for it.
The main part is actually #autowired where you injection the dependecy.
For example
public interface SortAlog();
public class BubbleSortAlgo();
No we are following the dynamic binding and creating the object of interface but implementation is on the run time.
So #autowired is the one that will create the object internally and we have #component for bubbleSortAlgo and the only candidate for the injection, so it will get reference from there.
I hope I was able to make a point here.

#Conditional not working on inherited classes?

I have a simple class annotated with #Conditional(MyCondition.class)
e.g.:
#Conditional(MyCondition.class)
public class MyBean {
...
}
Then I have a configuration bean which extends this bean:
#Configuration
public class MyConfig extends MyBean {
...
}
It seems that the #Conditional is being ignored and the #Configuration is always processed no matter how the condition would resolve (it's not even called)
As soon as I move the #Conditional annotation to the MyConfig everything works as expected.
From the doc:
The #Conditional annotation may be used in any of the following ways:
as a type-level annotation on any class directly or indirectly
annotated with #Component, including #Configuration classes
as a meta-annotation, for the purpose of composing custom stereotype
annotations
as a method-level annotation on any #Bean method
I would assume the first point applies here, i.e. MyConfig is indirectly annotated with #Configuration. Or does the indirectly refer to other annotations which are annotated with #Conditional?
Thanks for the insight
According to the javadoc of #Conditional
NOTE: #Conditional annotations are not inherited; any conditions from superclasses or from overridden methods are not being considered.
The #Conditional annotation isn't #Inherited and as such it isn't visible on sub classes.

Categories

Resources