Spring Core

Spring Framework 5 for Java Web Applications

Testing Code

Terminology

Testing Goals

Test Scope Dependencies

JUnit Annotations

Spring Boot Annotations

Best Coding Practice

Naming

SOLID Principals

  1. Single Responsibillity Principal
    • Each class jas a single repsonsibillity
    • No more than a screen full of code per class
  2. Open/Closed Principal
    • Classes should be open for extension but closed for modification
    • Use private getters and setters ONLY when you need them
  3. Liskov Substitution Principal
    • Objects should be replaceable with instances of their subtypes without altering correctness
    • E.g. A sqaure is a rectangle
  4. Interface Segregation Principal
    • Make fine-grained interfaces that are client specific
    • Keep components focused and minimize shared dependencies
  5. Dependency Inversion Principal
    • Abstraction should not depend on details
    • Important that high and low level objects depend on the same abstract implementation

Spring Bean Life Cycle


Shutdown

Container Shutdown -> Disponable Bean's destroy() -> Call custom destroy method -> Terminated


Callback Interfaces

Life Cycle Annotations


Bean Post Processors

Note: The guru admits in all his years he has never used these


'Aware' Interfaces

Spring Bean Scopes

*Only valid in the contex of a web-aware Spring ApplicationContext

No declaration is needed for singleton scope.

In Java configuration use the @Scope annotation. We see the xml configuaration above.

Dependency Injection and IoC

Dependency Injection

How objects obtain dependent objects

The class being injected has no responsibillity in instantiating the object being injected Key Theme: Avoid Tight Coupling

Types of Dependency Injection:

Inversion of Control

A technique to allow dependencies to be injected at runtime

IoC vs DI

Spring Configuration and StereoTypes

Spring Configuration Options

Use one or a combination of the above. They will work seemlessly together to define beans in the Spring Context The industry tends to favor Java based config

Spring Framework Sterotypes

Spring Sterotypes are used to define Spring beans in the Spring context Available Stereotypes: @Component, @Controller, @RestController, @Repository, @Service a921ccad78a354eb9ee1b66204dfffef.png

301c93e6ad11962389eb2f899073a752.png. Repository is cool because Spring will detect platform specific persistence exceptions and re-throw them as Spring exceptions

Reactive Programming

Reactive programming focuses on non-blocking, asynchronous execution

The Reactive Manifesto

Responsive

Resilient

Elastic

Message Driven

Features of Reactive Programming

Reactive Streams

Spring Reactive Types

Docker

What is Docker?

Containers can:

Docker Terminology

7d249b52aac81e51e686581a3420501a.png

Docker Editions

Docker Community Edition

Docker Enterprise Edition

Docker uses the release number of year.month.version.edition (yy.mm.v.ed)

Docker Images

Data Validation with JSR-303

JSR 380 - Bean Validation 2.0

Built in Contstraint Definitions

Hibernate Validator Constraints

Exception Handling

JSR 303

JSR 380 - Bean Validation 2.0

Built in Contstraint Definitions

Hibernate Validator Constraints

Data Binding in Spring

Ex. address.addressLine1 would bind to the addressLine1one of the address property of the PersonBean

Options for Database Intialization

DDL = Data Definition Lang DML = Data Manipulation Lang

Hibernate

*Use with cuation, not reccomended for all production systems

Spring JDBC

JPA

Java Persistance API

Entity Types

The "Owning Side" of a relationship will hold the foreign key in the database.

Fetch Type

Cascade Types

If I delete the parent will the child be deleted as well?

By default, no operations are cascaded

Embeddable Types

Inheritance

Create and Update Timestamps

Spring Boot

Spring boot is sort of a configuration wrapper around the Spring MVC Framework.

Dependency Management

Maven or Gradle are supported. Can be used with Ant, but not reccommended.

Each version of Spring Boot is configured to work with a specific version of Spring Framework. Whenever possible, do not specify versions in POM, allow versions to inherit from parent. Don't override the Spring Framework version!!

Spring Boot Starters

Starters are top level dependencies for popular Java libraries. They will bring in deps for the project and related Spring components (Hibernate, JPA, etc.)

Spring Boot Annotations

Disabling Specific Auto Config

Autoconfig brings in A LOT of configuration classes in supplied Spring Boot Jars To Exlude: @EnableAutoConfiguration(exlude={DataSourceAutoConfiguration.class}). Pass in the parameter -debug for a report of the Autoconfig

Dependency Inversion Principle


Violation (Bad) Example

Consider the example of an electric switch that turns a light bulb on or off.

LightBulb.java

    public class LightBulb {
        public void turnOn() {
            System.out.println("LightBulb: Bulb turned on...");
        }
        public void turnOff() {
            System.out.println("LightBulb: Bulb turned off...");
        }
    }

ElectricPowerSwitch.java

    public class ElectricPowerSwitch {
        public LightBulb lightBulb;
        public boolean on;
        public ElectricPowerSwitch(LightBulb lightBulb) {
            this.lightBulb = lightBulb;
            this.on = false;
        }
        public boolean isOn() {
            return this.on;
        }
        public void press(){
            boolean checkOn = isOn();
            if (checkOn) {
                lightBulb.turnOff();
                this.on = false;
            } else {
                lightBulb.turnOn();
                this.on = true;
            }
        }
    }

Our switch is now ready for use to turn on and off the light bulb. But the mistake we did is apparent. Our high-level ElectricPowerSwitch class is directly dependent on the low-level LightBulb class. if you see in the code, the LightBulb class is hardcoded in ElectricPowerSwitch.

Following the Dependency Inversion Principle

To follow the Dependency Inversion Principle in our example, we will need an abstraction that both the ElectricPowerSwitch and LightBulb classes will depend on. But, before creating it, let’s create an interface for switches. Switch.java

    package guru.springframework.blog.dependencyinversionprinciple.highlevel;
     
    public interface Switch {
        boolean isOn();
        void press();
    }

We wrote an interface for switches with the isOn() and press() methods. This interface will give us the flexibility to plug in other types of switches, say a remote control switch later on, if required. Next, we will write the abstraction in the form of an interface, which we will call Switchable. Switchable.java

    package guru.springframework.blog.dependencyinversionprinciple.highlevel;
     
    public interface Switchable {
        void turnOn();
        void turnOff();
    }

In the example above, we wrote the Switchable interface with the turnOn() and turnoff() methods. From now on, any switchable devices in the application can implement this interface and provide their own functionality. Our ElectricPowerSwitch class will also depend on this interface, as shown below: ElectricPowerSwitch.java

    package guru.springframework.blog.dependencyinversionprinciple.highlevel;
     
     
    public class ElectricPowerSwitch implements Switch {
        public Switchable client;
        public boolean on;
        public ElectricPowerSwitch(Switchable client) {
            this.client = client;
            this.on = false;
        }
        public boolean isOn() {
            return this.on;
        }
       public void press(){
           boolean checkOn = isOn();
           if (checkOn) {
               client.turnOff();
               this.on = false;
           } else {
                 client.turnOn();
                 this.on = true;
           }
     
       }
    }

In the ElectricPowerSwitch class we implemented the Switch interface and referred the Switchable interface instead of any concrete class in a field. We then called the turnOn() and turnoff() methods on the interface, which at run time will get invoked on the object passed to the constructor. Now, we can add low-level switchable classes without worrying about modifying the ElectricPowerSwitch class. We will add two such classes: LightBulb and Fan. LightBulb.java

    package guru.springframework.blog.dependencyinversionprinciple.lowlevel;
     
    import guru.springframework.blog.dependencyinversionprinciple.highlevel.Switchable;
     
    public class LightBulb implements Switchable {
        @Override
        public void turnOn() {
            System.out.println("LightBulb: Bulb turned on...");
        }
     
        @Override
        public void turnOff() {
            System.out.println("LightBulb: Bulb turned off...");
        }
    }

Fan.java

    package guru.springframework.blog.dependencyinversionprinciple.lowlevel;
     
    import guru.springframework.blog.dependencyinversionprinciple.highlevel.Switchable;
     
    public class Fan implements Switchable {
        @Override
        public void turnOn() {
            System.out.println("Fan: Fan turned on...");
        }
     
        @Override
        public void turnOff() {
            System.out.println("Fan: Fan turned off...");
        }
    }

In both the LightBulb and Fan classes that we wrote, we implemented the Switchable interface to provide their own functionality for turning on and off. While writing the classes, if you have missed how we arranged them in packages, notice that we kept the Switchable interface in a different package from the low-level electric device classes. Although, this did not make any difference from coding perspective, except for an import statement, by doing so we have made our intentions clear- We want the low-level classes to depend (inversely) on our abstraction. This will also help us if we later decide to release the high-level package as a public API that other applications can use for their devices.


Summary of the Dependency Inversion Principle

Robert Martin equated the Dependency Inversion Principle, as a first-class combination of the Open Closed Principle and the Liskov Substitution Principle, and found it important enough to give its own name. While using the Dependency Inversion Principle comes with the overhead of writing additional code, the advantages that it provides outweigh the extra effort. Therefore, from now whenever you start writing code, consider the possibility of dependencies breaking your code, and if so, add abstractions to make your code resilient to changes.

Open Closed Principle


Violation (Bad) Example

HealthInsuranceSurveyor.java

package guru.springframework.blog.openclosedprinciple;
    public class HealthInsuranceSurveyor{
        public boolean isValidClaim(){
            System.out.println("HealthInsuranceSurveyor: Validating health insurance claim...");
            /*Logic to validate health insurance claims*/
            return true;
        }
    }

ClaimApprovalManager.java

package guru.springframework.blog.openclosedprinciple;
    public class ClaimApprovalManager {
        public void processHealthClaim (HealthInsuranceSurveyor surveyor)    {
            if(surveyor.isValidClaim()){
                System.out.println("ClaimApprovalManager: Valid claim. Currently processing claim for approval....");
            }
        }
    }

The above follows the single responsibillity principle, but when a new type of insurance claim in introduced the code has to be modified: : Modified ClaimApprovalManager.java

    package guru.springframework.blog.openclosedprinciple;
    public class ClaimApprovalManager {
        public void processHealthClaim (HealthInsuranceSurveyor surveyor)    {
            if(surveyor.isValidClaim()){
                System.out.println("ClaimApprovalManager: Valid claim. Currently processing claim for approval....");
            }
        }
        public void processVehicleClaim (VehicleInsuranceSurveyor surveyor)    {
            if(surveyor.isValidClaim()){
                System.out.println("ClaimApprovalManager: Valid claim. Currently processing claim for approval....");
            }
        }
    }

Coding to the Open Closed Principal

InsuranceSurveyor.java

    package guru.springframework.blog.openclosedprinciple;
    public abstract class InsuranceSurveyor {
        public abstract boolean isValidClaim();
    }
HealthInsuranceSurveyor.java
    package guru.springframework.blog.openclosedprinciple;
    public class HealthInsuranceSurveyor extends InsuranceSurveyor{
        public boolean isValidClaim(){
            System.out.println("HealthInsuranceSurveyor: Validating health insurance claim...");
            /*Logic to validate health insurance claims*/
            return true;
        }
    }

VehicleInsuranceSurveyor.java

    package guru.springframework.blog.openclosedprinciple;
    public class VehicleInsuranceSurveyor extends InsuranceSurveyor{
        public boolean isValidClaim(){
           System.out.println("VehicleInsuranceSurveyor: Validating vehicle insurance claim...");
            /*Logic to validate vehicle insurance claims*/
            return true;
        }
    }

ClaimApprovalManager.java

    package guru.springframework.blog.openclosedprinciple;
    public class ClaimApprovalManager {
        public void processClaim(InsuranceSurveyor surveyor){
            if(surveyor.isValidClaim()){
                System.out.println("ClaimApprovalManager: Valid claim. Currently processing claim for approval....");
            }
        }
    }   

Our insurance system is now open to support more types of insurance claims, and closed for any modifications whenever a new claim type is added.


Summary

Most of the times real closure of a software entity is practically not possible because there is always a chance that a change will violate the closure. For example, in our insurance example a change in the business rule to process a specific type of claim will require modifying the ClaimApprovalManager class. So, during enterprise application development, even if you might not always manage to write code that satisfies the Open Closed Principle in every aspect, taking the steps towards it will be beneficial as the application evolves.

Interface Segregation Principle


Violation (Bad) Example

Consider the requirements of an application that builds different types of toys. Each toy will have a price and color. Some toys, such as a toy car or toy train can additionally move, while some toys, such as a toy plane can both move and fly. An interface to define the behaviors of toys is this.

Toy.java

    public interface Toy {
        void setPrice(double price);
        void setColor(String color);
        void move();
        void fly();
    }

ToyHouse.java

    public class ToyHouse implements Toy {
        double price;
        String color;
        @Override
        public void setPrice(double price) {
            this.price = price;
        }
        @Override
        public void setColor(String color) {
            this.color=color;
        }
        @Override
        public void move(){}
        @Override
        public void fly(){}    
    }

As you can see, it is useless to provide ToyHouse with implementations of move and fly. This also leads to violation of the open closed principle

Following the Interface Segregation Principle

Create interfaces for specific behaviors Toy.java

    package guru.springframework.blog.interfacesegregationprinciple;
     
    public interface Toy {
         void setPrice(double price);
         void setColor(String color);
    }

Movable.java

    package guru.springframework.blog.interfacesegregationprinciple;
     
    public interface Movable {
        void move();
    }

Flyable.java

    package guru.springframework.blog.interfacesegregationprinciple;
     
    public interface Flyable {
        void fly();
    }

Now we can implement classes which only implement interfaces they are interested in.

ToyHouse.java

    package guru.springframework.blog.interfacesegregationprinciple;
     
    public class ToyHouse implements Toy {
        double price;
        String color;
     
        @Override
        public void setPrice(double price) {
     
            this.price = price;
        }
        @Override
        public void setColor(String color) {
     
            this.color=color;
        }
        @Override
        public String toString(){
            return "ToyHouse: Toy house- Price: "+price+" Color: "+color;
        }
    }

ToyCar.java

    package guru.springframework.blog.interfacesegregationprinciple;
     
    public class ToyCar implements Toy, Movable {
        double price;
        String color;
     
        @Override
        public void setPrice(double price) {
     
            this.price = price;
        }
     
        @Override
        public void setColor(String color) {
         this.color=color;
        }
        @Override
        public void move(){
            System.out.println("ToyCar: Start moving car.");
        }
        @Override
        public String toString(){
            return "ToyCar: Moveable Toy car- Price: "+price+" Color: "+color;
        }
    }

ToyPlane.java

    package guru.springframework.blog.interfacesegregationprinciple;
     
    public class ToyPlane implements Toy, Movable, Flyable {
        double price;
        String color;
     
        @Override
        public void setPrice(double price) {
            this.price = price;
        }
     
        @Override
        public void setColor(String color) {
            this.color=color;
        }
        @Override
        public void move(){
     
            System.out.println("ToyPlane: Start moving plane.");
        }
        @Override
        public void fly(){
     
            System.out.println("ToyPlane: Start flying plane.");
        }
        @Override
        public String toString(){
            return "ToyPlane: Moveable and flyable toy plane- Price: "+price+" Color: "+color;
        }
    }

Summary of Interface Segregation Principle

Both the Interface Segregation Principle and Single Responsibility Principle have the same goal: ensuring small, focused, and highly cohesive software components. The difference is that Single Responsibility Principle is concerned with classes, while Interface Segregation Principle is concerned with interfaces.Interface Segregation Principle is easy to understand and simple to follow. But, identifying the distinct interfaces can sometimes be a challenge as careful considerations are required to avoid proliferation of interfaces. Therefore, while writing an interface, consider the possibility of implementation classes having different sets of behaviors, and if so, segregate the interface into multiple interfaces, each having a specific role.

Interface Segregation Principle in the Spring Framework

The Interface Segregation Principle becomes especially important when doing Enterprise Application Development with the Spring Framework.

As the size and scope of the application you’re building grows, you are going to need pluggable components. Even when just for unit testing your classes, the Interface Segregation Principle has a role. If you’re testing a class which you’ve written for dependency injection it is ideal that you write to an interface. By designing your classes to use dependency injection against an interface, any class implementing the specified interface can be injected into your class. In testing your classes, you may wish to inject a mock object to fulfill the needs of your unit test. But when the class you wrote is running in production, the Spring Framework would inject the real full featured implementation of the interface into your class.

The Interface Segregation Principle and Dependency Injection are two very powerful concepts to master when developing enterprise class applications using the Spring Framework.