Sunday, December 18, 2022

Object Injections to Springs

 There are two ways to inject an object to Springs.

1) Field Injection


2) constructor Injection






Prefer to use constructor injection over field injection as it has some advantages.

Below are some disadvantages of using field injection.

- First, you do not need to use autowired annotation, with constructer injection so you can inject an object while you are writing a simple Java codes without adding any annotation

- One of two major advantages of constructor injection is that it allows to be in to be immutable,  (Observe that the variable is declared with "final" unlike in field injection)

since you can define the property as final and immutable objects helps to create more robust and thread-safe applications.

- Constructor injection also forces that the object is created with the required dependency as the constructor forces it.

- And finally, Spring doesn't use a reflection with constructor approach, unlike field injection as  reflection makes the application code to run slower since it involves types that are dynamic result at runtime.




Loading Configuration along with SpringBoot main class

In situation where the service will not be triggered by a clients and need to start doing some action like reading files, reading streams,  reading data from Twitter, etc.,

when the applications starts we need to find a way to trigger the reading logic.

To do that, we have different options. 



Application YAML file is used to hold the application configuration properties.

Spring boot binds external properties from application.YAML or 

application.properties file into a application at runtime.


Multiple ways:

1) PostConstruct

2) ServeletContextListener

3) ApplicationListener

4) CommandListener


 1) Using PostConstruct

One way is that we can use post construct annotation on methods, let's say, with a method in it.




Now, the code we write here in the init method will be called once after the spring being created.

And by default, spring beans are created once because they are created a singleton.

However, we can actually change these behaviors with scope annotation.





Here we see the supported scope annotations for a bean definition in spring

For example, if you set it to TYPE  "request", it will create a new bean for each request.




So how many times the init method will be called FOR ABOVE SCOPE Then?  it will be called in each request separately because the method will run after each object creation. That means for each request.

So actually, this is not a good option for an application general initialization job.

Although this behavior is only valid, for example, for a controller, where a request will cause to create A NEW BEAN. 



2) another option which is implementing application listener interface and overriding onApplicationEvent method.

This is an application listener method, so it will only run once for sure.

Therefore, we can use it.

Here, the parameter is ApplicationEvent for these method



  

3) implementing commandLineRunner and overriding the run method.

This is also a perfect option for application initialization logic.

The only difference with the previous way is the parameters.

Here we have a string array as parameter in the previous method

The parameter was applicationEvent.





Saturday, December 17, 2022

Log4J addtion to Spring Boot Application

want to add logging capability to our service.

it's very easy thanks to the Springboot, we got logback and SLF4J dependencies automatically, so we could only add a logback.xml in resources folder to the project to customize logging behavior.

To add to this file

Here we defined two appenders

- One writes to console and the other one rights to a file, we can define as many appenders as we want, according to our needs.

 - In the console appender we said, only a pattern for the message.




 - in the file appender, you also specify a file name for logging and again, a pattern of the log Message.

  • Where we define the structure of a log message such as showing the class name, thread ID, time and the log level in the message.
  • And finally, we have a rolling policy here to create a new file and compress and keep the old one after the file reaches a certain size.
  • Finally, we say that we can match the appenders to any package.




For example, here we said two appenders, defined here to all classes that starts with com.microservices.demo package.

That actually means that, our all application classes will be logged by using those two appenders





And here, the root logger will set the log level as a root, which can be overwritten using a specific logger, as we did here.





One more thing about logger is that we can actually define different log levels like trace , Debug, info, warn and error for our logger definition.

And it will work like if you define a lower level it, it will also print the higher levels.

That means Trace level will print all the log messages defined in the code

However, if you set the level as error, all the messages except error will be ignored.

So this way we can control in the configuration how much work will be printed, for example, in production. You don't want to include that much logging, as it can affect the performance of your application because of higher cost.

Having the log feature, I will now update the initialization codes we created in the spring application

class and use the logging framework to log the keywords we defined in the application configuration.






POM File learnings

 - <scope> provided </scope>. in dependency means this is only for dependency

Eg:  Lombok is a compile-only tool, so that we used to provide a scope here for this dependency.

- <scope>test </scope> in depdency section is only test.


spring boot MAVEN Plugin to create a runnable jar automatically for our microservice.

- To read applicatoin.properties from a class 

  •  We will add @ConfiguratoinProperties annotation on the class by adding prefix with value
    • Ex: You have application.yaml in module/resources folder
      • There you provided as
                           Twitter-to-kafka-service:

                                twitter-keywords:

                                - Java

                                 - Microservices

                                 - Spring

                                 - Kafka

        

  • In the class where we want to read the properties file we define as below in class
                @ConfiguratoinProperties(prefix = "twitter-to-kafka-service")
                public class TwitterToKafkaServiceConfigData {
                        private List<String> twitterKeywords;
                        // Please note that 
/*

Then as a private list of string, with name twitterKeywords here.

The naming is important, and this should match to the definition and the application YAML file

Note that for twitter-keywords, we use twitterKeywords with capital, "K" so for replacement of. "-K" we use "Capital K".


*/
                }
                
  • To make that class as a Spring Bean, we will add @Configuration Annotation.
               
                @Configuration
                @ConfiguratoinProperties(prefix = "twitter-to-kafka-service")
                public class TwitterToKafkaServiceConfigData {
                        private List<String> twitterKeywords;
                        // Please note that 

  • We will also use @Data  annotation from Lombok here to obtain methods like getter, setter , hashcode  and toString to get rid of some boilerplate JAVA codes.

    So what Lombok does is to create some code like getter setter methods and then update the class with these methods.                

                 
                @Data 
                @Configuration
                @ConfiguratoinProperties(prefix = "twitter-to-kafka-service")
                public class TwitterToKafkaServiceConfigData {
                        private List<String> twitterKeywords;
                        // Please note that 
   

Friday, December 16, 2022

POM update to run JUNIT Tests when we do "mvn test"

 Some times:


unit tests in test files under src/test wont run when we do. "mvn test" command


Some observations to check  is:

- Few plugins considers file name is Test

- Practise to name function name prefix or suffix by Test

- Another important thing is maven configuration (For Junit 4) add below info


<dependencies>
    <dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.4.0</version>
<scope>test</scope>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.22.0</version>
</plugin>
<plugin>
<artifactId>maven-failsafe-plugin</artifactId>
<version>2.22.0</version>
</plugin>
</plugins>
</build>

Refer: https://junit.org/junit5/docs/current/user-guide/#running-tests-build-maven