Spring Framework

As Java developers, we constantly seek ways to write cleaner, more efficient code. The Spring Framework (stable version 5.3.32 as of March 2025) delivers just that by managing object creation and wiring through Inversion of Control (IoC) and Dependency Injection (DI). In this article, I’ll walk you through Spring’s powerful DI types—byType, byName, and byConstructor—across XML, Java-based, and annotation-driven setups, plus a deep dive into essential annotations with real-world examples. Whether you’re maintaining legacy code or building a new app, these tools will elevate your Spring game.

Here are the Spring projects I have worked on : [Github]


IoC Container: The Engine of Spring

The Inversion of Control (IoC) Container is Spring’s backbone. Instead of your code controlling object creation (e.g., using new), Spring flips the script—hence “inversion.” You define what you need, and the IoC container delivers it.

  • BeanFactory: The basic, lightweight container. It manages beans but lacks advanced features.
  • ApplicationContext: The modern choice—extends BeanFactory with support for annotations, internationalization, and more.

What It Does:

  • Manages Bean Lifecycle: Creates, configures, and destroys beans.
  • Handles Dependencies: Wires beans together via DI.

Example (XML):

ApplicationContext context = new   ClassPathXmlApplicationContext("beans.xml");
Student student = context.getBean(Student.class);        

  • Here, ApplicationContext reads beans.xml, creates the Student bean, and hands it to you.


Dependency Injection: Wiring Made Simple

Dependency Injection (DI) is how Spring connects beans. Rather than a Student class creating its own Mobile, Spring injects the Mobile into a Student. This reduces tight coupling and makes code easier to test and maintain.

  • Why It Matters: No more manual object creation—Spring does the heavy lifting.
  • Core Idea: A “target” class (e.g., Student) gets its “dependent” class (e.g., Mobile) from the IoC container.

Let’s see DI in action with its key types.

Base Classes for Examples

Mobile.java:

public class Mobile {
    public void ring() { System.out.println("Ring ring!"); }
}        

Student.java:

public class Student {
    private Mobile mobile;
    public void setMobile(Mobile mobile) { this.mobile = mobile; }
    public Student() {}
    public Student(Mobile mobile) { this.mobile = mobile; }
    public void study() { mobile.ring(); System.out.println("Studying..."); }
}        



DI Types Across Configurations

1. ByType: Matching by Class Type

  • How It Works: Spring injects a bean based on its type.
  • XML: beans.xml:

<beans xmlns="https://www.springframework.org/schema/beans"
       xmlns:xsi="https://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="https://www.springframework.org/schema/beans
       https://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="mobile" class="com.example.Mobile" />
    <bean id="student" class="com.example.Student" autowire="byType" />
</beans>        

  • Spring matches Mobile to student.mobile by type.
  • Run:

ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
Student student = context.getBean(Student.class);
student.study(); // Output: Ring ring! Studying...        

Java-Based:

@Configuration
public class AppConfig {
    @Bean
    public Mobile mobile() { return new Mobile(); }
    @Bean
    public Student student(Mobile mobile) { return new Student(mobile); }
}        

  • Type-based matching via constructor.
  • Run: Same output.
  • Annotation-Driven:

@Component
public class Student {
    @Autowired // By type
    private Mobile mobile;
    public void study() { mobile.ring(); System.out.println("Studying..."); }
}        

Mobile.java:

@Component
public class Mobile { public void ring() { System.out.println("Ring ring!"); } }        

AppConfig.java:

@Configuration
@ComponentScan("com.example")
public class AppConfig { }        

Run: Same output.

2.ByName: Matching by Property Name

How It Works: Spring links a bean by matching its ID to the property name.

XML:

  • beans.xml:

<bean id="mobile" class="com.example.Mobile" />
<bean id="student" class="com.example.Student" autowire="byName" />        

  • Property mobile matches bean ID mobile.
  • Run: Same output.

Java-Based:

@Configuration
public class AppConfig {
    @Bean(name = "mobile")
    public Mobile mobile() { return new Mobile(); }
    @Bean
    public Student student() {
        Student s = new Student();
        s.setMobile(mobile()); // Mimics byName
        return s;
    }
}        

Run: Same output.

Annotation-Driven:

@Component
public class Student {
    @Autowired
    @Qualifier("mobile") // By name
    private Mobile mobile;
    public void study() { mobile.ring(); System.out.println("Studying..."); }
}        

Mobile.java

@Component("mobile")
public class Mobile { public void ring() { System.out.println("Ring ring!"); } }        

  • AppConfig.java: Same as above.
  • Run: Same output.
  • 3.ByConstructor: Constructor-Based Injection
  • How It Works: Dependencies are injected via the constructor.
  • XML: beans.xml

<bean id="mobile" class="com.example.Mobile" />
<bean id="student" class="com.example.Student">
    <constructor-arg ref="mobile" />
</bean>        

Run: Same output.

Java-Based:

@Configuration
public class AppConfig {
    @Bean
    public Mobile mobile() { return new Mobile(); }
    @Bean
    public Student student(Mobile mobile) { return new Student(mobile); }
}        

  • Run: Same output.

Annotation-Driven:

@Component
public class Student {
    private final Mobile mobile;
    @Autowired
    public Student(Mobile mobile) { this.mobile = mobile; }
    public void study() { mobile.ring(); System.out.println("Studying..."); }
}        

  • Mobile.java: Same as above with @Component.
  • Run: Same output.


Additional DI Modes

  • Setter Injection (XML):

<bean id="mobile" class="com.example.Mobile" />
<bean id="student" class="com.example.Student">
    <property name="mobile" ref="mobile" />
</bean>        

Field Injection (Annotations):

@Component
public class Student {
    @Autowired
    private Mobile mobile;
    public void study() { mobile.ring(); }
}        

Method Injection (XML):

<bean id="student" class="com.example.Student">
    <replaced-method name="study" replacer="replacer" />
</bean>
<bean id="replacer" class="com.example.StudyReplacer" />        

Lookup Method Injection (XML):

<bean id="student" class="com.example.Student">
    <lookup-method name="getMobile" bean="mobile" />
</bean>
<bean id="mobile" class="com.example.Mobile" scope="prototype" />        

Key Spring Annotations: Practical Examples

Annotations streamline Spring configuration. Here’s how they work in practice:

  • @Component (and Variants: @Service, @Repository, @Controller):
  • Marks a class as a bean.
  • Example:

@Service
public class StudentService {
    public String getInfo() { return "Student Service Active"; }
}        

@Autowired:

  • Injects dependencies.
  • Example:

@Component
public class Classroom {
    @Autowired
    private StudentService service;
    public void start() { System.out.println(service.getInfo()); }
}        

@Qualifier:

  • Resolves multiple beans of the same type.
  • Example:

@Component
public class Classroom {
    @Autowired
    @Qualifier("studentService")
    private StudentService service;
}        

@Configuration:

  • Defines a Java config class.
  • Example:

@Configuration
public class AppConfig {
    @Bean
    public Mobile mobile() { return new Mobile(); }
}        

@Bean:

  • Declares a bean in a config class.
  • Example:

@Configuration
public class AppConfig {
    @Bean
    public Student student() { return new Student(mobile()); }
}        

@ComponentScan:

  • Scans for beans.
  • Example:

@Configuration
@ComponentScan("com.example")
public class AppConfig { }        

@Value:

  • Injects values.
  • Example:

@Component
public class Student {
    @Value("Good morning!")
    private String greeting;
    public void say() { System.out.println(greeting); }
}        

@Scope:

  • Sets bean scope.
  • Example:

@Component
@Scope("prototype")
public class Mobile { }        

@Lazy:

  • Delays initialization.
  • Example:

@Component
@Lazy
public class Student {
    public Student() { System.out.println("Lazy Student created"); }
}        

Other Important Concepts

  • Spring Core: The foundation module providing IoC and DI. It’s where BeanFactory and ApplicationContext live, enabling dependency management across all Spring apps.
  • Internal Beans: Beans defined within another bean, not reusable elsewhere. Example (XML):

<bean id="student" class="com.example.Student">
    <property name="mobile">
        <bean class="com.example.Mobile" />
    </property>
</bean>        

  • Invasive vs. Non-Invasive Frameworks:
  • Invasive: Code ties to the framework (e.g., Servlets extend classes), limiting portability.
  • Non-Invasive: Spring’s approach—loose coupling (e.g., @Component), easy-to-switch frameworks.
  • Cyclic Dependencies: When beans depend on each other.
  • Example:

@Component
public class Student {
    @Autowired
    private Mobile mobile;
}
@Component
public class Mobile {
    @Autowired
    private Student student;
}        

Fix:

@Component
public class Student {
    private final Mobile mobile;
    @Autowired
    public Student(@Lazy Mobile mobile) { this.mobile = mobile; }
}        

Setting Up Spring with Maven

  • pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.32</version>
    </dependency>
</dependencies>        


Dheeraj Makineedi

Software Engineer @PeopleTechGroup | Gen-AI and ML | AWS-certified AI Practitioner | Computer Science Graduate@George Washington University |

4 天前

Insightful

Jayasimha Reddy Kanukuntla

SWE @ People Tech Group Inc

4 天前

Very informative

要查看或添加评论,请登录

Jashwanth Jampala的更多文章

  • Hibernate

    Hibernate

    In modern Java development, managing database interactions efficiently is crucial. Spring Data JPA, a powerful…

  • JDBC

    JDBC

    ?? Why You Should Still Learn Core JDBC in the Era of Spring Data JPA Nowadays, developers rely heavily on Spring Data…

    1 条评论
  • Comparator vs Comparable in Java

    Comparator vs Comparable in Java

    Comparable is used at the class level in Java, while Comparator is used at the object level. ? Comparable (Class-Level)…

    1 条评论
  • Introduction to Java Predefined Functional Interfaces

    Introduction to Java Predefined Functional Interfaces

    Hi everyone! Today, I’m excited to discuss some of the predefined functional interfaces in Java that are commonly used…

    4 条评论

社区洞察