Is where a needed dependency is injected by another object.
Refers to the composition of the classes. I.e., We compose classes with DI
in mind.
Pass dependencies by constructor.
- We can set dependencies through constructors, setters or properties (spring will use reflection in this case (DO NOT DO THIS));
Avoid DI
with concrete classes
. Prefer Interfaces
instead because:
- It allows runtime to decide which implementation to inject;
- Follows Interface segregation principle from SOLID;
- Makes code more testable;
- Spring autowires dependencies when injected through constructor;
- Use
@Qualifier
annotation on the constructor parameter to specify whichbean
should be used if there is more than one;- E.g.,
public ConstructorABC(@Qualifier("constructorAbcService") ABCService abcService)
- E.g.,
- Use the
@Primary
annotation when you have multiple beans of the same type and you want one of them to go by default;
Allow dependencies to be selected and injected at runtime. The runtime env (or framework) injects dependencies;
The runtime of our code. I.e., Spring framework's IoC
container.
Spring settings at runtime that define how we wire up things
The interfaces we can implement to make use of bean lifecycle are:
- InitializingBean
- DisposableBean
The annotations to access Spring Bean Lifecycle are:
- @PostConstruct
- PreDestroy
- Xml based
- Introduced in spring framework 2.0;
- Common in legacy spring applications;
- Still supported in spring framework 5.x
- The config file should be placed within
resources
folder; - The config file should be imported through the
@ImportResource("classpath:config-file.xml")
above the@SpringBootApplication
annotation;- xml attribute example:
<bean name="chuckNorrisQuotes" class="guru.springframework.norris.chuck.ChuckNorrisQuotes" />
- The class should be the one to be imported;
- xml attribute example:
- Annotation based
- Introduced in version 3;
- Picked up via 'Component Scans';
- Refers to class level annotations;
@Controller
,@Service
,@Component
,@Repository
;
- Java based (Preferred)
- Introduced in version 3;
- Uses java classes to define Spring Beans;
- Annotation used:
@Configuration
;
- Annotation used:
- Beans are declared with
@Bean
annotation;- Very useful when we want to load an external class as a
Bean
so it can be autowired;
- Very useful when we want to load an external class as a
- Groovy Bean Definition DSL
- Introduced in spring 4;
- Allows us to declare beans in groovy;
- Borrowed from Grails;
Definition: It is a fixed general image or set of characteristics which represent a particular type of person or thing;
Spring stereotypes are used to define Spring Beans in the Spring context;
@Component
(root node in the hierarchy): The class will be created as a Bean;@Controller
: The class has the role of a Spring MVC Controller;@RestController
: Extends@Controller
and adds@ResponseBody
;@Repository
(data layer): The class has a mechanism for encapsulating storage, retrieval, and search behavior which emulates a collection of objects;- When using this annotation spring will catch specific platform exceptions and re-throw them as spring exceptions;
@Service
: The class has an operation offered as an interface that stands alone in the model, with no encapsulated state;- We place a service inside the controller. The service communicates to the database through a repository;
Spring scans the application looking for classes annotated with spring annotations;
Spring starts scanning components from the package where the class with @SpringBootApplication
is located;
To configure spring to scan other packages as well we can add the following annotation below:
@SpringBootApplication
@ComponentScan(basePackages= = { <root.package.name>, "augustovictor.services" })
Ps: When setting this option we overwrite the spring default package scan so we have to inform all of them.
It is a good practice to keep related configurations in one centralized class;
Use the @Configuration
annotation;
Is just a configuration wrapper around the Spring MVC Framework;
To declare a scope we add the @Scope
annotation;
In xml configuration based we use the scope
attribute in the bean
tag;
Singleton (Default): Only one instance of the bean is created in the IoC container;
Prototype: A new instance is created each time the bean is requested;
Request: A single instance per http request. Only valid in the context of a web-aware Spring ApplicationContext;
Session: A single instance per http session; Only valid in the context of a web-aware Spring ApplicationContext;
Global-session: Only in a context of portlets;
Application: Bean is scoped to the lifecycle of a ServletContext; Only valid in a context of a web-aware;
Web-socket: Bean is scoped to the lifecycle of a Web-socket; Only valid in a context of a web-aware;
Custom-scope: Spring Scopes are extensible and we can create our owns by implementing the interface Scope
;
It is not possible to overwrite the scopes Singleton
and Prototype
;
The @SpringBootApplication
includes 3 other annotations:
@Configuration
;@EnableAutoConfiguration
;@ComponentScan
;
To display an auto-configuration report from spring boot: Start the command line parameter --debug
;
To disable specific spring boot configuration classes pass the class name to he exclude
parameter of @EnableAutoConfiguration
annotations;
A good example of this is a database credentials file;
Create a datasource.properties
in resources folder;
We can add env variables through intellij under Run > Edit configurations > Environment
To make use of an env variable we should declarate an @Autowire
Environment variable and access values through env.getProperty("propertyName")
Spring active profiles
Spring boot configuration files
If we create a file applicatio-<profile>.properties
it will overwrite the application.properties
values;
@Lob
: Large object (Blob or clob);@Enumerated
: Consider whether you want to store the value as ordinal or string.- Ordinal values change when we add new elements between values in our enum;
- Ordinal is default;
The owner side of a Many to Many relationship is defined by the mappedBy
attribute (the child entity property that would reference the parent).
- Lazy: Data is not required until referenced;
- OneToMany
- ManyToMany
- Eager: Data is required upfront;
- OneToOne
- ManyToOne
Control how state changes are cascated from parent to child objects;
- Persist: Save operations will cascade to related entities;
- Merge: Related entities are merged when owning entity is merged;
- Refresh: Related entities are refreshed when the owning entity is refreshed;
- Remove: All related entities are removed when owning entity is deleted;
- Detach: Detaches all related entities if a manual detach occurs;
- No longer associated with the hibernate session. So we cannot access lazy associations anymore;
- All: Applies all the above cascade options;
Ps: By default no operations are cascated;
JPA/Hibernate support.
Used to define a common set of properties. E.g.: an order might have a billing address, and a shipping address;
Relational DB does not have the concept of inheritance;
- MappedSuperclass: Entities inherit from a superclass. A table is NOT created for the superclass;
- Single Table (Hibernate default): One table is used for all subclasses;
- Joined Table: Base class and subclasses have their own tables. Fetchin subclass entities require a join to the parent table;
- Table per class: Each subclass has its own table;
JPA supports @PrePersist
and @PreUpdate
via JPA lifecycle callbacks.
Hibernate provides @CreationTimestamp
and @UpdateTimestamp
(Preferred way).
It controls what DDL operations Hibernate will perform on startup;
DDL - Data Definition Language
DML - Data Manupulation Language
Hibernate property is set by the spring property spring.jpa.hibernate.ddl-auto
The options are:
- none: No DDL activity from hibernate; Does not verify the db structure neither;
- validate (use in production): Fail to startup if anything is missing (table or column);
- update: Automatically update db schema based on JPA model;
- create: Automatically create the database;
- create-drop: Drop after application finishes;
Spring boot will use create-drop for embedded databases (hsql, h2, derby) or none for other dbs;
Data (seeds) can be loaded from an import.sql
file (This is a hibernate feature);
- The file must be located on the root of the classpath;
- This will be executed only if Hibernate's ddl-auto property is set to
create
orcreate-drop
;
Spring's datasource initializer via spring boot will by default load schema.sql
and data.sql
from the root o the classpath.
Spring boot will also load from schema-${platform}.sql
and data-${platform}.sql
(set spring.datasource.platform
in properties first).
These configs may conflict with Hibernate's DDL auto property (choose spring approach only); If you have to use both, set hibernate's ddl-auto option to either none or validate;
To reference the tables in scripts we use the lower_snake_case
We can make use of query methods
The objective is to get rid of java boilerplate;
Lombok resolves this by reading annotations and converting them into actual methods when the code is compiled;
Annotations
- @Getter: Generate getters for all properties;
- @Setter: Generate setter for all non-final properties;
- @ToString: Generates a string of classname, and each field separated by commas;
- We can set it to include field names as well;
- Also call the super toString
- @EqualsAndHashCode: Generates implementations of
equals(Object other)
andhashCode()
- By default will use all non-static, non-transient properties;
- Can optionally exclude specific properties;
- @NoArgsConstructor: Will cause compiler error if there are final fields;
- Can optionally force, which will initialize final fields with
0
/ false / null;
- Can optionally force, which will initialize final fields with
- @RequiredArgsConstructor: Generates a constructor for all fields that are final or marked `@NonNull``
- Will throw a NullPointerException if any
@NonNull
fields are null;
- Will throw a NullPointerException if any
- @Data: Generates typical boilerplate code for POJOs;
- Combines @Getter, @Setter, @ToString, @EqualsAndHashCode, @RequiredArgsConstructor
- No constructor is generated if you have already declared one;
- @Value: The immutable variant of @Data
- All fields are made private and final by default;
- @NonNull: Set on parameter of method or constructor and a NullPointerException will be thrown if parameter is null
- @Builder: Implements the builder pattern for object creation
- @SneakyThrows: Throw checked exceptions without declaring in calling method's throw clause;
- @Syncronized: A safer implementation of java's synchronized
- @Log: Creates a java util logger
- Slf4j: Creates a SLF4J logger
Setup
- Add maven dependency
groupId: org.projectlombok
artifact: lombok
Unit tests
-
Code under test: Code we're testing
-
Test fixture: Fixed state of a set of objects used as a baseline for running tests.
- This includes: Input data, mock objects, loading db with known data, etc;
-
Ideal test coverage is within 70%-80%;
-
Should be unity and execute very fast;
-
Should not have external dependencies (No db, no spring context, etc);
Integration test
- Designed to test behaviors between objects and parts of the overall system;
- Much marger scope;
- Can include spring context, db, message brokers, etc;
- will run much slower than unit tests;
Functional tests (End-to-end)
- Test a running application;
- Application is live, likely deployed in a known env;
- Functional touch points are tested (using a web driver, calling web services, sending/receiving messages, etc);
TDD: Write tests first, which wil fail, then code to fix the test;
BDD: Builds on TDD and specifies that tests of any unit of software should be specified in terms of desired behavior or the unit;
Often implemented with DSLs to create natural language tests (JBehave, Cucumber, Spock(preferred))
Example of tests: "Given ...", "When...", "Then..."
Mock: Fake implementation of a classe used for testing. Like a test double.
Spy: Partial mock, allowing us to override select methods of a real class;
Testing goals:
- Have the majority of the tests as unit tests;
- Try to test specific business logic in unit tests;
- Use integration tests to test interactions;
- Think of a pyramid. Base is unit tests, middle is integration tests, and top is functional tests;
Test scope dependencies
- Using spring-boot-starter-test (default from spring initializr will load the following dependencies):
- JUnit
- Spring Test and Spring Boot Test: Utilities and integration tests support for spring boot apps;
- AssertJ
- Hamcrest: Lib for matcher objects;
- Mockito
- JSONassert: Json assertion lib;
- JSONPath: XPath for JSON;
JUnit annotations
- @Test
- @Before
- @After
- @BeforeClass
- @AfterClass
- @Ignore
- @Test(expected = Exception.class)
- @Test(timeout = 10) (10 = seconds)
Spring Boot annotations
- @RunWith(SpringRuner.class)
- @SpringBootTest
- @TestConfiguration: Specifies a spring config for the test
- @MockBean (Uses mockito)
- @SpyBean (Uses mockito)
- @JsonTest
- @WebMvcTest: Used to test web context without a full http server (Tomcat)
- @DataJpaTest: Used to test data layer with embedded database;
- @JdbcTest: Like @DataJpaTest but does not configure entity manager. We would be testing agains a mysql for exemple;
- @DataMongoTest: Configures an embedded MongoDB for testing;
- @RestClientTest: Creates a mock server for testing rest clients;
- @AutoConfigureRestDocks: Allows us to use Spring Rest Docs in tests, creating API docs;
- @BootStrapWith: Configures how TestContext is bootstrapped;
- @ContextConfiguration: Directs Spring on how to configure the context for the test;
- @ContextHierarchy: Creates hierarchy with @ContextConfiguration
- @ActiveProfiles: Set which spring profiles are active for the profile;