How does the EnableAutoConfiguration spring annotation work? - java

I am no fan of gross over abstractions, And i think Spring has committed a major felony.
But I'm willing to overlook it this time if someone can explain the algorithm behind the 'auto' configuration.
Having a look at spring's own javadocs, It doesn't give much away other than saying that it will intelligently guess what you need and something to do about conditional beans.
Does someone know what algorithm is used to determine what needs to be loaded?

In my experience as a Spring Boot user the basic factors for Spring Boot to decide on what auto-configurations will be enabled are:
1) The classes present on the classpath. For example if RabbitMQ and Spring AMQP classes are present, then the RabbitAutoConfiguration will be enabled. The corresponding annotation is #ConditionalOnClass,
2) The presence or not of user defined beans. For example, if all the Spring Data JPA is present on the classpath, Spring Boot will register a LocalContainerEntityManagerFactoryBean bean only if the user has not already done so. The beans registered by the user will 'override' the default ones. The relevant annotation is #ConditionalOnMissingBean
As #DaveSyer mentions, you can of course use Spring Boot without #EnableAutoConfiguration if you want to include the relevant configuration on your own. Or you could use the less drastic solution of the exclude field of #EnableAutoConfiguration. If for example you want Spring Boot to autoconfigure everything except ActiveMQ, you would use #EnableAutoConfiguration(exclude=ActiveMQAutoConfiguration.class)
In my opinion, there is absolutely no felony here! You can use what you want from Spring Boot. When you don't want something it has to offer, you can easily opt out partially or completely!
Also if you want to get a look under the covers, you can add the property
logging.level.org.springframework.boot=DEBUG
to application.properties and Spring Boot will gladly give a detailed report of what was auto-configured and what wasn't

There is some documentation in the Spring Boot Reference Guide. It's not terribly complicated, and I hardly think it's a felony to just include a bunch of #Configuration that you might have written anyway (because that's all it does). Feel free not to use #EnableAutoConfiguration if you prefer to include the individual configurations individually.

Related

Does defining a DataSource bean automatically stop spring auto-config, even if the data source is not annotated with #Primary?

The Spring Boot documentation states that if you add your own DataSource bean, spring will not handle the Auto-configuration anymore.
Basically, I want to have two data sources in my project. I was thinking that I can explicitly config the second ds, and not annotate it with #Primary, and Spring will do the auto-config for the primary data source. After trying to do this without any success and reading the docs, it is still unclear to me what they really mean. Does declaring any bean of type DataSource stop the auto config, even if it's not the primary one? Or is the auto config stopped only if you annotate the bean with #Primary / leave it with the default name (which I believe is simply "dataSource"). I have manually configured the default data source so I know how to do that, but I want to know if it's really necessary.
Thanks, any help would be really appreciated, as I have been stuck on this one for a while now.
The documentation you linked to seems clear to me. Emphasise is mine.
Auto-configuration is non-invasive. At any point, you can start to define your own configuration to replace specific parts of the auto-configuration. For example, if you add your own DataSource bean, the default embedded database support backs away.
#Primary or the bean name is not mentioned at all, so I'm not sure why you would expect it to be relevant.
It even describes in the following paragraph how to run you application so you can see which autoconfigurations are applied and why (not).
If you need to find out what auto-configuration is currently being applied, and why, start your application with the --debug switch. Doing so enables debug logs for a selection of core loggers and logs a conditions report to the console.

Spring Boot: Datasource properties

I have a confusion regarding datasource autoconfiguration in Spring-boot. From what I have read, we have to specify the datasource properties in the form spring.datasource.*. But my application code works fine if I supply property name in the form SPRING_DATASOURCE_*. Is there any reason that I am missing, due to which it works? Please clarify.
I think You've come across a feature of spring boot called Relaxed Binding.
It allows using some "relaxed" rules for binding to ConfigurationProperties. So essentially both ways of definition have the same effect in your application.
Here you can find a link to the relevant chapter in the official documentation
Spring Boot has so-called Relaxed Binding
https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-relaxed-binding which allows you to define configuration in different ways:
acme.my-project.person.first-name
acme.myProject.person.firstName
acme.myProject.person.firstName
acme.my_project.person.first_name
ACME_MYPROJECT_PERSON_FIRSTNAME
The latter is often used when passed via environment variables.

Spring Boot: Determining what autoconfiguration are applied to jersey?

Following the online docs for adding jersey to Sring boot, it appears I just need to include the following package
spring-boot-starter-jersey
Actually, it states that Spring Boot provides automatic configuration by including this package.
Where can I find out what exactly is happening?
If I don't add this package then what is NOT configured?
I tried searching for the package in google but got no specific explanation only saying that it automatically configures, but configures what?
I would like to know a little more of what is happening behind the scenes.
All of the auto-configuration code for all that Spring Boot supports is in the spring-boot-autoconfigure module. If you look through the packages, you will see a jersey package.
The "starter" modules generally do not have any code (of course unless it is a third-party module). How it works is that the code in the auto-configuration has some annotations that are #ConditionalOnXxx, where the condition be anything from a class being on the classpath. If this class is not available, then the auto-configuration will not take place. That's pretty much all adding the jersey starter module does: it adds the jersey dependencies so that the auto-configurer will applied.
Now what exactly is being auto-configured specifically for Jersey? Check out the source for the JerseyAutoConfiguration. Basically what you are going to see is your ResourceConfig being injected into the configurer. From that ResourceConfig, it creates Jersey's ServletContainer (which is the main entry point for Jersey.
Then, depending on our properties configuration, either a FilterRegistrationBean or a ServletRegistrationBean is created as a Spring bean, wrapping Jersey's ServletContainer. Jersey can be created as a Servlet or a Servlet Filter. Whichever one we configure we be used.
And that's it for the Jersey configuration. Spring Boot will get a servlet container (e.g. Tomcat, Jetty) from some other auto-configuration, and take the Filter/ServletRegistrationBean and add the Servlet/Filter to that servlet container.
Also, not really that important, but the auto-configuration also give us some Jackson configuration helpers. For example, instead of configuring our own ContextResolver, we can just configure an ObjectMapper Spring bean.
That's really all you get. It's nothing so spectacular that you couldn't just do it yourself without depending on the auto-configuration.
I would recommend learning a little more about how Spring Boot works to provide the automatic configuration in general.
A good reference is the spring boot reference guide. http://docs.spring.io/spring-boot/docs/1.5.3.RELEASE/reference/htmlsingle/#common-application-properties
You can look at the common application properties in appendix A to see what all spring allows you to configure out of the box.
The Reference guide also gives a high level of what "spring-boot-starter-jersey" if you search for it on the page.
They also have a few samples that you can go through and debug to follow along if that is a way for you to learn.
Hope that gives you a starting point for learning!

Spring boot, how to disable autoconfiguration of springSecurityFitlerChain

I'm studying the Spring Security framework with Spring Boot, and one thing I dislike about boot is it's obscurity. There's so much magic happening, troubleshooting and customization is trial and error, guessing what is configured automatically and where. This is high risk in the security field, as misconfigured system may be compromised.
I would like to replace springSecurityFilterChain with my own implementation. In vanilla Spring I would register DelegatingFilterProxy with a different name in web.xml, and implement corresponding bean. However, Spring boot apparently registers springSecurityFilterChain automatically if jars are present, and now I'm not sure if the auto configuration will back of just by declaring the springSecurityFilterChain in a traditional way, or will this lead to misconfigured system?
Generally, I would like to understand Spring boot better, and not just guessing what is happening, where and how to take control of that area.
There are a lot of preconfigured things, but you can override every single step. The magic of #EnableAutoConfiguration is just convenience. The --debug switch should tell you more what is happening in the background.
http://docs.spring.io/spring-boot/docs/current/reference/html/using-boot-auto-configuration.html
If you use Spring Boot 1.4.x (I'm not sure about previous releases), one of the following would work.
#EnableAutoConfiguration(exclude = {org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration.class})
OR
#SpringBootApplication(exclude = { org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration.class})
OR
In your application.properties file,
spring.autoconfigure.exclude=org.springframework.boot.autoconfigure.security.SecurityFilterAutoConfiguration
Sometimes you may need to exclude the org.springframework.boot.autoconfigure.security.SecurityAutoConfiguration class as well.
Do you really want to disable the whole security chain? I don't see the use case, but if, then you do not need #EnableWebSecurity at all. If you only want to adjust the chain, create a Class annotated with #Configuration and #EnableWebSecurity which is extending WebSecurityConfigurerAdapter. There you can tell who is allowed to do what by overriding configure(HttpSecurity).

Ease of rolling back from Spring Boot to regular Spring and viewing hybrid of Spring Context and configurations while using Spring Boot

I am assessing whether spring-boot and how I could migrate to using it.
One question I have is whether a project that uses spring boot can be converted easily back to a regular spring project which uses the traditional spring configuration files if that is required. This would be useful in my mind for a few reasons.
1) merging with legacy projects, because as I have read moving from legacy spring to spring-boot is somewhat tedious.
2) Obtaining a view of the spring application context file and webapp configuration files to understand what the actual configurations being used are.
Another question I have is regarding the lack of application-context file, is there a way to have some kind of hybrid where there is still an application-context file that can be seen? Part of my concern is that spring-boot auto configures components without us knowing and learning how they are configured and work together.
Spring Boot provides auto-configuration.
When #SpringBootApplication is encountered, it triggers a search of the CLASSPATH for a file called META-INF/spring.factories which is just a regular text file that enumerates a list of Java configuration classes. Java configuration was introduced in 2006 and then merged into Spring 3 in 2009. So it's been around for a long time. These Java configuration classes define beans in the same way that XML does. Each class is annotated with #Configuration and therein you find beans defined using methods (factory methods, or provider methods) whose return value is managed and exposed via Spring. Each such provider method is annotated with #Bean. This tells Spring to consider the method and its return value the definition of the bean.
Spring Boot tries to launch all the Java configurations it sees enumerated in that text file. It tries to launch RabbitAutoConfiguration.class, which in turn provides beans for connecting to RabbitMQ and so on. Of course, you don't want those beans in certain cases, so Spring Boot takes advantage of Spring framework 4's #Conditional mechanism to conditionally register those beans only if certain conditions are met: is a type on the CLASSPATH, is a property exposed through the environment, has there been another bean of the same type defined by the user, etc. Spring boot uses these to only create the RabbitMQ-specific beans if, for example, the dependencies that you would get from org.springframework.boot:spring-boot-starter-amqp are on the CLASSPATH. It also considers that the user may have provided a different implementation of RabbitTemplate in some othe rbean definition (be it XML or Java configuration) so it uses that if it's there.
These java configuration classes are the same sort of Java configuration classes you would write without Spring Boot. BUT... WHY? 80% of the time, the auto-configuration that Spring Boot provides is going to be as good or better than the configuration you would write yourself. There are only so many ways to configure Spring MVC, Spring Data, Spring Batch, etc., and the wager you take using Spring Boot is that the leaders and engineers on those various projects can provide the most sensible 80%-case configuration that you probably don't care to write, anyway.
So, yes you could use Spring Boot with existing applications, but you'd have to move those existing applications to Spring 4 (which is easy to do if you're using the spring-boot-starter-* dependencies) to take advantage of #Conditional. Spring Boot prefers: NO configuration, Java configuration, XML configuration, in that order.
If you have an existing application, I'd do the following:
find out what dependencies you can remove from your Gradle/Maven build and just have taken care of for you with the various spring-boot-starter- dependencies.
add #SpringBootApplication to a root component class. Eg, if your package is a.b.c, put a class Application in a.Application and annotate that with #SpringBootApplication
You can run it as a Servlet 3 application or in an embedded servlet container. It might be easier to just run in a standard servlet container as you take baby steps. Go to http://start.spring.io and make sure to choose war in the packaging drop down. Copy the ServletInitializer class and the specification from the pom.xml to ensure that your application is a .war, not a .jar. Then, once everything works on Spring Boot, rm -rf the Initializer and then revert the Maven build to a simpler .jar using the Spring Boot plugin for extra win.
If your application has lots of existing configuration, import it using #Import(OldConfig.class) or #ImportResource("old-config.xml") on the a.Application configuration class. The auto-configuration will kick in but it will see, for example, that you may have already defined a DataSource so it'll plug that in in the right places. What I like to do now is just start the application up, see if everything's OK, then start removing code in my old Java or XML configuration. Don't remove your business code, but remove things related to turning on parts of Spring. Anything that looks like #Enable..* or ..:annotation-driven/>. Restart and verify things still work. The goal is to let Spring Boot do as much of the heavy lifting as possible. Viewing the source is very handy here so you can see what Spring Boot will try to do for you. Spring Boot will log information on what #Conditional conditions evaluated to true for you. Simply provide --Ddebug=true wen you start the application to see the output. You could also export DEBUG=true then restart your IDE to run it as long as the environment variable is ivsible in your shell.

Categories