Building a Simple Spring IOC Container: XML and Annotation‑Based Bean Assembly

This article demonstrates how to create a lightweight Spring‑style IoC container in Java by parsing a properties file for XML‑like configuration, implementing annotation‑driven bean registration with a custom @Bean annotation, and adding automatic field injection using a custom @Autowired annotation, complete with full source code examples.

Sohu Tech Products
Sohu Tech Products
Sohu Tech Products
Building a Simple Spring IOC Container: XML and Annotation‑Based Bean Assembly

Introduction

After studying Spring, the author built a very simple Spring‑style IoC container that supports XML‑style bean definition, annotation‑based bean registration, and @Autowired automatic wiring. The following sections describe the design ideas and provide complete Java source code.

1. XML‑based Bean Assembly

Idea

The container reads a conf.properties file that maps interface names to implementation classes, loads the classes via Class.forName, creates instances, and stores them in a Map<Class,Object> for later retrieval.

Implementation

com.wql.dao.userDao=com.wql.daoImpl.userDaoImpl
com.wql.service.userService=com.wql.serviceImpl.userServiceImpl
package com.wql.application;

import java.io.File;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class MyApplicationContext<T> {
    // simulate IOC container
    private Map<Class,Object> map = new HashMap<>();

    private String ResourcePath;
    private String filepath;

    public MyApplicationContext() {
    }

    public MyApplicationContext(String resourcePath) {
        ResourcePath = resourcePath;
    }

    // obtain an object of unknown type (through the map)
    public T getBean(Class clazz) {
        return (T)map.get(clazz);
    }

    // load Class objects from properties and inject into the map
    public void initXMLSpringIOC() {
        try{
            InputStream stream = MyApplicationContext.class.getClassLoader().getResourceAsStream(ResourcePath);
            Properties properties = new Properties();
            properties.load(stream);
            // get content
            Set<Object> keys = properties.keySet();
            for(Object key:keys){
                // Class:instance
                map.put(Class.forName(key.toString()),Class.forName(properties.getProperty(key.toString())).newInstance() );
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    // annotation‑based bean assembly
    public void initAnnotationSpringIOC(){
        filepath = MyApplicationContext.class.getClassLoader().getResource("").getFile();
        System.out.println(filepath);
        loadOne(new File(filepath));
        AnnotationAutowired();
    }

    private void loadOne(File fileparent) {
        if(fileparent.isDirectory()){
            File[] files = fileparent.listFiles();
            if(files.length==0||files==null){
                return;
            }else{
                for(File file:files){
                    if(file.isDirectory()){
                        loadOne(file);
                    }else{
                        try{
                            String oldpath = file.getAbsolutePath().substring(filepath.length()-1,file.getAbsolutePath().length());
                            if(oldpath.contains(".class")){
                                String newpath = oldpath.replaceAll("\\\\",".").replace(".class","");
                                Class<?> aClass = Class.forName(newpath);
                                // simulate bean assembly
                                if(!aClass.isInterface()){
                                    if(aClass.getAnnotation(Bean.class)!=null){
                                        map.put(aClass.getInterfaces()[0],aClass.newInstance());
                                    }
                                }
                            }
                        }catch (Exception e){
                            e.printStackTrace();
                        }

                    }
                }
            }
        }
    }

    // automatic wiring
    private void AnnotationAutowired(){
        for(Map.Entry<Class,Object> entry:map.entrySet()){
            Object obj = entry.getValue();
            Class<?> aClass = obj.getClass();

            Field[] fields = aClass.getDeclaredFields();
            for(Field field: fields){
                field.setAccessible(true);
                if(field.getAnnotation(MyAutowired.class)!=null){
                    try{
                        field.set(obj,map.get(field.getType()));
                    }catch (Exception e){
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

2. Annotation‑Based Bean Assembly

Idea

The container scans the compiled .class files under the project directory, converts file paths to fully‑qualified class names, checks each class for the custom @Bean annotation, and registers non‑interface classes into the map.

Implementation

package com.wql.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
// The scanning logic is part of the loadOne method shown in the previous code block.

3. @Autowired Automatic Wiring

The container iterates over all beans already stored in the map, inspects their fields, and if a field is annotated with the custom @MyAutowired annotation, the corresponding bean is injected via reflection.

package com.wql.Annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAutowired {
}
package com.wql.serviceImpl;

import com.wql.Annotation.MyAutowired;
import com.wql.Annotation.Bean;
import com.wql.dao.userDao;
import com.wql.service.userService;

@Bean
public class userServiceImpl implements userService {

    @MyAutowired
    public userDao userDao;

    @Override
    public void test() {
        userDao.test();
    }
}
// The AnnotationAutowired method in MyApplicationContext (shown earlier) performs the field injection.

Conclusion

The article provides a complete, runnable implementation of a minimal Spring‑like IoC container, covering XML‑style configuration, annotation‑driven bean registration, and automatic dependency injection, and demonstrates its usage with simple DAO and service examples.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaReflectionIoCspringannotationdependency-injection
Sohu Tech Products
Written by

Sohu Tech Products

A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.