Showing posts with label Spring JavaConfig. Show all posts
Showing posts with label Spring JavaConfig. Show all posts

Thursday, 8 November 2018

Aggregating @Configuration classes with @Import | Spring Tutorial

🚀 Master Modular Spring JavaConfig!

Subscribe to Ram N Java for clean architectural patterns, Spring framework tutorials, and code walkthroughs!

🔔 Subscribe to Ram N Java

What Is the @Import Annotation in Spring?

In large-scale enterprise Java applications, keeping all bean definitions inside a single configuration class quickly leads to bloated, unmaintainable code. Spring's @Import annotation provides an elegant solution by allowing developers to split bean configurations across focused, modular @Configuration classes and aggregate them cleanly into a central configuration hub.

How Aggregating Configuration Works

Instead of registering multiple configuration classes manually when initializing the container, you designate one primary or root configuration class and aggregate other specialized classes:

  • Modular Configuration Classes: Separate your beans logically into domain-specific modules (such as AppConfigA and AppConfigB).
  • Aggregation Hub: Annotate a root configuration class with @Import({AppConfigA.class, AppConfigB.class}) to consolidate the configurations.
  • Simplified Container Bootstrapping: Pass only the main configuration class to AnnotationConfigApplicationContext. Spring automatically discovers and loads all imported classes and their associated @Bean definitions.

Step-by-Step Implementation Flow

  1. Define Feature Configs: Create individual configuration classes annotated with @Configuration, defining beans specific to their feature.
  2. Create Main Config: Define a main aggregation class (e.g., AppConfig) and apply @Import passing an array of module configuration classes.
  3. Initialize ApplicationContext: Instantiate the container with new AnnotationConfigApplicationContext(AppConfig.class).
  4. Access Beans: Retrieve beans declared across any of the imported configuration classes seamlessly from the single context.

Major Architectural Benefits

  • Separation of Concerns: Keeps configuration files cohesive, lightweight, and focused on specific domains (e.g., database, security, or business logic).
  • Easier Unit & Integration Testing: Allows test suites to bootstrap only relevant configuration modules rather than the entire application graph.
  • Clean Maintenance: Adding, removing, or swapping modular features becomes as simple as updating an entry in the @Import array.

Recommended Next Videos

Continue your deep dive into Spring configuration and annotations with these tutorials from our channel:


Click here to watch on Youtube:
https://www.youtube.com/watch?v=GRitnworI4c&list=UUhwKlOVR041tngjerWxVccw

Click the below Image to Enlarge:

Aggregating @Configuration classes with @Import | Spring Tutorial

Aggregating @Configuration classes with @Import | Spring Tutorial
pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>com.ram.core</groupId>
    <artifactId>SpringDemo</artifactId>
    <packaging>jar</packaging>
    <version>1.0-SNAPSHOT</version>
    <name>SpringHelloWorld</name>
    <url>http://maven.apache.org</url>

    <properties>
        <spring.version>5.0.2.RELEASE</spring.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>3.8.1</version>
            <scope>test</scope>
        </dependency>

        <!-- Spring 5 dependencies -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-core</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
    </dependencies>
</project>

Employee.java

package com.ram.core;

/**
 * Spring bean
 *
 */

public class Employee
{
    private String name;

    public Employee(String name)
    {
        System.out.println(this.getClass().getName()
                + ", Employee(String name) constructor is called, " + name);

        this.name = name;
    }


    public void employeeDetails()
    {
        System.out.println("Employee Name =  " + name);
    }
}

Customer.java

package com.ram.core;

/**
 * Spring bean
 *
 */

public class Customer
{
    private String name;

    public Customer(String name)
    {
        System.out.println(this.getClass().getName()
                + ", Customer(String name) constructor is called, " + name);

        this.name = name;
    }

    public void customerDetails()
    {
        System.out.println("Customer Name =  " + name);
    }
}

EmployeeConfig.java

package com.ram.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.ram.core.Employee;

@Configuration
public class EmployeeConfig
{

    @Bean(name = "employee")
    public Employee employee()
    {

        System.out.println(
                "In EmployeeConfig employee() is called by the Spring container");
        return new Employee("Peter");

    }
}

CustomerConfig.java

package com.ram.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import com.ram.core.Customer;

@Configuration
public class CustomerConfig
{

    @Bean(name = "customer")
    public Customer customer()
    {
        System.out.println(
                "In CustomerConfig employee() is called by the Spring container");
        return new Customer("John");
    }

}

AppConfig.java

package com.ram.config;

import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;

@Configuration
@Import({ EmployeeConfig.class, CustomerConfig.class })
public class AppConfig
{

}

App.java

package com.ram.core;

import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.ram.config.AppConfig;

public class App
{
    public static void main(String[] args)
    {
        ApplicationContext context = new AnnotationConfigApplicationContext(
                AppConfig.class);

        System.out.println("---------------------------------------");
     
        Employee employee = (Employee) context.getBean("employee");
        System.out.println("Got employee object from the ApplicationContext");
        employee.employeeDetails();
     
        System.out.println("---------------------------------------");
     
        Customer customer = (Customer) context.getBean("customer");
        System.out.println("Got customer object from the ApplicationContext");
        customer.customerDetails();

    }
}

Output

Oct 07, 2018 7:32:15 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5f4da5c3: startup date [Sun Oct 07 07:32:15 IST 2018]; root of context hierarchy
In EmployeeConfig employee() is called by the Spring container
com.ram.core.Employee, Employee(String name) constructor is called, Peter
In CustomerConfig employee() is called by the Spring container
com.ram.core.Customer, Customer(String name) constructor is called, John
---------------------------------------
Got employee object from the ApplicationContext
Employee Name =  Peter
---------------------------------------
Got customer object from the ApplicationContext
Customer Name =  John

Click the below link to download the code:
https://sites.google.com/site/ramj2eev2/java_basics/SpringDemo_aggregate_import.zip?attredirects=0&d=1

Github Link:
https://github.com/ramram43210/javaee/tree/master/Spring_2018/SpringDemo_aggregate_import

Bitbucket Link:
https://bitbucket.org/ramram43210/spring/src/e16b8c6ef73a72464fa5812e24080179c4adc913/Spring_2018/SpringDemo_aggregate_import/?at=master

See also:

  • All JavaEE Videos Playlist
  • All JavaEE Videos
  • All JAVA EE Links
  • Spring Tutorial
  • Servlets Tutorial
  • All Design Patterns Links
  • JDBC Tutorial
  • Java Collection Framework Tutorial
  • JAVA Tutorial
  • Kids Tutorial
  • Cooking Tutorial
  • Wednesday, 31 October 2018

    Spring JavaConfig @Import example | @Import Annotation in Spring JavaConfig | Spring Tutorial

    🚀 Master Modular Spring JavaConfig!

    Subscribe to Ram N Java for clean architectural patterns, Spring framework tutorials, and code walkthroughs!

    🔔 Subscribe to Ram N Java

    Mastering Spring JavaConfig with the @Import Annotation

    As enterprise Spring applications grow in scale, consolidating all configuration beans into a monolithic class quickly creates technical debt and maintainability challenges. Spring provides the @Import annotation as the standard mechanism to organize, separate, and import modular @Configuration classes cleanly, keeping configuration files modular, focused, and test-friendly.

    How @Import Simplifies Spring Configuration

    The @Import annotation functions as the pure Java equivalent of the traditional <import resource="..."/> element in XML configuration:

    • Granular Configuration: Distinct domain layers (such as service configurations, persistence settings, or security filters) are isolated in separate classes marked with @Configuration.
    • Centralized Composition: A root or primary configuration class pulls in these discrete configuration classes using @Import({ConfigA.class, ConfigB.class}).
    • Single Entry Point: When booting up AnnotationConfigApplicationContext, developers only need to pass the central class. Spring automatically registers and coordinates all declared beans across the imported classes.

    Step-by-Step Implementation Flow

    1. Define Sub-Configurations: Build feature-specific configuration classes (e.g., ConfigA providing BeanA, and ConfigB providing BeanB).
    2. Aggregate with @Import: In your central configuration class (such as AppConfig), annotate the class with @Configuration and @Import({ConfigA.class, ConfigB.class}).
    3. Bootstrap ApplicationContext: Instantiate the Spring container by passing only AppConfig.class into AnnotationConfigApplicationContext.
    4. Verify Bean Availability: Both BeanA and BeanB are instantiated, wired, and accessible from the single application context seamlessly.

    Major Architectural Benefits

    • Enhanced Maintainability: Keeps configuration files concise, domain-driven, and easy to navigate.
    • Isolated Unit & Integration Testing: Enables test setups to selectively load only relevant configuration modules rather than the full application context.
    • Explicit Dependencies: Provides clear visibility into configuration dependencies directly through standard Java imports and type references.

    Recommended Next Videos

    Broaden your Spring JavaConfig and architecture expertise with these related tutorials from our channel:


    Click here to watch on Youtube:
    https://www.youtube.com/watch?v=zGTO57LGOtI&list=UUhwKlOVR041tngjerWxVccw

    Click the below Image to Enlarge:
    Spring JavaConfig @Import example | @Import Annotation in Spring JavaConfig | Spring Tutorial

    Spring JavaConfig @Import example | @Import Annotation in Spring JavaConfig | Spring Tutorial
    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0%20http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.ram.core</groupId>
        <artifactId>SpringDemo</artifactId>
        <packaging>jar</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>SpringDemo</name>
        <url>http://maven.apache.org</url>

        <properties>
            <spring.version>5.0.2.RELEASE</spring.version>
        </properties>

        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>

            <!-- Spring 5 dependencies -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
        </dependencies>
    </project>

    Employee.java

    package com.ram.model;

    public class Employee
    {
        private int id;
        private String name;

        public Employee(int id, String name)
        {
            System.out.println("Employee(int id, String name) constructor "
                    + "is called by the Spring container");
            this.id = id;
            this.name = name;
        }

        public void displayEmployeeDetails()
        {
            System.out.println("Employee [id=" + id + ", name=" + name + "]");
        }

    }

    EmployeeConfig.java

    package com.ram.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    import com.ram.model.Employee;

    /**
     * Annotate with @Configuration to tell Spring that this is the core
     * Spring configuration file, and define bean via @Bean.
     */

    @Configuration
    public class EmployeeConfig
    {

        @Bean(name = "employee")
        public Employee getEmployee()
        {
            return new Employee(36,"Peter");
        }

    }

    ApplicationBeans.java

    package com.ram.config;

    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.Import;

    /**
     * Annotate with @Configuration to tell Spring that this is the core
     * Spring configuration file, and define bean via @Bean.
     */

    @Configuration
    @Import({EmployeeConfig.class})
    public class ApplicationBeans
    {

    }

    App.java

    package com.ram.core;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;

    import com.ram.config.ApplicationBeans;
    import com.ram.model.Employee;

    public class App
    {
        public static void main(String[] args)
        {
            ApplicationContext context = new AnnotationConfigApplicationContext(
                    ApplicationBeans.class);

            System.out.println("---------------------------------------");

            Employee employee = (Employee) context.getBean("employee");
            System.out.println(
                    "Got employee object from the ApplicationContext(Spring Container)");
            employee.displayEmployeeDetails();

        }

    }

    Output

    Oct 06, 2018 8:30:01 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
    INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5f4da5c3: startup date [Sat Oct 06 08:30:01 IST 2018]; root of context hierarchy
    Employee(int id, String name) constructor is called by the Spring container
    ---------------------------------------
    Got employee object from the ApplicationContext(Spring Container)
    Employee [id=36, name=Peter]

    Click the below link to download the code:
    https://sites.google.com/site/ramj2eev2/java_basics/SpringDemo_JavaConfig_import.zip?attredirects=0&d=1

    Github Link:
    https://github.com/ramram43210/javaee/tree/master/Spring_2018/SpringDemo_JavaConfig_import

    Bitbucket Link:
    https://bitbucket.org/ramram43210/spring/src/864d48b49c31c0a6d41770bb5dba6b0893945b87/Spring_2018/SpringDemo_JavaConfig_import/?at=master

    See also:

  • All JavaEE Videos Playlist
  • All JavaEE Videos
  • All JAVA EE Links
  • Spring Tutorial
  • Servlets Tutorial
  • All Design Patterns Links
  • JDBC Tutorial
  • Java Collection Framework Tutorial
  • JAVA Tutorial
  • Kids Tutorial
  • Cooking Tutorial
  • Monday, 29 October 2018

    Spring bean java based configuration using @Configuration and @Bean[employee setter method]

    🚀 Master Java-Based Spring Configuration!

    Subscribe to Ram N Java for clean Java tutorials, Spring framework integrations, and step-by-step code demonstrations!

    🔔 Subscribe to Ram N Java

    Configuring Spring Beans with Setter Injection

    In modern Spring applications, Java-based configuration (JavaConfig) using @Configuration and @Bean has largely replaced traditional XML configurations. A common requirement when defining beans is initializing object properties using setter methods. This approach gives developers complete, type-safe control over object instantiation and property population directly within pure Java code.

    Key Annotations Explained

    • @Configuration: Marks a class as a source of bean definitions for the Spring IoC container, allowing methods to define and manage bean lifecycles.
    • @Bean: Indicates that a method instantiates, configures, and initializes a new object to be managed by the Spring ApplicationContext.
    • Setter Injection: After instantiating a class (such as an Employee POJO), its fields are initialized by invoking its setter methods (e.g., setId(), setName()) before returning the bean instance to the container.

    Step-by-Step Implementation Flow

    1. Create the POJO: Define the Employee class containing private fields, default constructor, and getter/setter methods.
    2. Create Configuration Class: Annotate your configuration class (e.g., AppConfig) with @Configuration.
    3. Define the @Bean Method: Create a method returning an Employee instance, annotate it with @Bean, create the object with new Employee(), and configure its values via setter calls.
    4. Bootstrap the Container: Load the configuration class into AnnotationConfigApplicationContext and retrieve the configured bean via context.getBean().

    Advantages of Java-Based Bean Configuration

    • Compile-Time Safety: Eliminate runtime typos and syntax issues common in XML bean configurations.
    • Full Programmatic Control: Seamlessly integrate custom conditional logic, calculations, or external properties when instantiating beans.
    • Clean IDE Refactoring: Renaming classes, methods, or fields instantly updates across your configuration with full IDE support.

    Recommended Next Videos

    Continue mastering Spring JavaConfig and bean management with these related tutorials from our channel:


    Click here to watch on Youtube:
    https://www.youtube.com/watch?v=Hijk4QSmuzU&list=UUhwKlOVR041tngjerWxVccw

    Click the below Image to Enlarge:

    Spring bean java based configuration using @Configuration and @Bean[employee setter method]

    Spring bean java based configuration using @Configuration and @Bean[employee setter method]

    Spring bean java based configuration using @Configuration and @Bean[employee setter method]

    pom.xml

    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/POM/4.0.0%20http://maven.apache.org/maven-v4_0_0.xsd">
        <modelVersion>4.0.0</modelVersion>
        <groupId>com.ram.core</groupId>
        <artifactId>SpringDemo</artifactId>
        <packaging>jar</packaging>
        <version>1.0-SNAPSHOT</version>
        <name>SpringDemo</name>
        <url>http://maven.apache.org</url>

        <properties>
            <spring.version>5.0.2.RELEASE</spring.version>
        </properties>

        <dependencies>
            <dependency>
                <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>3.8.1</version>
                <scope>test</scope>
            </dependency>

            <!-- Spring 5 dependencies -->
            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-core</artifactId>
                <version>${spring.version}</version>
            </dependency>

            <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>${spring.version}</version>
            </dependency>
        </dependencies>
    </project>

    Employee.java

    package com.ram.model;

    public class Employee
    {
        private int id;
        private String name;

        public int getId()
        {
            return id;
        }

        public void setId(int id)
        {
            this.id = id;
        }

        public String getName()
        {
            return name;
        }

        public void setName(String name)
        {
            this.name = name;
        }

        @Override
        public String toString()
        {
            return "Employee [id=" + id + ", name=" + name + "]";
        }

    }

    ApplicationBeans.java

    package com.ram.config;

    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;

    import com.ram.model.Employee;

    /**
     * Annotate with @Configuration to tell Spring that this is the core
     * Spring configuration file, and define bean via @Bean.
     */

    @Configuration
    public class ApplicationBeans
    {

        @Bean(name = "employee")
        public Employee getEmployee()
        {
            Employee employee = new Employee();
            employee.setId(50);
            employee.setName("Peter");
            return employee;
        }

    }

    App.java

    package com.ram.core;

    import org.springframework.context.ApplicationContext;
    import org.springframework.context.annotation.AnnotationConfigApplicationContext;

    import com.ram.config.ApplicationBeans;
    import com.ram.model.Employee;

    public class App
    {
        public static void main(String[] args)
        {
            ApplicationContext context = new AnnotationConfigApplicationContext(
                    ApplicationBeans.class);

            System.out.println("---------------------------------------");

            Employee employee = (Employee) context.getBean("employee");
            System.out.println(
                    "Got employee object from the ApplicationContext(Spring Container)");
            System.out.println(employee);

        }

    }

    Output

    Oct 02, 2018 9:13:01 AM org.springframework.context.support.AbstractApplicationContext prepareRefresh
    INFO: Refreshing org.springframework.context.annotation.AnnotationConfigApplicationContext@5f4da5c3: startup date [Tue Oct 02 09:13:01 IST 2018]; root of context hierarchy
    ---------------------------------------
    Got employee object from the ApplicationContext(Spring Container)
    Employee [id=50, name=Peter]

    Click the below link to download the code:
    https://sites.google.com/site/ramj2eev2/java_basics/SpringDemo_Java_config_employee_setter.zip?attredirects=0&d=1

    Github Link:
    https://github.com/ramram43210/javaee/tree/master/Spring_2018/SpringDemo_Java_config_employee_setter

    Bitbucket Link:
    https://bitbucket.org/ramram43210/spring/src/f1b6bcc6f92fb27386d202f76d65a2386b8928b2/Spring_2018/SpringDemo_Java_config_employee_setter/?at=master

    See also:

  • All JavaEE Videos Playlist
  • All JavaEE Videos
  • All JAVA EE Links
  • Spring Tutorial
  • Servlets Tutorial
  • All Design Patterns Links
  • JDBC Tutorial
  • Java Collection Framework Tutorial
  • JAVA Tutorial
  • Kids Tutorial
  • Cooking Tutorial
  • Tutorials