Spring通过注解实现IoC容器(简单实现)

一, 项目整体结构

创建maven项目创建如图所示的结构

二,annotation包

2.1 Bean.java

package com.best.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 {


}

 2.2,DI.java

package com.best.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 DI {

}

三,bean包

3.1,AnnotationApplicationContext.java

package com.best.bean;

import com.best.annotation.Bean;
import com.best.annotation.DI;

import java.io.File;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLDecoder;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;


public class AnnotationApplicationContext implements ApplicationContext{


    // 创建map集合,放bean对象
    private final Map<Class<?>,Object> beanFactory = new HashMap<>();

    public static String rootPath;


    //返回对象
    @Override
    public Object getBean(Class<?> clazz) {
        return beanFactory.get(clazz);
    }

    //设置包的扫描规则
    //当前包以及子包 那个类有@Bean注解,就把这个类通过反射实例化
    // basePackage 包的路径
    public  AnnotationApplicationContext(String basePackage) throws Exception {
        //com.xxxx
        //1. 把 . 替换成 \
        String packagePath = basePackage.replaceAll("\\.", "\\\\");

        //2. 获取包的绝对路径
        Enumeration<URL> urls = Thread.currentThread()
                .getContextClassLoader()
                .getResources(packagePath);


        while (urls.hasMoreElements()){
            URL url = urls.nextElement();
            String filePath = URLDecoder.decode(url.getFile(), "utf-8");

            //获取包前面路径部分进行截取,字符串截取
            rootPath = filePath.substring(0, filePath.length() - packagePath.length());

            //包扫描
            loadBean(new File(rootPath));

            //属性注入
            loadDI();
        }
    }


    //属性注入
    private void loadDI() {
        //实例化对象在beanFactory的map集合里面
        //1. 遍历beanFactory的map集合
        Set<Map.Entry<Class<?>, Object>> entries = beanFactory.entrySet();
        for (Map.Entry<Class<?>, Object> entry : entries) {
            //2. 获取map集合每个对象(value),每个对象属性获取到
            Object obj = entry.getValue();
            //获取对象的Class
            Class<?> clazz = obj.getClass();
            Field[] declaredFields = clazz.getDeclaredFields();
            //3. 遍历得到每个对象属性数组,得到每个属性
            for (Field field : declaredFields) {
                //4. 判断属性上是否有@DI注解
                DI annotation = field.getAnnotation(DI.class);
                if(annotation != null) {
                    //如果是私有属性,涉设置可以使用
                    field.setAccessible(true);
                    //5. 如果有@DI注解,把对象进行设置(注入)
                    try {
                        //设置值
                        field.set(obj,beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }

                }

            }
        }








    }

    //包扫描过程, 实例化
    private void loadBean(File file) throws Exception {
        //1. 判断当前是否是文件夹
        if(file.isDirectory()){
            //2. 获取文件夹里所有的内容
            File[] childrenFiles = file.listFiles();
            //3. 判断文件夹里为空直接返回
            if(childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            //4. 文件夹里面不为空,遍历文件夹里的所有内容
            for (File child : childrenFiles) {
                //4.1 遍历每一个File对象,继续判断,如果还是文件,递归
                if(child.isDirectory()){
                    loadBean(child);
                }
                else{
                    //4.2 遍历得到File对象不是文件夹,是文件
                    //4.3 得到包路径+类名称部分-字符串截取
                    String pathWithClass =
                            child.getAbsolutePath().substring(rootPath.length() - 1);

                    //4.4 判断当前文件夹类型是否为.class
                    if(pathWithClass.contains("class")) {
                        //4.5 如果是.class类型,把路径\替换成. 把.class去掉
                        // com.best.service.UserServiceImpl
                        String allName = pathWithClass.replaceAll("\\\\", ".")
                                .replaceAll(".class", "");

                        //4.6 判断类上是否有注解@Bean,如果有就实例化过程
                        //4.6.1 获取类的Class
                        Class<?> clazz = Class.forName(allName);
                        //4.6.2 判断不是接口
                        if(!clazz.isInterface()){
                            //4.6.3 判断类上受否有注解@Bean
                            Bean annotation = clazz.getAnnotation(Bean.class);
                            if(annotation != null) {
                                //4.6.4 实例化对象
                                Object instance = clazz.getConstructor().newInstance();
                                //4.7 把对象实例化之后,放到map集合beanFactory中
                                //4.7.1 判断当前类如果有接口,让接口class作为map的key
                                if(clazz.getInterfaces().length>0) {
                                    beanFactory.put(clazz.getInterfaces()[0],instance);
                                } else {
                                    beanFactory.put(clazz,instance);
                                }
                            }
                        }
                    }
                }
            }
        }
    }





}

3.2,Application.java 接口

package com.best.bean;

public interface ApplicationContext {

    Object getBean(Class<?> clazz);

}

四,测试类和测试方法

4.1,dao包和service包

4.1.1,UserDao接口和UserDaoImpl实现类

UserDao.java

package com.best.dao;

public interface UserDao {

    void add();
}

UserDaoImpl.java

package com.best.dao.impl;

import com.best.annotation.Bean;
import com.best.dao.UserDao;

@Bean
public class UserDaoImpl implements UserDao {

    @Override
    public void add() {
        System.out.println("dao add......");
    }
}

UserService.java接口

package com.best.service;

public interface UserService {

    void add();
}

UserServiceImpl.java实现类

package com.best.service.impl;


import com.best.annotation.Bean;
import com.best.annotation.DI;
import com.best.dao.UserDao;
import com.best.service.UserService;

@Bean
public class UserServiceImpl implements UserService {

    @DI
    private UserDao userDao;
    @Override
    public void add() {
        userDao.add();
    }
}

4.2,测试类TestUser.java

package com.best;

import com.best.bean.AnnotationApplicationContext;
import com.best.bean.ApplicationContext;
import com.best.service.UserService;

public class TestUser {

    public static void main(String[] args) throws Exception {

        ApplicationContext context = 
                new AnnotationApplicationContext("com.best");
        UserService userService = (UserService) context.getBean(UserService.class);
        System.out.println(userService);
        userService.add();
    }
}

测试结果如图:

 

补充pom文件

<?xml version="1.0" encoding="UTF-8"?>
<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/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.best</groupId>
    <artifactId>spring6</artifactId>
    <packaging>pom</packaging>
    <version>1.0-SNAPSHOT</version>
    <modules>
        <module>spring-first</module>
        <module>spring6-ioc-xml</module>
        <module>spring6-ioc-annotation</module>
        <module>spring6-reflect</module>
        <module>spring-ioc</module>
    </modules>

    <properties>
        <maven.compiler.source>17</maven.compiler.source>
        <maven.compiler.target>17</maven.compiler.target>
    </properties>


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


        <dependency>
            <groupId>org.junit.jupiter</groupId>
            <artifactId>junit-jupiter-api</artifactId>
            <version>5.10.2</version>

        </dependency>





        <dependency>
            <groupId>javax.annotation</groupId>
            <artifactId>javax.annotation-api</artifactId>
            <version>1.3.2</version>
        </dependency>



    </dependencies>


</project>

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值