I want to conditionally expose repositories annotated with RepositoryRestResource based on a Spring Boot application property which will have an environment-specific value.
I hoped to use something like exported = "${myProperty}" but only a literal true or false is accepted.
The only solution I am currently aware of is implementing a custom RepositoryDetectionStrategy instead.
Is there a simpler way that is similar to annotating a #Bean with #ConditionalOnProperty?
Related
Problem context: in our application we use custom PropertySourcesPlaceholderConfigurer to extend possibilities of EmbeddedValueResolver with custom property sources. I am very inspired of Spring Boot #ConditionalOnProperty and #ConditionalOnExpression and want to use it with custom placeholders.
What I wanted to do was to write custom #Conditional annotation that uses EmbeddedValueResolver to resolve placeholders (${...}). I noticed that ConfigurationClassPostProcessor implements ResourceLoaderAware interface, and ResourceLoaderAware classes are configured later than EmbeddedValueResolverAware ones. So when we initialize ResourceLoaderAware, our EmbeddedValueResolverAware beans are already configured. So potentially solution seems possible.
What I wanted to do next was to write custom Condition that uses EmbeddedValueResolver from ApplicationContext to resolve some property and match it to some value. But the problem is that Condition uses some another context class called ConditionContext which doesn't include EmbeddedValueResolver. Using Environment#resolvePlaceholder doesn't help - seems like Environment doesn't know anything about placeholders that are available through EmbeddedValueResolver.
So, is that possible to use EmbeddedValueResolver with Spring conditionals?
I am trying to understand how beans that we make using #Configuration tends to override the beans that are generated by SpringBoot by default. I have been working on a project where in many cases we create beans for things like ZuulConfigs and the assumption is, whatever we are making shall take precedence over the default generated bean. I have been trying to figure this out but can't. Basically,
Is Spring achieving this via some custom class loader
If not how is this precedence working. Can I give some precedence in similar manner to my beans
Can I generate similar hierarchy in my project,if so how
The help is highly appreciated
Spring AutoConfiguration is used to provide a basic configuration if certain classes are in the classpath or not.
If you want to configure the order in which beans are instantiated by spring you can use
#DependsOn("A")
public class B {
...
}
This would create bean "A", then "B". Hence you can order the configuration depending upon the beans need first to be done. Anyways Spring automatically detects the dependencies by analyzing the bean classes.
for more help check this question
Spring Boot AutoConfiguration Order
Alternative :
There is also "#AutoConfigureOrder" annotation(where you can prioritise the configuration), you can have a look in the code for deeper understanding.
Documentation of AutoConfiguration is here
First of all, class loading and bean creation are two different things. We don't need to create a bean to load a class, however, a class has to be loaded in order to create a bean.
Now, coming back to Spring's example, Spring looks into all the packages configured by #componentScan and creates beans of all the classes annotated with #Bean, #Configuration and/or #Component. Spring's container keeps track of all the beans created and hence, when it encounters user defined bean with same name and class type as default bean, it replaces the original definition with user defined one (e.g. we can create our custom #ObjectMapper to override Spring boot's own instance). You can also use #Primary annotation to make you bean take precedence if another definition with same class exists (documentation here).
Below are the answers for your questions:
Spring uses reflection to load the classes and create instances. Although you can load the classes with your custom class loader (more on that here), you don't need to worry about it for #Configuration.
Yes, you can use #Primary annotation to give your bean a precedence. You can also use #Order(here) to define the creation order for your beans.
With #Primary, #Order and #Qualifier annotation you can define your own hierarchy for bean creation.
Can I give some precedence in similar manner to my beans
Yes.
A) To define a specific order your Configuration classes will be handled (by the way, a Configuration class does not have to be annotated with #Configuration (so-called full definition), but it's enough to be annotated with #Component, #ComponentScan, #Import, #ImportResource or just have a method annotated with #Bean - so-called lite definition), you should
1) add your Configuration Candidates to your SpringApplication's primarySource, for example, in your main method like that
SpringApplication.run(
new Class[]{YourSpringBootApplication.class, Config1.class, Config2.class, ...},
args);
2) and annotate each of your Configuration Candidates with #Order annotation, any other ordering means like Ordered interface, #DependsOn etc will be ignored by ConfigurationClassPostProcessor, the order in the primarySource array will also be ignored.
Then ConfigurationClassPostProcessor will sort your Configuration Candidates and handle them according the #Order annotation value you specified.
B) The precedence can also be achieved by defining your own AutoConfiguration classes. Although both Configuration and AutoConfiguration are handled by the same ConfigurationClassPostProcessor, they are essentially distinctive machineries. To do so
1) define in your classpath /META-INF/spring.factories file and put in the EnableAutoConfiguration section of it your AutoConfiguration classes like that
org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
your.package.AutoConfig1,your.package.AutoConfig2
2) and annotate your AutoConfiguration classes with #AutoConfigureOrder, #AutoConfigureAfter, or #AutoConfigureAfter annotations, any other ordering means again will be ignored.
Like #Strelok pointed out, AutoConfiguration classes, your own and provided e.g. by spring-boot-autoconfigure library alike, will be added to the end of the list of Configuration Candidates.
Remember, however, that the order the Configuration Candidates will be handled by ConfigurationClassPostProcessor does not necessarily coincide with the order the beans defined by the Configuration classes will be created. For example, you might define your Configuration class that overrides TomcatServletWebServerFactory to make your own customization of Tomcat web server like
#Configuration
public class EmbeddedTomcatConfig {
#Bean
public TomcatServletWebServerFactory containerFactory() {
...
return customizedTomcatWebServerFactory;
}
but this method will be called right at the moment when your Spring Boot application decides to create a Web server, regardless of how you defined the precedence for your EmbeddedTomcatConfig Configuration class.
Is Spring achieving this via some custom class loader
There is no need to. Although you could, as always with Spring, define your own ClassLoader for BeanFactory, standard ClassLoader is good enough if everything you need for Configuration in your application is available in the classpath. Please notice, that at first phase ConfigurationClassPostProcessor does not load (i.e. does not resolve) the Configuration candidates classes (otherwise, most of the classes in spring-boot-autoconfigure library will fail to load). Instead it analyzes their annotations with bytecode analyzer, ASM by default. For that purpose, it is just enough to get a binary form, a byte array, of a class to feed it to bytecode analyzer.
Just know this: Spring Boot (specifically) auto configuration classes are always configured last. After all user beans have been created. Spring Boot auto configuration classes almost always use the #ConditionalXXXX annotations to make sure that any beans of the same type/name and other conditions that are configured in your application will take precedence over the Spring Boot auto-configured beans.
If you want your #Component to take precedence over other #Component while scanning all the components by spring, use #Order(Ordered.LOWEST_PRECEDENCE) i.e. the max value to load your component over other.
#Primary is used to give your bean a default preference, we can override the default preference using #Qualifier
I have a Spring Boot Web application exposing rest services.
I'm asking myself how to correctly manage profiles on Filters.
Actually, my app has 2 profiles: dev and prod (you guess what it stands for...)
In prod mode, i have more filters to activate than in dev mode.
My Filters configuration class is the following:
#Configuration
public class FiltersConfig {
#Bean
public FilterRegistrationBean filterRegistrationBean(CompositeFilter compositeFilter){
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setDispatcherTypes(EnumSet.allOf(DispatcherType.class));
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setFilter(compositeFilter);
return filterRegistrationBean;
}
#Bean
#Profile("dev")
public CompositeFilter devCompositeFilter(){
CompositeFilter compositeFilter = new CompositeFilter();
List<Filter> filtersList = new ArrayList<>();
//filtersList.add(filter1());
compositeFilter.setFilters(filtersList);
return compositeFilter;
}
#Bean
#Profile("prod")
public CompositeFilter prodCompositeFilter(){
CompositeFilter compositeFilter = new CompositeFilter();
List<Filter> filtersList = new ArrayList<>();
//filtersList.add(filter1());
compositeFilter.setFilters(filtersList);
return compositeFilter;
}
}
My questions are:
Is it a good practice to add #Profile on method?
Is there a way to force the compiler to exclude classes, methods, etc. annotated with a diferent profiles than the one set as current?
(I don't want my production jar/war populated with unnecessary code!)
Does spring boot provide a clearer way to organize profiles?
thx.
In my own experience, using #Profile in any java code is not a good idea. This is why I think you have to avoid using it in the code:
You can always define property like my.feature-for-the-profile.enabled to achieve the same goal by using profile.
Profiles diverge sometimes, keep every changing configuration as properties give you more control on everything, everywhere.
Spring Boot has a well defined profile-specific externalize properties support (like application-prod.yml). Having profile in you code base will make things more complicated and sometimes misleading.
You can modify or override by using properties more easily than update and recompiling your code.
ProfileCondition (as meta-annotation on #Profile) is not a SpringBootCondition, you can not use /autoconfig to determine is it activated or not.
The bottom line: Define profiles for properties, not for #Configurations nor #Beans.
If you really want to exclude test stuff for your production code, take a look on the documentation of spring-boot-devtools, if your using Maven, you can put all test classes/resources in a separate module, and mark its as <optional>true</optional> or define maven profile for it. Notice, having maven profile and spring boot profile at the same time maybe confusing!
I think it would be better to have configurations for different environments in distinct packages. You don't want to mix your configuration.
The structure might look like this:
config
- Config1.java
- Config2.java
dev
- WebConfig.java
- DataConfig.java
prod
- WebConfig.java
- DataConfig.java
Is it a good practice to add #Profile on method?
It is the spring approach to this problem - so it is in keeping with the spring ecosystem
Is there a way to force the compiler to exclude classes, methods, etc. annotated with a diferent profiles than the one set as current? (I don't want my production jar/war populated with unnecessary code!)
You would have to tune your build to exclude classes - another approach is to configure the beans with id's, and use the ID's and configuration per environment. An approach similar to to
In my experience Profiles are easier
Does spring boot provide a clearer way to organize profiles?
Not that I know of, except the approach in the link above
Spring Boot 1.4 offers some fantastic testing improvements. One is the #DataJpaTest annotation where it wires up just the parts needed for JPA testing. What would the equivalent look like for just wiring up the parts needed for JdbcTemplate tests?
I'm fine constructing my own composite annotation that mimics the #DataJpaTest one.
Good question. Ironically enough, that one was raised during the testing talk yesterday at SpringOne Platform. Let's see what it takes to implement such dedicated test annotation.
TL;DR check the code on github
First of all you need to create the annotation. This annotation reuses some bits from the spring-boot-test-autoconfigure module. You may want to auto-configure an in-memory database (like DataJpaTest does). You also want to make sure that caching is configured and disabled by default (in case you have #EnableCaching on your Spring Boot application). You also want that all your tests are #Transactional by default so you should add that.
Next, you want that slicing effectively kicks in. All you need at this point is a DataSource, a JdbcTemplate, database migrations (flyway/liquibase) and a transaction manager to process #Transactional. To avoid the other auto-configurations to kick in you should add the following:
#OverrideAutoConfiguration(enabled = false)
Then, you want to explicitly enable the auto-configurations above. In order to do so, you add #ImportAutoConfiguration and you add the following content in META-INF/spring.factories
# AutoConfigureDataJpa auto-configuration imports
com.example.test.autoconfigure.jdbc.DataJdbcTest=\
org.springframework.boot.autoconfigure.flyway.FlywayAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.DataSourceTransactionManagerAutoConfiguration,\
org.springframework.boot.autoconfigure.jdbc.JdbcTemplateAutoConfiguration,\
org.springframework.boot.autoconfigure.liquibase.LiquibaseAutoConfiguration,\
org.springframework.boot.autoconfigure.transaction.TransactionAutoConfiguration
The key in spring.factories should match the FQN of your annotation. Whenever Spring Boot finds #ImportAutoConfiguration with no extra attributes, it will look for a key matching the annotation type in spring.factories.
Next up you want to be able to include additional components (component scan) with a filter. In order to do that, you can add #TypeExcludeFilters(DataJdbcTypeExcludeFilter.class) where DataJdbcTypeExcludeFilter is pretty much the same thing as DataJpaTypeExcludeFilter (so we might want to extract a common class for that).
Once you've done that, you only need to add your annotation and your JdbcTemplate is auto-configured for you
#RunWith(SpringRunner.class)
#DataJdbcTest
public class DataJdbcSampleTests {
#Autowired
private JdbcTemplate jdbcTemplate;
...
}
I think the option will be #JdbcTest, you could found further info on doc.
How to enable the #Required annotation in Java (Spring 3.1) ? Not in a xml, but in through Java. Also under which annotation I put this enabling? Under #Feature (in #FutureConfiguration or #Bean (in #Configuration) ?
Edit:
#Feature
public MvcAnnotationDriven annotationDriven(ConversionService conversionService) {
return new MvcAnnotationDriven().conversionService(conversionService)
.argumentResolvers(new CustomArgumentResolver());
}
Does this enables all annotations?
#anubhava's answer works, but he's referenced the Spring 2.0 manual, which is 5 years old.
In XML config, Spring 3.x has a more elegant approach: <context:annotation-config/>. This also enabled a whole other bunch of features that you'll probably want, whereas RequiredAnnotationBeanPostProcessor only enables a few.
See Spring 3.x manual.
If you're using #Bean-style config, then annotations like #Required should already be enabled, since that's how #Bean works. However, it's possible that this is a bug - Spring 3.1 is still in early beta, and big chunks of it are likely to be broken.
Unless you really know what you're doing, I strongly recommend sticking to 3.0.x.
From the Spring manual:
There is one last little (small, tiny)
piece of Spring configuration that is
required to actually 'switch on' this
behavior. Simply annotating the
'setter' properties of your classes is
not enough to get this behavior. You
need to enable a component that is
aware of the #Required annotation and
that can process it appropriately.
This component is the
RequiredAnnotationBeanPostProcessor
class. This is a special
BeanPostProcessor implementation that
is #Required-aware and actually
provides the 'blow up if this required
property has not been set' logic. It
is very easy to configure; simply drop
the following bean definition into
your Spring XML configuration.
<bean class=
"org.springframework.beans.factory.annotation.RequiredAnnotationBeanPostProcessor"/>
Please check: http://static.springsource.org/spring/docs/2.0.x/reference/metadata.html
Use AnnotationConfigApplicationContext if you don't want to use XML:
Standalone application context,
accepting annotated classes as input -
in particular #Configuration-annotated
classes, but also plain #Components
and JSR-330 compliant classes using
javax.inject annotations. Allows for
registering classes one by one
(register(java.lang.Class...)) as well
as for classpath scanning
(scan(java.lang.String...)).
In case of multiple Configuration
classes, Bean methods defined in later
classes will override those defined in
earlier classes. This can be leveraged
to deliberately override certain bean
definitions via an extra Configuration
class.
Sample Code:
ConfigurableApplicationContext applicationContext =
new AnnotationConfigApplicationContext(
"com.mycompany.package1",
"com.mycompany.package2",
"com.mycompany.package3"
// etc.
);
applicationContext.refresh();