Wa05 SpringBoot
Wa05 SpringBoot
environment (es. when user start paying an object need to lock the resources).
Typically, when we create program in the object-oriented model, we split our code between two different
kinds of needs or activities: on one side we have lines of code to implement the business logic (set of
behaviors and data management that are behind the purpose of the application as a whole). On the other
side, we typically need also to write lines of code used for configuring our object graph.
Object are interconnected; sometimes we use element that need to operate on another element. Before
starting really operating, so having the code doing something useful, we need to configure the tree of
objects so that they are properly interconnected. This second part is used to configure or set the
dependencies.
These two parts of code are intermixed and not easy distinguish between each other. When the code
grows, they become more and more interconnected.
So, the idea is to try to split the code base, so that we can leave all the procedural part, the one related to
the business logic and move out the configuration.
We would like to have the configuration being created declaratively, by having some way of saying who
depends on whom. That is the exact idea around which the Spring framework as a set of libraries have been
built. So, we have an object-oriented application where elementary object provides their own
functionalities, but they don’t have inside in the code that describe the behavior, directly the
dependencies. They have references to dependencies and annotation and the framework takes care of
finding out who relying on whom based on the annotations, create the object graph and run the
application.
The programmer is responsible of defining components which make our application, elementary classes
and declare via annotations their dependencies, their configuration, so the set of other components they
are connected to, so the framework will be able when application start, to inspect all the declared
components, instantiate them as necessary and connect one to another, according to what is the
declaration.
We do not need to manually instantiate object, but to instantiate classes and provide suitable annotations
because the container will start looking at all available classes and selecting those that looks important to
the job to be run according to the annotation they have.
This is the basic idea of the Spring framework as a whole. Spring framework is made by a lot of different
libraries.
Spring Boot is one of the layers, that helps us to create applications, a single-entry point that can be packed
as a single file. It is specialized in packaging all the application and the application at the end is one simple
Jar file and we can move it across different deploy environments.
Most of the time the assumption is good and working for us. In any situations, we can override and change
them and define alternatives.
Spring Boot provides a set of pluggable ready-made building block, that are easy to customize and
assemble together they provide a layer of custom code. We have small lines of code with respect to the
overall number of lines of code we run. This is possible because it makes a lot of clever assumption and
deduction looking around what can be necessary, based on what we put on the class. We can also use
project properties to define customizations, so they can be modified easily without require touching the
code base.
Thanks to the fact the Spring boot project is based to the Spring core libraries and the idea of object
container, all available components provided by the programmer or implicitly provided by the framework
are automatically wired together. This is what we usually called convention over configuration (most of the
things are obvious, there is no need to tell them). In most other situations, we need to spell one of the
time all the steps, here we just put a generic idea.
Also, it provides support for building all the project in one single jar, putting together all the useful classes
and assemble everything in one single executable. There is no risk of dropping things along the road.
runApplication is a generic function written by people at Spring Boot which initializes the application
context, so the container of all Java beans we can create.
At the very beginning if there is a @Component, Spring generates it and if there is nothing useful, the
project drops.
In the example in the slide, we can see the Jackson module library that we do not have by default.
The Gradle Boot plugin is what assembles all the many files of the libraries we list and the libraries we
imply. Also, it applies the dependency management plugin, that is the one in charge of connecting together
different components.
Here we have an example of the things that can happen. Here we want to have some business logic. We
want to create a knight capable to rescuing a damsel. The actual implementation of the knight will be
embarking on a damsel rescue quest, a specific quest.
This is possible but has some drawbacks. This class in order to be compiled and tested and executed need
to meet the RescueDamselQuest class. If we create the class as declared it will break because we do not
have the RescueDamselQuest class, and nothing can be done until we create it.
When we create software, we need to create software one piece of a time and tested it; if we create a lot
of classes together, we cannot test them. We need an approach that let me keep things separated.
To prevent it, we need to create two levels: a source code level, so DamselRescuingKnight should not have
a dependency on the other class. But at runtime, since we want it depends on it, we define a Quest
interface and see that RescuingDamselQuest is an instance of the quest and the knight this time instead of
depending on DamselRescuingQuest depends on a quest and somebody later on decide which quest is it.
In this way we can compile the code independently, but we are not able to instantiate the knight anymore
because we do not have any quest.
At this point we can create our quest. We have to make our quest recognizable to the application context,
so we can label the BraveKnight as a @Component. Spring understand it is a component and understand it
needs a component and link it.
runApplication instantiate the application context, search for all components, wires them together and
return a reference to the context, so that if we need it, we can ask for more. At this point we ask if it finds
any Knight.
If we have two Knights (BraveKnight and RescueDamselKnight) in the system, we can have an ambiguity
and the program crash. We can solve it adding extra constraints. Most of the time we do not have this type
of ambiguity and in case there are many alternatives, and we can label them as primary or non-primary.
This is called inversion of control, because instead of having Knight class that knowing exactly at compile
time every instance where it operates, the Knight class only knows it will operate on an interface. The
actual class will be provided at runtime by inspecting existing constraints.
The interface separates two planes: what must be done (the concrete class DamselRescuingQuest class
know what has to be done) from where it must be executed (not our business, it is decided externally, who
uses the quest know when it will be invoked).
More generally, this kind of inversion moving from a directly invocation of an object of our choice, to an
indirect invocation of an object supplied by somebody else. Whoever instantiates the Knight, will have to
provide a quest and that quest will decide the behavior of our Knight.
This happens also on other situation in programming; if we have a graphical user interface, the fact that the
mouse clicked on a given position, emit some events. That piece of code totally ignored who will grad that
event and react to it. Eventually listener will be attached later on, the mouse only notify.
Also, it is typical to the plugin pattern. In chrome we can add a lot of plugins that extend the behavior of
Chrome. If chrome cannot display some type of file, we can add a plugin. The plugin has a common
interface (start method, stop method, …) and doesn’t know who is going to invoke it (hosted in Chrome,
Firefox etc.) but only provide an interface through others can invoke it.
The way in which the injection was performed was via a primary constructor parameter, one of the ways
supported by Spring. We can see another way.
Instead of giving the special parameter RescueDamselQuest (val quest: Quest), we can move the
val into a lateinit var and we label it as @Autowired (if we do not put lateinint it is wrong, the class has not
a value and this is dangerous)
Inversion of control has to do with our choices in code that is we do not directly name the actual
dependent class inside our other class, but we just name an interface.
Inversion of control alone is useless but becomes interesting because there is dependency injection. We
named an interface, but the container takes care of filling the variable, property we defined as instance of
the interface with an actual value. Dependency injection is a program impactor in charge of wiring objects
at runtime instead of compile time.
For that reason, we need to use a dedicated component that is the application context, that is the
machinery which knows about all our object, instantiate them according to their labels, bean components
and whatever and properly wiring as necessary.
What it is interesting is that the container takes into consideration the fact that each object has
dependencies, so it builds a dependency graph and decide who create first and last. If we create a circular
dependency graph it will fail, it will recognize it and stop.
From the code analysis point of view, dependency injection works because we use inversion of control, so
only interfaces are implemented. Objectives are dynamically wired on the basis of declarative pieces of
information. The name they have, the type they have, the annotation they have. There is no computation in
there (no if, for etc.). The framework itself is in charge to make this.
All dependencies are created and kept in a software container. Once everything was created, those objects
will be inspected, properly wired and whatever they need. Once everything is ready, control is returned to
the program, so we have run the runApplication and it returns us the set of wired objects that we can use
and operate with them.
This is in contrast with the naïve approach of the application configuration where the program entry point
is in charge of instantiating programmatically object and all the dependencies making code difficult to read.
Today, we use either explicit configuration based on data type and constructor parameters (mark it as
Controller and add val quest: Quest) or via an implicit bean discovering and autowiring (with lateinit
var and @Autowired).
They are equivalent. The form depends on personal preferences or some constraint that exist. For create
unit test and integration test, jUnit need to have the test constructor without any parameters, so we need
@Autowired.
The third pillar on which the Spring framework was built is the Aspect oriented programming. When we
write programs, there are some lines of code which pertain a specific business we are doing, but there are
others rather generic which are independent on the specific business and apply horizontally on many things
like log. We probably need to log everywhere. Another is transaction management or security. These things
need to be present almost everywhere, they are not bounded with one business aspect.
We call this cross-cutting concerns. They horizontally cut all the application. We can spread those lines of
code along the method, but it makes method unreadable and also makes it difficult to change for example
the log style.
So, we prepare what we need to do in a special class called advice and then we ask to Spring to wire it by
re-writing the byte code dynamically when its loaded so that it appears as if the aspects were fit together
with the source code, but we insert in runtime.
We can create advice that goes before, after, ater-returning, after throwing or around (something before
and something after).
In the example I create a new annotation class called Timed, so that I can label the places where we want
some cross-cutting concerns to be applied. For example, we introduce an annotation and say that we can
apply it to any function. This allows us simply to put @Timed. That annotation will do nothing by itself.
Then we create the second block that is a component. So, Spring boot will automatically instantiate it. This
is not only a component, but also has the @Aspect annotation. When Spring boot find a component that is
an aspect, understand it can use it to rewrite dynamically the code which it has.
This function will receive a parameter generated by spring boot that has a syntactical sugar for saying a
representation of what must be invoked. We store the nanotime in a variable and then invoke the
joint.proceed that invoke the actual function. At the end of the function the final block will be executed in
any case (if the function return or give an error).
We can do it adding for example @Timed on the embarkOnQuest and when method return, we have a
print on the output. To remove it we need to remove the @Timed label, or we drop the @Aspect at all. If
we want to change the way in which the time happen, we only need to change the log aspect, so we can
concentrate some kind of operations in one single place. We use declarativity for expressing the behavior.
In a Spring application, objects are creating by the software container that takes care of dependency
injection and aspect weaving (it is like putting wire together and creating a tissue to having the original
code and the aspect).
How do we create components in Beans? For example, we create a class and label it as @Component. Or
we can label it with other annotations that are derived from component like controller, restController,
service and so on.
When we need something to exist, we can just put a label in front of the class and the class will be
instantiated and if that class needs other classes, they will be wired together.
There is another possibility. One of the many components is @Configuration. Spring boot application is
configuration, so it derives from configuration.
If we have a class that is configuration and has any method inside equipped with @Bean automatically that
method will be invoked, and the return value will be stored as a component. So, we can drop the
@Component from the class and no longer instantiate it because it becomes a component itself.
This gives the possibility also to consider Beans things that are out of our control, like string component.
Apart of the fact that the programmer can use a set of potential components, Spring library comes with a
large number of ready-made components which are potentially included in our code base. Potentially
because they are annotated with some extra feature which makes them candidates if nothing better can be
found 8something more specific or provided by the programmer itself).
Those are components which have some extra annotations which represent a conditional candidate, we
should take into consideration in the ApplicationContext only if some conditions hold, for example if a
programmer does not insert a class like this of it is support a class that the programmer introduce that by
itself is not enough.
Here we have an example. It is a pruned version to have a general idea. This class plays the role of providing
a Java database connectivity driver (something to connect with a relational db). This class provide a driver
when we don’t explicitly provide one. It is @Configuration, so it will be a component if it has some method
with @Beans. It also has @ConditionalOnClass, that means that only if inside the project I can find the
presence of a class called DataSource.class or Jdbctemplate.class it should be considered, otherwise we skip
it.
Also, we need to be sure that there is only one datasource class (@ConditionalOnSingleCandidate),
otherwise this is not a good candidate. It should be autoconfigured after data source autoconfiguration,
that means in the process of considering all the dependencies, data source autoconfiguration should be
properly invoked and resolved, and later on the content of the class will be further inspected
(@AutoConfigureAfter).
Inside the class, we find two inner classes. The first is called NamedPArameterJdbcConfiguration and the
other is JdbctemplateConfiguration. Both are labeled as @Configuraiton, so if the container class is
selecte,c they are processed and their Benas method produce something. In this case we have a method
called t that return a NamedJdbcTemplate which must be dependent on the existence of a JdbcTemplate
and provide the bean providing that there is only a Jdbc template available, and no other parameter called
like that.
Whenever we do not use an application framework and we want to create an object, we have to instantiate
it, provide the dependency and at some point, of time to remove it (dispose it). Typically, for disposing an
Spring is much more sophisticated; it strictly tracks the life cycle of Beans and govern how they behave in
many sub steps.
First, whenever we use Spring, it is the framework that is in charge to instantiate the object. In there is any
annotation in the bean classes or if those elements implement some interfaces, some steps will be inserted
by the ApplicationContext to deal with the life cycle.
The first step the ApplicationContext perform when it bootstraps, it’s reading and locating all beans
definitions. It will simply inspect classes searching for annotations and mark all of them together with the
possible constraints. It builds a kind of dependency graph for the analysis phase.
Once all these readings happen, the ApplicationContext know about which Benas potentially existing, so
instantiate something only if a bean is searched it or if there is some annotation that want to create it
immediately.
This will mean that first an object will be created using the constructor. Clearly this is possible if the primary
constructor has no dependency, otherwise the creation of that beans will be subject first to the list of
parameters the primary constructor requires. Dependencies can be specified both via the constructor
parameter or also internally by defining lateinit var.
Depending on how the bean are declared and located, some special rules may be applied. By default,
Spring considers all beans as singleton, that mean just one instance will be created throughout the whole
lifecycle of the process duration. As soon as a bean is seen if there are no other annotations, Spring will try
to instantiate it and keep that instance for all the duration of the process.
There are several possible scopes. We can have beans bound to a connection, a websocket and so on.
Moreover, the bean classes are inspected to see if implement any kind of interface. If a bean declares to
implement the BeanPostProcessor interface, so it has a method called postPorcessBeforeInitialization, the
ApplicationContext will invoke it passing relevant parameters and so on.
Depending on the kind of beans, they can remain alive until the ApplicationContext will be alive (the entire
application) or related to other scopes if declared.
Whatever kind of class we have, we can easily make it fit the purpose we want.
The way in which it happens depends on various possibilities but typically we have three approaches.
By constructor is usually the preferred way when we have control over the constructor and no constraints
prevent us to do that. The major constraint we have is in test for example. It is very clean.
When we use this kind of dependency if it is not a collection, there should be no ambiguity otherwise we
have an exception that will be thrown. A way of dealing with it is labeling the beans that have multiplicity
with the @Primary annotation for example or we can use the @Profile annotation that requires a label that
is a text (debugging, deploy and so on). So, I give preference to this bean if my compilation have that flag
upon. We define different situations.