Given the following Java class
#Order(12)
#Component
public class MyComponent {
//....
}
what is the equivalent in the Spring XML configuration? I couldn't find anything matching the #Order annotation for the XML based configuration:
<bean class="MyComponent" />
In spring you have 2 choices:
annotation
interface implementation
In your case you will have to go with the second option.
Your class needs to implement Ordered, but this will bind your class with spring API. It's same when using annotation over class.
But if you are using configuration classes, instead of xml config, then you can have plain java beans, and keep all Spring API in configurations.
Example:
#Bean(destroyMethod = "shutdown")
#Order(12)
public ScheduledExecutorService scheduledExecutorService() {
return Executors.newSingleThreadScheduledExecutor();
}
Configuration classes give you the option to separate Spring API(annotations) from your beans.
Related
Is it possible to use #ConstructorBinding bound immutable #ConfigurationProperties beans in an implementation of EnvironmentPostProcessor?
I have an EnvironmentPostProcessor implementation:
#Order(LOWEST_PRECEDENCE)
#EnableConfigurationProperties({KeyVaultCertificatesEnvironmentProperties.class, KeyVaultCertificatesEnvironmentServerSslProperties.class})
public class KeyVaultCertificatesEnvironmentPostProcessor implements EnvironmentPostProcessor {
private KeyVaultCertificatesEnvironmentProperties keyVaultProperites;
private KeyVaultCertificatesEnvironmentServerSslProperties sslProperties;
This implementation must use some #ConfigurationProperties beans. I would like these bean to be immutable. Here is a sketch of the beans
#ConstructorBinding
#ConfigurationProperties(prefix=KeyVaultCertificatesEnvironmentProperties.PREFIX)
public class KeyVaultCertificatesEnvironmentProperties {
//...
}
#ConstructorBinding
#ConfigurationProperties(prefix=KeyVaultCertificatesEnvironmentServerSslProperties.PREFIX)
public class KeyVaultCertificatesEnvironmentServerSslProperties {
//...
}
I don't know how to make it so the two #ConfigurationProperties beans are available to my EnvironmentPostProcessor.postProcessEnvironment implementation. I suspect there may be some timing issues.
Any ideas how I can do this?
Thanks,
Ed
It's not possible to directly use any #ConfigurationProperties beans with an EnvironmentPostProcessor because the ApplicationContext that holds the beans is always created after the Environment. It is, however, possible to use the org.springframework.boot.context.properties.bind.Binder class directly if you want to create a an object from the properties that have been loaded into the Environment so far.
For example, you can have the following class:
public class Certs {
// ... fields
Certs(String first, String second) {
// ...
}
}
and bind it with the following code:
Binder binder = Binder.get(environment);
Certs certs = binder.bind("my.certs", Certs.class).get();
Note that the Certs properties class doesn't use any #ConfigurationProperties or #ConstructorBinding annotations and it has a single constructor. For more complex setups you might need to use the Binder constructor that accepts a BindConstructorProvider.
If you're using Spring Boot 2.4 or above you might want to look into the ConfigDataLocationResolver and ConfigDataLoaders classes. These allow you to support custom imports from an application.properties or application.yaml file. The resolver provides a ConfigDataLocationResolverContext object with a getBinder() method that you can use for reading additional properties. You can read a bit about it in this blog post.
You can also look at the new org.springframework.boot.Bootstrapper interface that was added in Spring Boot 2.4 to help Spring Cloud solve a similar chicken-and-egg problem. There's also a test application in the Spring Boot codebase that might help.
I have a collection of classes which I want to be injected into the Spring application context. However, these classes can only be guaranteed to be annotated with one of a group of annotations I have written - i.e. I can assume it will be annotated with #MyAnnotation, but not #Component.
However, #MyAnnotation forms part of an API for my project, and I don't want to state an explicit dependency of this API on Spring. Thus, I can't annotate #MyAnnotation with #Component in order to have it be transitively picked up by Spring.
Is there a way to tell Spring to additionally include #MyAnnotation in its classpath scanning without adding this dependency to my API?
Currently I'm manipulating the bean definition registry to 'manually' add each class annotated with #MyAnnotation, but I'd prefer to rely on Spring's inbuilt support.
Thanks in advance.
It's possible if you create your own BeanDefinitionRegistryPostProcessor to register your own beans. If you implement the postProcessBeanDefinitionRegistry method, you can add beans to the registry by yourself, for example:
#Component
public class FooFactoryBean implements BeanDefinitionRegistryPostProcessor {
#Override
public void postProcessBeanDefinitionRegistry(BeanDefinitionRegistry registry) throws BeansException {
registry.registerBeanDefinition(..);
}
}
To obtain these bean definitions, you can use the ClassPathScanningCandidateComponentProvider class, which will create BeanDefinition objects for all classes found for a specific filter. In this case, an AnnotationTypeFilter will work:
ClassPathScanningCandidateComponentProvider scanner = new ClassPathScanningCandidateComponentProvider(false);
scanner.addIncludeFilter(new AnnotationTypeFilter(Foo.class));
Set<BeanDefinition> definitions = scanner.findCandidateComponents("com.example.my");
In this example, it will find all classes annotated with #Foo in the com.example.my package.
#Configuration classes and XML based configuration should work for you. Have a look at this tutorial: https://www.tutorialspoint.com/spring/spring_java_based_configuration.htm
But to get your #MyAnnotations picked up is more difficult (see #g00glen00b's answer), and I'm not sure it makes sense if the above mentioned solutions are available.
In a Spring 4 application, we are extending PropertySourcesPlaceholderConfigurer to do some custom task during resolving properties.
To register our new class (MyPropertyConfigurer) o Spring we use the following class:
#Configuration
public class AppConfig {
#Bean
public static PropertySourcesPlaceholderConfigurer
propertySourcesPlaceholderConfigurer() {
return new MyPropertyConfigurer();
}
}
As a matter of curiosity, can I add my new bean to Spring with spring.xml instead of using the #Configuration annotation?
I had the same problem, my problem was fixed simply with placing the bean of my class in my Springbeans.xml file like below:
<beans:bean class="MyPropertyConfigurer"/>
You can very well use a combination of both Spring based xml and java based config in your spring application.
You have to use
#ImportResource({"classpath:sampleapp.xml"})
along with
#Configuration
Look at the sample post below which explains it:
Mixing xml and java config with spring
When I was working with CDI, I could use the #Produces annotation to create a producer method to be called to choose which bean that implemented an interface would be injected by the #Inject annotation .
Now I am working with Spring, but I didn't find anything similar. What I need to use to achieve the same result I had with the #Produces annotation in CDI when I use the #Autowired annotation?
You're looking for #Bean:
#Bean is a method-level annotation and a direct analog of the XML <bean/> element. The annotation supports most of the attributes offered by <bean/>, such as: init-method, destroy-method, autowiring, lazy-init, dependency-check, depends-on and scope.
Example (taken from link above):
#Configuration
public class AppConfig {
//similar to #Produces CDI annotation
#Bean
public TransferService transferService() {
return new TransferServiceImpl();
}
}
I suggest you to pay a read to this: Spring DI and CDI comparative study
Using Spring, one can define classes that implement MessageSourceAware. The container will then inject a MessageSource automatically (see the tail end of this documentation).
Is this a special case or can I use this concept to inject other dependencies too? For instance, can my classes implement the following interface:
public interface MyServiceAware {
void setMyService(MyService service);
}
and then somehow be auto-wired with a suitable bean?
Note: I am using XML configuration exclusively at the moment and I'd be reluctant to move to Java-based annotations.
The *Aware interfaces are handled by a BeanPostProcessor that is automatically registered in the application context (org.springframework.context.support.ApplicationContextAwareProcessor).
You could create and register your own postprocessor to handle MyServiceAware beans.
Remember also that the XML configuration does support autowiring for appropriately configured beans.