Showing posts with label spring boot. Show all posts
Showing posts with label spring boot. Show all posts

Monday, December 16, 2024

Inversion of control(IOC) and Dependency Injection(DI) in Spring Framework

In this tutorial, we will learn the basic concept of Inversion of control and Dependency Injection.

The core of the spring framework is based on the IOC principle. IOC and DI are closely related concepts. They describe the different aspects of how the spring manages the objects and their interaction. Let's look into each concept.

Inversion of Control(IOC)

IOC is a design principle where the control of object creation, lifecycle and its management is transferred to a spring. Let's see the example of creating two services i.e DatabaseService and UserService

In non-IOC applications, the application code is responsible for creating and managing the DI

DatabaseService dbService = new DatabaseService();
UserService userService = new UserService(dbService);

Here, first, we create the database service object and inject it into user service as a DI resulting in a tight coupling

public class UserService {
    private final DatabaseService dbService;

    public UserService() {
        this.dbService = new DatabaseService(); // Tight coupling
    }
}

With IOC approach

@Component
public class UserService {
    private final DatabaseService dbService;

    @Autowired
    public UserService(DatabaseService dbService) {
        this.dbService = dbService;
    }
}

Here, With IoC, the spring framework itself is responsible for creating and injecting dependencies. Here our application code is not responsible for creating both the object rather spring does. We only provide the metadata @Component and @Autowired to the spring container. UserService doesn't create the DatabaseService but Spring provides it with the help of annotation provided

Dependency Injection(DI)

DI is a design pattern that implements IoC by injecting an object's dependencies at runtime. That simply means it's a mechanism used to achieve IoC. It simply provide the instances of your application classes with all the dependencies they need.

Here are some advantages of using DI

- Loose coupling

DI allows components to be loosely coupled. This makes it easier to modify or replace dependencies without affecting other components.

- Simplify application configuration

DI uses configuration files, such as XML, annotations, or Java-based configuration, to define the dependencies, making it easier to switch configurations without changing the code.

- Improve code maintenance

DI reduces the amount of code to write to wire the components of the application together. As dependencies are managed externally via a Spring's IoC container; it centralizes configuration and makes the application more modular

- Testability

With DI, it's easier to write unit tests for components. Since dependencies can be injected as mock or stub objects.

- Easier Integration with Frameworks and Libraries

Spring's IoC container can manage their dependencies alongside with application's components, enabling cleaner integration and easier management of external resources.

Share:

Tuesday, June 2, 2020

Hot reloading the resources file for changes in Grails.


How to hot reload the resources file when the changes happened in Grails.


I was working on Grails 3.3.0 and hot reloading was not working while changing in the resources files. So, I found some workaround which is worth sharing here. There are the following steps to resolve the issue.

  1. Configure to watch the directory.
  2. Watch the directory for code changes
  3. Reload spring resources config
  4. Load from the application

Configure to watch the directory:




Here I am creating a class BeanWatcher.groovy to watch the config file changes.


import grails.spring.BeanBuilder
import grails.util.Environment
import grails.util.Holders
import groovy.util.logging.Slf4j
import org.grails.core.exceptions.GrailsConfigurationException
import org.grails.spring.DefaultRuntimeSpringConfiguration
import org.grails.spring.RuntimeSpringConfigUtilities
import org.springframework.beans.factory.support.BeanDefinitionRegistry

import java.nio.file.FileSystems
import java.nio.file.FileVisitResult
import java.nio.file.Files
import java.nio.file.Path
import java.nio.file.SimpleFileVisitor
import java.nio.file.StandardWatchEventKinds
import java.nio.file.WatchEvent
import java.nio.file.WatchKey
import java.nio.file.WatchService
import java.nio.file.attribute.BasicFileAttributes
import java.util.concurrent.atomic.AtomicBoolean
    
    class BeanWatcher extends Thread{
    
    
    private final WatchService watchService
    private long sleepTime = 1000
    private AtomicBoolean stop = new AtomicBoolean(false)
    
    public BeanWatcher(Path path){
        watchService = FileSystems.getDefault().newWatchService()
        walkAndRegisterDirectories(path)

    }
    

    private void walkAndRegisterDirectories(final Path start){
        // register directory and sub-directories
        Files.walkFileTree(start, new SimpleFileVisitor<Path>() {
            @Override
            public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs){
                registerDirectory(dir)
                return FileVisitResult.CONTINUE
            }
        })
    }
    

    private void registerDirectory(dir){

        dir.register(
                watchService,
                StandardWatchEventKinds.ENTRY_MODIFY)
    }
    
    
     @Override
    void run() {

       
    }
    
     static void configureBeanWatcher(){
        Environment environment = Environment.current
        File baseDir = new File(environment.getReloadLocation()).canonicalFile
        String location = baseDir.canonicalPath
        File watchDir = new File(location, "grails-app/conf/spring")
        Path path = watchDir.toPath()
        BeanWatcher beanWatcher = new BeanWatcher(path)
        beanWatcher.start()
    }
    
    
    }

I want to watch the config spring file so I provided the path: "grails-app/conf/spring" under the project directory. As we are running in the thread so the current thread will not be interrupted for each time file changes. Here, we are registering directories and sub-directories.


Watch the directory for code changes:

    @Override
    void run() {

        try {
            WatchKey key
            try {
                while ((key = watchService.take()) != null) {
                    List<WatchEvent <?>> watchEvents = key.pollEvents()
                    for (WatchEvent <?> event : watchEvents) {
                        WatchEvent.Kind <?> kind = event.kind()
                        WatchEvent <Path> pathWatchEvent = cast(event)
                        Path name = pathWatchEvent.context()
                        Path dir = (Path) key.watchable()
                        Path child = dir.resolve(name).toAbsolutePath()
                        File childFile = child.toFile()
                        if(kind == StandardWatchEventKinds.ENTRY_MODIFY){
                            onChange(childFile)
                        }
                    }
                    key.reset()
                }
            } catch (InterruptedException e) {
                e.printStackTrace()
            }
        } catch (IOException e) {
            e.printStackTrace()
        }

    }
        

    @SuppressWarnings("unchecked")
    private static <T> WatchEvent<T> cast(WatchEvent<?> event) {
        return (WatchEvent<T>)event
    }
        
The above code will listen to the file changes and call the method onChange for each time the file changes. Now, it's time to reload our resources file while changes occurred.


Reload spring resources config:

   private static void onChange(File file) { // the changed file 
        processBeanDefinitionRegistry()
    }
    
    public static void processBeanDefinitionRegistry(){
        def springConfig = new DefaultRuntimeSpringConfiguration()
        def application = Holders.grailsApplication
        def context = application.mainContext
        def beanResources = context.getResource(RuntimeSpringConfigUtilities.SPRING_RESOURCES_GROOVY)
        if (beanResources?.exists()) {
            def gcl = new GroovyClassLoader(application.classLoader)
            try {
                RuntimeSpringConfigUtilities.reloadSpringResourcesConfig(springConfig, application, gcl.parseClass(new GroovyCodeSource(beanResources.URL)))
            } catch (Throwable e) {
                throw new GrailsConfigurationException("Error loading spring/resources.groovy file: ${e.message}", e)
            }
        }
        def bb = new BeanBuilder(null, springConfig, application.classLoader)
        bb.registerBeans((BeanDefinitionRegistry)application.getMainContext())
    }
    


This is the code snippet that I found in the grails where they used to reload the file. This will reload and re-configure the resources file.






Load from the application:

We set up all the necessary config and necessary code inside BeanWatcher.groovy now lets load the file from application for this add the following code.

Application.groovy

    if (Environment.current == Environment.DEVELOPMENT){
            BeanWatcher.configureBeanWatcher()
        }
    
This is only for the development env so we did the same.
Share:

Monday, December 24, 2018

Create Simple Secured Restful Web Services Application Using Spring Boot.​

How to create simple restful web services with spring security using Spring Boot.


Prerequisites:

  • Java JDK 1.8
  • IDE 

Introduction:

In this tutorial, we are going to create simple restful web services with spring security included. We are using spring boot scaffolding mechanism, from which we can simply generate the application prototype with its project structure. Simply visit start.spring.io here.

We are using maven project with java and spring boot 2.1.1 with dependencies Web, Security and DevTools.


Generate Project and extract it and open with your favorite Ide. It may take some time to download selected dependencies.

Project Structure:


Here, inside LearntocodeApplication.java there is the main method which will run spring boot application. As we have already added spring boot starter like "Web" inside dependencies section so it has autoconfiguration for tomcat and other feature configuration for running the application.

Make sure required dependencies are in pom.xml file.
  
<dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-security</artifactid>
  </dependency>
  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-web</artifactid>
  </dependency>

  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-devtools</artifactid>
   <scope>runtime</scope>
  </dependency>
  <dependency>
   <groupid>org.springframework.boot</groupid>
   <artifactid>spring-boot-starter-test</artifactid>
   <scope>test</scope>
  </dependency>
  <dependency>
   <groupid>org.springframework.security</groupid>
   <artifactid>spring-security-test</artifactid>
   <scope>test</scope>
  </dependency>

Run the application:

In order to run your application you can simply run via your editor or via command line. If you are trying to run via command line simply go to project's root directory and type the following command in your terminal.

mvn spring-boot:run
Now you can find spring security generated password in your terminal in order to access the application.
Using generated security password: 0fbaa489-e991-4920-a84d-a9710741c378



Create End Point:

In order to test our application, we need to create some Controller with a specified endpoint.

HelloController.java

package com.example.learntocode.restTest;

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class HelloController {

    @GetMapping("/")
    public String hello(){
        return "Hello";
    }

}
Here we are creating rest controller HelloController which is wrapped by annotation @RestController and Get mapping to hello action i.e whenever "${baseUrl}/" endpoint request it will hit this "hello" action.

Test:

I am using postman for a testing endpoint. If we hit endpoint "http://localhost:8080" with Get request we will get Unauthorized message as follows.


Now lets test with the credential provided by spring security as discussed above with generated password.

Note: The default username is "user" and password is generated one. It will generate a new password for each time when we run our application.



Here we have successfully secured our application.

In order to customize the username and password go to "application.properties" and configure as follows.

spring.security.user.name=yourUserName
spring.security.user.password=yourPassword

Share: