Spring #Configuration (non-xml configuration) for annotation-driven tasks - spring

Can anyone explain how to do achieve a basic configuration of a task using the #Scheduled annotation without any XML configuration? All the examples I can find use at least a minimal XML configuration. For example:
http://blog.springsource.com/2010/01/05/task-scheduling-simplifications-in-spring-3-0/
This uses a typical:
<context:component-scan base-package="org/springframework/samples/task/basic/annotation"/>
<task:annotation-driven/>
So I'm just using a #Configuration annotation with a bunch of #Bean annotations. They are all instantiated at startup but the one with the #Scheduled does not run. I've used that annotation successfully in the past when using XML configuration, but never with annotations only.

Just add #EnableScheduling on you WebMvcConfig class
#Configuration
#EnableWebMvc
#EnableAsync
#EnableScheduling
public class WebMvcConfig extends WebMvcConfigurerAdapter {
/** Annotations config Stuff ... **/
}

The <task:annotation-driven /> annotation ends up declaring a ScheduledAnnotationBeanPostProcessor to read the #Scheduled annotations in your code. See here: http://static.springsource.org/spring/docs/3.1.x/javadoc-api/org/springframework/scheduling/annotation/ScheduledAnnotationBeanPostProcessor.html.
That takes care of the <task:annotation-driven /> line. To get the component scanning you'll need to use AnnotationConfigApplicationContext. Not sure if/how that works with a web container though.

In Spring 3.0, you still need that little bit of XML. However, Spring 3.1 (still in beta) introduces additional annotation options to close the gap, removing any need for XML config.
See this blog entry for how it's done. Be very careful before using beta versions of Spring in production code, though - they really are unstable.

The answers so far are all helpful for earlier versions of Spring.
Here's one that's a bit more tailored to Spring 4:
Assume that you have your main Application class annotated for Component scan like this:
#ComponentScan({"com.my.class"})
And inside of that package, you have a job class that looks like this:
#Configuration
#EnableScheduling
public class MyJobClass {
#Scheduled (cron = "* * * * * *")
public void runJob() throws DocumentException {
thingsToDoOnSchedule();
}
}
Note that the method that you annotate with #Scheduled must return void and that your cron expression needs to have 6 characters (the example shown here runs every second, which makes testing what your job does easier).
You also need the class level annotations of both #Configuration and #EnableScheduling to make this work. Either by themselves seems to get ignored.
For further reading here is the Spring 4 Enable Scheduling Reference Doc.

Related

IntegrationComponentScan with an explicit basePackages required in Spring Boot?

I have a Spring Boot application (using Spring Boot 2.4.11) where I'm using Spring Integration. I added the org.springframework.boot:spring-boot-starter-integration and hence I expected #IntegrationComponentScan to be active by default. Indeed, I find Issue 2037 that seems to suggest this. Also, I see that annotation on org.springframework.boot.autoconfigure.integration.IntegrationAutoConfigurationScanRegistrar.IntegrationComponentScanConfiguration.
However, my #MessagingGateway annotated interfaces were not taken up by Spring. I tried to add an explicit #IntegrationComponentScan on one of my #Configuration classes, but it didn't work either.
It started to work once I also specified an explicit basePackages value for that annotation, so:
#Configuration
#IntegrationComponentScan(basePackages = "com.example.app.integration")
public class MyConfigurationClass {
}
and of course my annotated interfaces are in a package below com.example.app.integration.
Am I missing something? I couldn't find any reference to #IntegrationComponentScan in Spring Boot documentation. Other similar annotations (like #EnableJpaRepositories for Spring Data or #EntityScan) are not strictly necessary, unless you need to customize the scanning scope.
I also found Issue 3375, that seems to suggest that I should look at #AutoConfigurationPackage, but:
I can't find any mention to this annotation in Spring Boot documentation
I suspect this will apply to ANY other "scan" annotation enabled by Spring Boot, so my basePackages in this case must probably point to some package very close to the "root" of my application
why isn't this annotation required by other #*Scan annotations like the above ones?
I think you need to show your project structure. It work as expected:
I have an interface like com.example.integration.gateway.MyGateway
My main class is in the com.example.integration.IntegrationApplication with a content like:
#SpringBootApplication
public class IntegrationApplication {
It still works even if I have that MyGateway in the com.example.integration package.
To conclude. The #SpringBootApplication is marked with the #ComponentScan where Spring starts scanning components from the package where this #SpringBootApplication is declared and all the way down to its sub-packages.
If your components are in a different from #SpringBootApplication class, then consider to have it customized via its scanBasePackages property:
/**
* Base packages to scan for annotated components. Use {#link #scanBasePackageClasses}
* for a type-safe alternative to String-based package names.
* <p>
* <strong>Note:</strong> this setting is an alias for
* {#link ComponentScan #ComponentScan} only. It has no effect on {#code #Entity}
* scanning or Spring Data {#link Repository} scanning. For those you should add
* {#link org.springframework.boot.autoconfigure.domain.EntityScan #EntityScan} and
* {#code #Enable...Repositories} annotations.
* #return base packages to scan
* #since 1.3.0
*/
#AliasFor(annotation = ComponentScan.class, attribute = "basePackages")
String[] scanBasePackages() default {};
Everything else needs an investigation already inside your project. If you can share that with us, we can take a look and find something.

How is #ConfigurationProperties-annotated classes detected automatically with #SpringBootApplication Annotation

I am learning Spring Boot and have a question with one example in the reference documentation.
Following section of the documentation mentions
6. Using the #SpringBootApplication Annotation
A single #SpringBootApplication annotation can be used to enable those
three features, that is:
#EnableAutoConfiguration: enable Spring Boot’s auto-configuration
mechanism
#ComponentScan: enable #Component scan on the package where the
application is located (see the best practices)
#Configuration: allow to register extra beans in the context or import
additional configuration classes
and the following example to replace this single annotation by any of the features that it enables is bit confusing for me . The example
package com.example.myapplication;
import org.springframework.boot.SpringApplication;
import org.springframework.context.annotation.ComponentScan
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
#Configuration(proxyBeanMethods = false)
#EnableAutoConfiguration
#Import({ MyConfig.class, MyAnotherConfig.class })
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
Explanation for the example
In this example, Application is just like any other Spring Boot
application except that #Component-annotated classes and
#ConfigurationProperties-annotated classes are not detected
automatically and the user-defined beans are imported explicitly (see
#Import).
The only major difference I see in the example code above is that it does not have #ComponentScan annotation. I also read in the comments section of an SO answer (Stephane Nicoll May 5 '17 at 11:07) that #Component annotation is not recommended officially to auto detect #ConfigurationProperties. So my assumption is that Spring framework classes with #ConfigurationProperties are not annotated with #Component.
Also I checked the #SpringBootApplication annotation source and couldn't identify anything that should enable the automatic detection of #ConfigurationProperties annotated classes.
The reference document 2.8.3. Enabling #ConfigurationProperties-annotated types section shows the following way to scan and autodetect #ConfigurationProperties
#SpringBootApplication
#ConfigurationPropertiesScan({ "com.example.app", "org.acme.another" })
public class MyApplication {
}
With all these details , I would like to understand
Why is it explicitly mentioned for this example that #ConfigurationProperties-annotated classes are not detected automatically ? and How is #ConfigurationProperties annotated classes automatically detected when #SpringBootApplication is used.
Additional note : I saw a small difference between the prior version of the documentation and the current one. The following reference is missing the current one
Keep in mind that the #EnableConfigurationProperties annotation is
also automatically applied to your project so that any existing bean
annotated with #ConfigurationProperties is configured from the
Environment
Following is what I understand from my analysis.
#ConfigurationProperties annotated types can be registered to the ApplicationContext by
Annotating the class with #ConfigurationProperties with an
annotation that falls in the scope of #ComponentScan (
#Component, #Service and the like ) . Not recommended as per the comment from Stephane Nicoll , which makes sense to me now.
Using annotation
#EnableConfigurationProperties . For this to
work the class annotated with #EnableConfigurationProperties
should be annotated with an annotation that falls in the scope of
#ComponentScan ( #Component, #Service and the like )
Using annotation #ConfigurationPropertiesScan and by making sure
the classes annotated with #ConfigurationProperties is placed
under its radar. The usage is similar to #ComponentScan .
Now , when we replace #SpringBootApplication with individual annotations that it enables and omit #ComponentScan (as in example) , the #EnableConfigurationProperties way (Point 2) of registering the types with #ConfigurationProperties will not work. This probably answers both my questions on why and how .
This was explicitly mentioned probably because the connection between #EnableConfigurationProperties and #ComponentScan is not that obvious for people like me.
Additional details.
The registration of #ConfigurationProperties annotated types when we use #EnableConfigurationProperties happens through of the EnableConfigurationPropertiesRegistrar class that is imported by the annotation
#Target(ElementType.TYPE)
#Retention(RetentionPolicy.RUNTIME)
#Documented
#Import(EnableConfigurationPropertiesRegistrar.class)
public #interface EnableConfigurationProperties {..}

Make bean only if #EnableScheduling is present

I am working on scheduling library. I am using #EnableScheduling to enable and run schedulers in Spring boot. There are many beans/components that I need in my scheduler. But I want to create the beans only if #EnableScheduling is present in the application. How can I achieve that?
If you take a look at what #EnableScheduling does, you'll see that it imports the SchedulingConfiguration configuration. Within this configuration class, a single bean is defined, called ScheduledAnnotationBeanPostProcessor.
This means that if you use conditionals to check for the existence of the ScheduledAnnotationBeanPostProcessor bean, you can define beans that are only created when #EnableScheduling is present.
For this purpose, we can use the #ConditionalOnBean annotation. For example:
#Bean
#ConditionalOnBean(ScheduledAnnotationBeanPostProcessor.class)
public CommandLineRunner appRunner() {
return args -> logger.info("Scheduling is enabled!");
}

Spring MVC #Value/#ConfigurationProperties working on MainConfig but not on SecurityConfig

I have a simple Spring MVC 5 project, with security layer enabled. Everything works good except the properties loading, only on Security Config.
I let you the scenario so you can see it.
application.properties (located at src/main/resources)
com.company.myapp.prop=myprop
MainConfig.java
#Configuration
public class MainConfig implements WebMvcConfigurer {
#Value("${com.company.myapp.prop}")
private String prop;
#Bean
public MySpecialBean mySpecialBean() {
System.out.println(prop); // output > myprop
return new MySpecialBean();
}
}
SecurityConfig.java
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Value("${com.company.myapp.prop}")
private String prop;
#Bean
public MySpecialSecurityBean mySpecialSecurityBean() {
System.out.println(prop); // output > null
return new MySpecialSecurityBean();
}
}
I don't understand why it's happening. I already switched the #EnableWebSecurity annotation to the app class, try to set the PropertySourcesPlaceholderConfigurer myself, but nothing works.
Do you have any idea what's going on?
From official docs about #PropertySource:
Resolving ${...} placeholders in <bean> and #Value annotations
In order to resolve ${...} placeholders in definitions or #Value annotations using properties from a PropertySource, you must ensure that an appropriate embedded value resolver is registered in the BeanFactory used by the ApplicationContext. This happens automatically when using in XML. When using #Configuration classes this can be achieved by explicitly registering a PropertySourcesPlaceholderConfigurer via a static #Bean method. Note, however, that explicit registration of a PropertySourcesPlaceholderConfigurer via a static #Bean method is typically only required if you need to customize configuration such as the placeholder syntax, etc. See the "Working with externalized values" section of #Configuration's javadocs and "a note on BeanFactoryPostProcessor-returning #Bean methods" of #Bean's javadocs for details and examples.
You should try to add annotation #PropertySource into the your config class.
#Configuration
#PropertySource("classpath:my.properties")
public class MainConfig implements WebMvcConfigurer {}
and then try to access your property in SecurityConfig class
To get full information see official docs
I hope it will help you
This works for me.
I guess you have another class that triggers the application and that is annotated with #SpringBootApplication
Also, your methods mySpecialBean do not return a MySpecialBean instance, so this probably does not even compile.
Is there any other class that you are using? Please advice
Finally got it!
The problem was related with some dependency priorities and unnecessary beans declarations. Getting into details, I'm working with OAuht2 and I started with this tutorial. In the end I've made a mix with this one too (more recent). The problem was related with these #Bean's that don't really need to be declared as beans:
ClientRegistrationRepository
ClientRegistration
OAuth2AuthorizedClientService
Spring was calling these beans before any other configuration, so any properties was not loaded yet. Maybe changing the priority, dependence or even the order would resolve the issue, but as I was analysing the code I found that these methods are only used on security configuration and not really needed along any other part of the app. So I removed the #Bean declaration and all works nice now! At the time these methods are called inside security config the properties are already loaded.
Hope to help someone out there.

How SpringBoot dependency injection works with different type of annotations

I recently started exploring Spring Boot. I see that there are 2 ways to define Beans in Spring Boot.
Define #Bean in the class annotated with #SprinBootApplication
Define #Bean in a class annotated with #Configuration
I am also confused about stereo-type annotation #Repository #Service #Controller etc.
Can someone please explain how dependency-injection works with these annotations?
Yes it is possible.
Either you use #Bean in any of your #Configuration or #SpringBootApplication class or mark the bean classes explicitly with annotations like #Service, #Component #Repository etc.
#Service or #Component
When you mark a class with #Service or #Compoenent and if spring's annotation scanning scope allows it to reach to the package, spring will register the instances of those classes as spring beans.
You can provide the packages to be included/excluded during scan with #ComponentScan
#Bean
#Beans are marked on factory methods which can create an instance of a particular class.
#Bean
public Account getAccount(){
return new DailyAccount();
}
Now in you application you can simply #Autowire Account and spring will internally call its factory method getAccount, which in turn returns an instance of DailyAccount.
There is a simple difference of using #Bean vs #Service or #Compoenent.
The first one makes your beans loosely coupled to each other.
In the #Bean, you have flexibility to change the account implementation without even changing any of the account classes.
Consider if your classes instantiation is a multi-step operation like read properties values etc then you can easily do it in your #Bean method.
#Bean also helps if you don't have source code access to the class you are trying to instantiate.
Spring Boot auto-configuration attempts to automatically configure your Spring application based on the jar dependencies that you have added.
You need to opt-in to auto-configuration by adding the #EnableAutoConfiguration or #SpringBootApplication annotations to one of your #Configuration classes.
You are free to use any of the standard Spring Framework techniques to define your beans and their injected dependencies. For simplicity, we often find that using #ComponentScan (to find your beans) and using #Autowired (to do constructor injection) works well.
One way is to define #Bean in the class annotated with
#SprinBootApplication
If you see #SprinBootApplication it is combination of many annotation, and one of them is #Configuration. So when you define #Bean in the Main class, it means it's inside #Configuration class.
According to Configuration docs :
Indicates that a class declares one or more #Bean methods and may be
processed by the Spring container to generate bean definitions and
service requests for those beans at runtime.
class annotated with #Configuration
When you define #Bean is a class annotated with #Configuration class, it means it is the part of spring configuration all the Beans define in it all available for Dependency-Injection.
I have also seen some code where neither of the 2 above approaches
have been used and yet dependency injection works fine. I have tried
to research a lot on this but could not find any concrete answer to
this. Is this possible?
I am assuming you are talking about Sterio-type annotation. Every sterio type annotation has #Component, according to docs :
Indicates that an annotated class is a "component". Such classes are
considered as candidates for auto-detection when using
annotation-based configuration and classpath scanning.

Resources