Monday, 11 January 2021

Understanding Spring and Config It

Spring Framework

Spring is built on the top of JEE. It re-manage the usage of JEE API and releasing developers from some trivial works.

Init a minimal spring project that needs the following major dependencies: 
spring-context: defines the actual Spring Injection Container and has a small number of dependencies: spring-core, spring-expression, spring-Aop, and spring-beans.
spring-core: is the core framework that provides the container required to implement Dependency Injection and inversion of control.

Application context:

ApplicationContext is a sub-interface of BeanFactory; so it is also a BeanFactory. In addition, it needs to know some concepts, Inversion of Control(IOC) and IOC container, Dependency Injection(DI),  and bean metadata.  The concept of IOC is about who is going to drive the car; driving yourself, or hiring a driver driving for you. That is the inversion of control. In another word in the software, who is going to inject the dependencies; injecting yourself, or leaving a container injecting for you. We leave the controls of creating an instance and its dependencies to a container, so as to dissolve client code from coupling with the underlying dependencies. 

The application context acts as the heart of the Spring framework. It encapsulates the bean factory,  and loading bean metadata externally for bean creation;  it provides a mechanism for the creation of beans in the correct order, meanwhile providing all beans dependency injections;  beans are created as the application startup, and managed in an IOC container ready for providing bean reference when the code request for it.

Developers mainly config IOC container and leaving bean creations to the container. By this way, it decouples class dependencies and leaving all of these couplings within the container. We use a kind of metadata or whatever it is called to tell the IOC container which beans are needed and their dependencies, just like a blueprint that depicts how an instance is created.  For the client-side code, it uses the @Autowire to request IOC container at the point it needs an instance reference. It means that the IOC container needs to provide the instance reference and assemble its all dependencies, i.e. it is also called Dependency Injection(DI)


DI and IOC container:  

Injection means that at a point that the code needs to refer to an instance, it requests the container and achieves its reference. All DI is handled by the bean factory, which is in charge of figuring bean dependencies, and in charge of assembling all these beans together and return the root reference to the client.  

IOC container manages dependent classes and their instances in a graph. It wires all class dependencies once and re-uses it as any point.  It, therefore, reducing a lot of repeated work and removes the coupling of classes from the client code.

DI and IOC are carried by two Spring packages, i.e. Spring core and Spring context. At a minimum, if you include these two packages in your project, then you may implement DI.

Configuring Application Context

Configuring Spring differently for different deployments, which may include different beans, different properties, different databases etc.

We looked at multiple ways of activating profiles. Let's now see which one has priority over the other and what happens if you use more than one, from highest to lowest priority:

  1. Context parameter in web.xml
  2. WebApplicationInitializer
  3. JVM system parameter
  4. Environment variable
  5. Maven profile 

Profiles:

@Profile is applied with @Configuration or individual bean method level.

@Profile("!dev")
@Bean

Spring Core Property together,  i.e. spring.profiles.active = 'dev', indicates that the 'dev' profile is activated. It realises that the configurations, beans, or properties can be switched according to the activated profile.

It is able to activate a @Profile externally during application start-up.

JVM system parameter:
-Dspring.profiles.active=dev

Program argument:
spring.profiles.active=dev

Environment variable:
in UNIX: export spring_profile_active=dev
or in IDE edit Configurations: set Environment variable; spring.profiles.active=dev

Application property file:
spring.profiles.active=dev

Command line parameter:
java -jar any.jar --spring.profiles.active=dev

Spring profile can be activated via Maven profiles, by specifying spring.profiles.active configuration property.

ref. to https://www.baeldung.com/spring-profiles

Using @ActiveProfile in Tests, making it easy to specify what profiles active.

Value injection: 
@Value is used for injecting property into the code. It is used in the fields or method arguments.
It may inject a value object from a property file or system or environment variables.

Spring expression language(SpEL) 

SpEL is an expression language that supports querying and manipulating an object graph at runtime. It is a single well supported within the Spring community, but it is self-contained and can be used independently. SpEL supports calling methods, accessing properties, and calling constructors.

We often use SpEL for Annotation Configuration; like putting a default value on fields, methods, and method or constructor parameters. 
@Value("#{new Boolean(environment['spring.profiles.active']!='dev')}")
private boolean is24Hours;
Spel can do a logic operation, may be helpful.

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions

Proxies

Proxy is a pattern, it is used to add behaviours to classes. Spring uses a lot of proxies to add aspected behaviours, for instance, transaction boundaries, security check,  logging, cache etc.  

Spring uses both JDK and CGLib-based proxies in its operations. JDK uses an interface to generate a proxy class in order to wrap the target class, but CGLib extends directly from the target class and overriding the point-cut. 

Bean Scopes

Bean scopes are critical concepts for understanding Spring in depth.

  • Singleton:  By default, all classes decorated by @Component are instantiated as a singleton, namely one instance per spring application context.  It needs to watch out states shared across the user of the bean.
  • Prototype;  Bean definition stored in IOC;  new instance every time it is referred. The definition is stored in IOC.
  • Session: It applies to web environment only. Session scope means one instance of a bean per user session.  Definition of the bean is stored in an IOC container when a session is created, the bean is created.
  • Request:  It applies to web environment only. Within a user session, the user may trigger several HTTP requests. A request scoped bean has a life cycle as the request where it is spawned.

Component Scanning

There are three ways to provide bean factory blueprints, i.e. an XML fileJava-based config, or Component scanning. Today, component scanning is the favourite for defining bean metadata. 

Component scanning(@ComponentScan) scans a base package(com.xxx.xxx) and load classes decorated by @Component or its derivatives(@Service, @Repository, etc) into the bean factory.  @ComponentScan without arguments tells Spring to scan the current package and all of its sub-packages.

Using @ComponentScan annotation along with @Configuration annotation together may bring Java-based blueprints and Component scanning metadata together to BeanFactory via an ApplicationContext.

In SpringBoot, using @SpringBootApplicatoin includes the component scanning by default. @ComponentScan(basePackages="xxx.zzz.yyy") defines the entry to scan for components.  Properties file can be scanned and loaded @PropertySource("classpath: application. properties"), it externally defines a location of customer property files

In a component scanning process, it builds up the dependency graph automatically according to component dependencies,  also called Dependency Injection(DI). From the client-side of beans, it is referred to as an auto-wiring process using @Autowired annotation at the point that the code needs the reference of the instance. IOC container and DI build up bean graph for clients and can be reused many times afterwards. This is a big saving. 

Using @Qualifier or @Primary to solve type ambiguity, because of one type having more than one implementation.

Component scanning is also used with conditional configuration.

Lifecycle methods: 

Leveraging JSR-250, not Spring specific. 

Post Construction (@PostConstruct) means to do something before a bean become use phase. It must be a void method without arguments. It is called after property setting is completed. it is used to init.

Pre Destroy(@PreDestroy) means to do something before the application context closes. The method is called before the application context is about to remove the bean. The method may be used to close the opened resources.

Both of them not included after java 9. 


Bean Life Cycles

There are three phases, initialization, use(interacting with Spring IOC container), and deconstruction. The most time of life cycle is spent during the use phase; the most complicated phase is the initialization, and deconstruction is the end of the life cycle. The following diagram illustrates the initialization. It begins with the creation of the application context and follows up with the bean factory initialization phase and bean initialization and instantiation. It is a phase we can impact the behaviour of application most. 

Init phase:  creating of App context => bean factory initialization phase=>bean initialization and instantiation

Load bean definitions: 

Bean definition loaded: 

The first step loading bean definition into the bean factory from all sources:
  1. Java configuration(@Configuration,@Bean,@Value, @DependsOn,@Import)
  2. XML configuration; not often used now. 
  3. Component scanning and auto-configuration. (@ComponentScan,@Component)
You can do all of them, but the best is to pick up one and stick with it.  The bean definition (class metadata); at the point, has been loaded, and instance references are created, however, instances have not been created. It is import to know that at this phase there is no bean having been instantiated.  At this phase, the bean factory contains bean metadata. and bean references.

Post-process bean definitions:

BeanFactory Post-Processors: Before bean instantiation, and after bean definition loading. This phase allows modifying any bean in the factory prior to instantiation. One of the most familiar examples of this is the  PropertySourcesPlaceholderConfigurer

Bean postprocess is the first extension point, allowing to impact bean factory. You can extend from the BeanFactoryPostProcessor to write a custom code to do something to beans or a subset of beans. 
It is not common to write your won, but it is good to understand you can use this to your advantage. It is very common to use existing ones(registering scope, properties)

Bean factory post-processors(BFPP) and bean definitions must be static; removing risks of side effects of dynamic instances.

At the end of this stage, the bean factory is loaded with references; the bean factory and all beans are configured; all system-level work is completed in Spring; It is ready for the next stage. 

Instantiation phase: 

for each bean Bean factory need to do: 

Construction

Beans are instantiated using constructors; Done in the correct order to ensure dependencies are created first; Creating only singletons at this  point, anything other than a singleton bean will not be constructed because they are prototype or session beans;

Eager vs. Lazy
By default, all beans are instantiated eagerly. To truly be lazy, there can be nothing that depends on them. Even you label a bean as a lazy bean, the application context reserve the right to ignore.

At the end of this phase, bean reference is still kept inside the Bean Factory; instances have been constructed, but not ready for use yet.

Setters:

post-initialization DI should only be done on optional beans or dynamic beans.
Autowiring occurs(non-constructor based)

This is another chance to auto-wire after beans having been instantiated.  Autowiring occurs on setters with @Autowired  annotation. 

At the end of this phase, all dependencies are injected, beans are fully initialized, but still not ready for use.

Bean post-processor(pre-initializer)

This is the final point of configuration manipulation. each bean may have additional behaviours added at this point; the bean post-processing event. there are two types of extensible and generic processing: before and after initializer.

Initializer: 
This is the second BeanPostProcessor action. @PostConstruct methods called here.

many other things happen during this initializer phase. 

BeanPostProcessor Interface
The bean post-processor interface is used for pre or post initializer steps. The BeanPostProcessor interface allows you to inject common behaviour to a "class" of beans. It still operates on specific beans.  The framework leverages lots of these, a lot of proxies are built during this pre-phase especially.  



Bean post-processor(Post-init)
at the end of this phase, beans have been instantiated and initialized.
Dependencies have been injected.
Beans are finally ready for use.

Use phase:

Most time is spent in this phase; ApplicationContext serves proxies to the original class; ApplicationContext maintains handle to each bean(singleton)

context-aware beans
Spring provides interface ApplicationContextAware; gives your class a handle to the ApplicationContext; not a very common interface to use, but is available during the use phase.
Actually, the context-aware beans get an application context reference injected.

https://dzone.com/articles/spring-bean-lifecycle-using-spring-aware-interface


Destruction phase:

When close is called on the ApplicationContext, the destruction phase of the life cycle begins, and it is a one-way door. Any @PreDestroy method is called at this point, in which beans are not destroyed, but only destroyed by GC.


Aspect-Oriented Programming

An Aspect stands for a cutting concern across many classes, and it is important to know AOP change your code behaviour in the runtime, only in the runtime. 

AOP is for reusing code on a cutting-cross concern, fx: logging, transaction management, caching, security, checking method performance, handling common exceptions etc. AOP programming is an easy way of applying the same code in many classes, to extend or modify its existing method's behaviour. 

In Spring, AOP is implemented by a JDK dynamic proxy(AspectJ) or a CGLIB proxy(inheritance).  AOP is implemented as a proxy pattern or OOP inheritance. 

Dependencies: 
spring-core, spring-context, and aspectjweaver 

Concept and Terms:

In the Spring, basically, AOP concept/terms/annotations have one to one mapping relationship; exactly understanding terms help to implement AOP in the code.  
  • Primary concern: business logic
  • Secondary concern: a supportive function. 
  • Weaving: linking Aspect with other application types or objects to create an advised object. 
  • Target object: object being advised by one or more aspect; referred to as the advised object. 
  • Joinpoint: a spot in your BL code, where a cutting concern code can be applied there.
  • Pointcut: selecting a joint point to apply a common-concern code that matches join points. 
  • Aspect: a concern that cuts across multiple class. 
  • Advice: an implementation of Aspect. the code to solve the cutting concerns
  • AOP proxy: a proxied target created by the AOP framework, to carry out the Advice.
The major points as Implementing an AOP: 
You need to define JoinPoint and then using PointCut to select the JoinPoint, Afterwards implementing the cutting concern code in an Advice. 


Pointcut syntax:

designator("r p.c.m(arg)") 
r:return type; 
p:package; 
c: class; 
m: method; 
arg:args

Supported Pointcut Designators

Spring AOP supports the following AspectJ pointcut designators (PCD) for use in pointcut expressions:

execution: For matching method execution join points. This is the primary pointcut designator to use when working with Spring AOP.

within: Limits matching to join points within certain types (the execution of a method declared within a matching type when using Spring AOP).

this: Limits matching to join points (the execution of methods when using Spring AOP) where the bean reference (Spring AOP proxy) is an instance of the given type.

target: Limits matching to join points (the execution of methods when using Spring AOP) where the target object (application object being proxied) is an instance of the given type.

args: Limits matching to join points (the execution of methods when using Spring AOP) where the arguments are instances of the given types.

@target: Limits matching to join points (the execution of methods when using Spring AOP) where the class of the executing object has an annotation of the given type.

@args: Limits matching to join points (the execution of methods when using Spring AOP) where the runtime type of the actual arguments passed have annotations of the given types.

@within: Limits matching to join points within types that have the given annotation (the execution of methods declared in types with the given annotation when using Spring AOP).

@annotation: Limits matching to join points where the subject of the join point (the method being run in Spring AOP) has the given annotation.



You need to enable AOP @EnableAspectJAutoProxy
Enables support for handling components marked with AspectJ's @Aspect annotation, similar to the functionality found in Spring's <aop:aspectj-autoproxy> XML element. To be used on @Configuration classes 

Using @Aspect to define an Aspect, but must together with a @Component, so that @Component can detect it. 

Type of Advice:

  • Before advice:  advice executed before a joint point.
  • After returning advice: Advice to be executed after a join point completes normally.
  • After throwing advice: Advice to be executed if a method exits by throwing an exception.
  • After(finally)  advice: Advice to be executed regardless of means by which a join point exits(normal or exceptional return).
  • Around advice:  performing custom behaviour before and after the joinpoint.

No comments:

Can Jackson Deserialize Java Time ZonedDateTime

Yes, but must include JSR310. Thus ZonedDateTime can be deserialized directly from JSON response to POJO field. <dependency> <g...