How to Configure Dependency Injection in a Library Project?
Let me illustrate this question with the following example.
Maven Library Project
ReservationAPI
com.example.reservation-api
This project contains a convenience class called ReservationApiClient which uses a RestTemplate (from the Spring Framework) for making HTTP calls.
Is it possible to make the RestTemplate field #Autowired in this library project instead of instantiating it myself?
Maven Executable Project
org.company.application
This project is a Spring Boot application and uses the above ReservationAPI as a dependency. This app will create a #Bean for the convenience class ReservationApiClient contained in that library and will then execute its public methods which in turn make HTTP requests.
What is a good strategy and/or best practices for the scenario described above?
You can do this if you include autowiring in your library project although that means it would always need to be used with a Spring application context to get the value unless you also have getter/setter methods to use as well. However, I don't think using RestTemplate as an autowired object makes sense since there is nothing specific about a RestTemplate and unless you name the beans there is only one bean definition for a class. All of the methods for the RestTemplate require the URI there anyhow. So in this case I would just use the bean for your ReservationApiClient in your application.
One other way to do it is if you want to include Spring dependencies in your library (which I guess you already are by using RestTemplate) you can declare your ReservationApiClient as a #Service or #Component and then use the #ComponentScan annotation in your main Spring Boot project to search that library for components to include in the bean registry.
Another option is to use a feature like Spring Boot's Autoconfigure to create factories that use third party libraries and configure them per properties in your application settings. The auto configuration documentation would be a good place to start with this. You can see the starter projects they have on GitHub and then the associated Autoconfigure classes they have associated with these.
Let me know if any of this does not make sense.
Related
I have a spring boot app in which I have added another library (in pom.xml).
This library is also a spring boot library which has created some beans and made the beans available using #Bean. The code snippet in 3rd party library is like this :
#Bean
public CustomObject customObject() {
return new CustomObject();
}
Now, I am using this library in my application, but I dont see this bean registered with my application.
I checked all the beans registered with application Context and also tried loading from application context. But no luck.
What am I missing here? The purpose of this 3rd party library is to check some config and create this bean, so if I have to manually create this bean, it takes away the whole purpose.
This is information is not enough, can you please share your pom file of library that contains CustomObject.
I need to see pom file build section code.
as suggested by #Rohit in comments, I missed to add the package of the class in the 3rd party lib jar under component scan. After adding the package under component scan, issue is resolved.
I have a common project I'd like to import to both a spring boot application and a J2EE application. One of the Objects is a set of attributes set from parameters. In spring boot I'd like to use #Value to set them, for the non-spring platform I have to load the properties with code. I'd like to use the same object for both environments since it's use is pervasive. My attempts to use builders have failed because they inevitably get instantiated before the spring objects.
Who's done this?
Thanks in advance
I'd hoped for something more elegant but maybe I'm spoiled by Spring Boot. I had to replace the #Autowired parameters class with a builder that implements ApplicationContextAware. The setApplicationContext method will instantiate the parameters object if it gets executed (the builder class was loaded by Spring and is aware) or by the simple retrieval of parameters for a non-spring environment.
I am a new user of Spring framework. I am facing some confusion in understanding the difference between core spring framework and spring boot. As far as I understand, Spring boot is a framework which performs the initial setup automatically (like Setting up Maven dependencies and downloading the jar files) and comes with an embedded Tomcat server which makes it ready to deploy in just one click., Whereas, Spring MVC requires manual setup. All the tutorials that I watched for core spring show bean configuration using bean factory which configures the beans using a .XML file. In Spring boot, this bean configuration file is absent. My question is, what is the use of this bean configuration file? I did not find any legitimate use of this file in making a REST service with spring. I didn't see any use of the Application Context, Bean Factory in creating web application. Can someone point out how can bean factory be used in Spring web apps? Is there any fundamental difference between core spring and spring boot other than the additional components?
The Spring application context is essentially the "pool" of beans (service objects, which include controllers, converters, data-access objects, and so on) and related information that define an application; I recommend the reference introduction. In theory, you can get complicated with the context setup and have hierarchical organization and such, but in most real-world cases you just have a single plain context.
Inside this context you need to install all of the beans that provide the logic for your application. There are several possible ways to do this, but the two main ways are by providing XML files with have directives like bean (define an individual bean) or component-scan (automatically search for classes with certain annotations, including #Controller) and by using Java classes annotated with #Configuration, which can use annotations and #Bean methods.
The XML style is generally older, and newer applications mostly use Java configuration, but both provide entries that are collected into the context, and you can use both simultaneously. However, in any application, you have to provide some way of getting the registration started, and you will typically have one "root" XML file or configuration class that then imports other XML files and/or configuration classes. In a legacy web.xml-based application, you specify this in your servlet configuration file.
Spring Boot is, as you said, essentially a collection of ready-to-go configuration classes along with a mechanism for automatically detecting configurations and activating them. Even this requires a configuration root, though! This is the #EnableAutoConfiguration instruction, frequently used through its composite #SpringBootApplication. The application context and configuration mechanisms work normally once Boot finds them and pulls them in. Spring knows where to get started because you give it an explicit instruction to build a context starting with that entry point, usually with SpringApplication.run(MyApplication.class, args).
The embedded-server configuration just happens to be a particular set of configuration that is really useful and comes with one of the Boot starter packages. There's nothing there that you couldn't do in a non-Boot application.
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!
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.