首页 > 其他分享 >手写IOC

手写IOC

时间:2023-02-27 11:36:01浏览次数:32  
标签:aClass DI class field Bean 手写 IOC public

1、定义IOC容器接口

public interface ApplicationContext {
    public Object getBean(Class clazz);
}

2、实现IOC接口

public class AnnotationApplicationContext implements ApplicationContext{
    private Map<Class,Object> beanFactory = new HashMap<>();
    private static String rootPath;

    public   AnnotationApplicationContext (String basePackage){
        try {
            String packagePath = basePackage.replaceAll("\\.", "\\\\");
            Enumeration<URL> resources = Thread.currentThread().getContextClassLoader().getResources(packagePath);
            while (resources.hasMoreElements()){
                URL url = resources.nextElement();
                String filePath = URLDecoder.decode(url.getFile(), "utf-8");
                rootPath  = filePath.substring(0,filePath.length()-packagePath.length());
                loadBean(new File(filePath));

            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        loadDI();
    }
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }
    private void loadBean(File file) {
        if (file.isDirectory()) {
            File[] childrenFiles = file.listFiles();
            if(childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            for (File child : childrenFiles) {
                if (child.isDirectory()) {
                    //如果是个文件夹就继续调用该方法,使用了递归
                    loadBean(child);
                } else {
                    //通过文件路径转变成全类名,第一步把绝对路径部分去掉
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //选中class文件
                    if (pathWithClass.contains(".class")) {
                        //    com.xinzhi.dao.UserDao
                        //去掉.class后缀,并且把 \ 替换成 .
                        String fullName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                        try {
                            Class<?> aClass = Class.forName(fullName);
                            //把非接口的类实例化放在map中
                            if(!aClass.isInterface()){
                                Bean annotation = aClass.getAnnotation(Bean.class);
                                if(annotation != null){
                                    Object instance = aClass.getConstructor().newInstance();
                                    //判断一下有没有接口
                                    if(aClass.getInterfaces().length > 0) {
                                        //如果有接口把接口的class当成key,实例对象当成value
                                        System.out.println("正在加载【"+ aClass.getInterfaces()[0] +"】,实例对象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass.getInterfaces()[0], instance);
                                    }else{
                                        //如果有接口把自己的class当成key,实例对象当成value
                                        System.out.println("正在加载【"+ aClass.getName() +"】,实例对象是:" + instance.getClass().getName());
                                        beanFactory.put(aClass, instance);
                                    }
                                }
                            }
                        } catch (Exception e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
    private void loadDI() {
        for(Map.Entry<Class,Object> entry : beanFactory.entrySet()){
            //放在容器的对象
            Object obj = entry.getValue();
            Class<?> aClass = obj.getClass();
            Field[] declaredFields = aClass.getDeclaredFields();
            for (Field field : declaredFields){
                DI annotation = field.getAnnotation(DI.class);
                if( annotation != null ){
                    field.setAccessible(true);
                    try {
                        System.out.println("正在给【"+obj.getClass().getName()+"】属性【" + field.getName() + "】注入值【"+ beanFactory.get(field.getType()).getClass().getName() +"】");
                        field.set(obj,beanFactory.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

}

3、定义注解@Bean和@DI

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface DI {
}

4、定义并实现DAO接口

public interface UserDAO {
    void add();
}
@Bean
public class UserDAOImpl implements UserDAO {
    @Override
    public void add() {
        System.out.println("DAO add ...");
    }
}

5、定义并实现Service接口

public interface UserService {
    void addUser();
}
@Bean
public class UserServiceImpl implements UserService {
    @DI
    private UserDAO userDAO;
    @Override
    public void addUser() {
        System.out.println("service....");
        userDAO.add();
    }
}

6、创建Controller层

@Bean
public class UserController {
    @DI
    private UserService userService;

    public void add(){
        System.out.println("controller...");
        userService.addUser();
    }
}

7、测试IOC容器

        ApplicationContext context = new AnnotationApplicationContext("com.jixian");
        UserController userController = (UserController) context.getBean(UserController.class);
        userController.add();

8、总结

IOC的实现通过反射加注解,进行包扫描检查类上的注解,如果有@Bean注解就通过反射创建对象,并把对象放在Map中,遍历Map集合检查属性上是否含有@DI注解,将含有@DI注解的属性通过反射进行赋值。

标签:aClass,DI,class,field,Bean,手写,IOC,public
From: https://www.cnblogs.com/jixian/p/17159064.html

相关文章