首页 > 其他分享 >Spring4-IoC3-手写IoC

Spring4-IoC3-手写IoC

时间:2024-09-15 23:23:47浏览次数:3  
标签:java com IoC3 qcby clazz import IoC public Spring4

Spring框架的IoC是基于Java反射机制实现的

Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意方法和属性,这种动态获取信息以及动态调用对象方法的功能称为Java语言的反射机制。简单来说,反射机制指的是程序在运行时能够获取自身的信息

要想解剖一个类,必须先要获取到该类的Class对象,而剖析一个类或用反射解决具体的问题就是使用相关API(1)java.lang.Class(2)java.lang.reflect,所以,Class对象是反射的根源

package com.qcby;

import org.junit.Test;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TestCar {
    //1.获取Class对象多种方式
    @Test
    public void test01() throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1)类名.class
        Class<Car> clazz1 = Car.class;
        //2)对象.getClass()
        Class clazz2 = new Car().getClass();
        //3.Class.forName("全路径")
        Class clazz3 = Class.forName("com.qcby.Car");
        
        //实例化
        Car car = (Car) clazz3.getDeclaredConstructor().newInstance();
        System.out.println(car);
    }
    
    //2.获取构造方法
    @Test
    public void test02() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class<Car> clazz = Car.class;
        //获取所有public的构造方法
//        Constructor[] constructors = clazz.getConstructors();
        //获取所有构造方法(public、private)
        Constructor[] constructors = clazz.getDeclaredConstructors();
        for (Constructor c : constructors) {
            System.out.println("名称:"+c.getName()+" 参数个数:"+c.getParameterCount());
        }

        //指定有参构造创造对象
        //1)构造方法是public
//        Constructor c1 = clazz.getConstructor(String.class, int.class, String.class);
//        Car car1 = (Car) c1.newInstance("奥迪", 10, "黑色");
//        System.out.println(car1);
        //2)构造private
        Constructor c2 = clazz.getDeclaredConstructor(String.class, int.class, String.class);
        c2.setAccessible(true); //允许访问私有构造
        Car car2 = (Car) c2.newInstance("宝马", 10, "白色");
        System.out.println(car2);
    }
    //3.获取属性
    @Test
    public void test03() throws NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        Class clazz = Car.class;
        Car car = (Car) clazz.getDeclaredConstructor().newInstance();
        //获取所有public属性
//        Field[] fields = clazz.getFields();
        //获取所有属性(包含私有属性)
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            if(field.getName().equals("name")){
                //设置允许访问
                field.setAccessible(true);
                field.set(car,"五菱宏光");
            }
            System.out.println(field.getName());
            System.out.println(car);
        }
    }
    //4.获取方法
    @Test
    public void test04() throws InvocationTargetException, IllegalAccessException {
        Car car = new Car("奔驰",10,"黑色");
        Class clazz = car.getClass();
        //1)public方法
        Method[] methods = clazz.getMethods();
        for (Method method : methods) {
//            System.out.println(method.getName());
            //执行方法
            if(method.getName().equals("toString")){
                String invoke = (String) method.invoke(car);
                System.out.println("toString执行了:"+invoke);
            }
        }
        //2)private方法
        Method[] methods1 = clazz.getDeclaredMethods();
        for (Method method : methods1) {
            //执行方法
            if(method.getName().equals("run")){
                method.setAccessible(true);
                method.invoke(car);
            }
        }
    }

}

手写IoC

1.创建子模块spring-ioc

2.创建测试类 service dao

3.创建两个注解

  • @Bean 创建对象
  • @Di 属性注入

4.创建bean容器接口 ApplicationContext

  • 定义方法
  • 返回对象

5.实现bean容器接口

  • 返回对象
  • 根据包规则加载bean

扫描com.qcby这个包和它的子包里面的所有类,看类上面是否有@Bean注解,如果有则把这个类通过反射实例化

package com.qcby.dao;

public interface UserDao {
    void add();
}
package com.qcby.dao.impl;

import com.qcby.anno.Bean;
import com.qcby.dao.UserDao;
import org.springframework.stereotype.Repository;


@Bean
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("dao...");
    }
}
package com.qcby.service;

public interface UserService {
    void add();
}
package com.qcby.service.impl;

import com.qcby.anno.Bean;
import com.qcby.anno.Di;
import com.qcby.dao.UserDao;
import com.qcby.service.UserService;
import org.springframework.stereotype.Service;

@Bean
public class UserServiceImpl implements UserService {

    @Di
    private UserDao userDao;

    @Override
    public void add() {
        System.out.println("service...");
        //调用dao的方法
        userDao.add();
    }
}
package com.qcby.bean;

public interface ApplicationContext {
    Object getBean(Class clazz);
}
package com.qcby.anno;


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 {
}
package com.qcby.anno;


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 {
}
package com.qcby.bean;

import com.qcby.anno.Bean;
import com.qcby.anno.Di;

import java.io.File;
import java.io.IOException;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
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 Map<Class,Object> beanFactory = new HashMap<>();

    private static String rootPath;

    @Override
    public Object getBean(Class clazz) {
        return beanFactory.get(clazz);
    }

    //设置包扫描规则
    //当前包及其子包,哪个类有@Bean注解,把这个类通过反射实例化
    public AnnotationApplicationContext(String basePackage) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        //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(filePath));
        }
        //属性注入
        loadDi();
    }



    //包扫描过程,实例化
    private void loadBean(File file) throws ClassNotFoundException, NoSuchMethodException, InvocationTargetException, InstantiationException, IllegalAccessException {
        //1.判断当前是否是文件夹
        if(file.isDirectory()){
            //2.获取文件夹里的所有内容
            File[] childrenFiles = file.listFiles();
            //3.判断文件夹里面为空,直接返回
            if(childrenFiles == null || childrenFiles.length == 0){
                return;
            }
            //4.如果文件夹不为空,遍历文件夹所有内容
            for (File child : childrenFiles) {
                //1)遍历得到每个File对象,继续判断,如果还是文件夹,递归
                if(child.isDirectory()){
                    loadBean(child);
                }else {
                    //2)遍历得到File对象不是文件夹,是文件
                    //3)得到包路径+类名称部分  字符串截取
                    String pathWithClass = child.getAbsolutePath().substring(rootPath.length() - 1);
                    //4)判断当前文件类型是否是.class
                    if(pathWithClass.contains(".class")){
                        //5)如果是.class类型,把路径\替换成.,把.class去掉
                        String allName = pathWithClass.replaceAll("\\\\", ".").replace(".class", "");
                        //6)判断类上是否有注解@Bean,如果有,实例化过程
                        //6.1获取类的Class
                        Class<?> clazz = Class.forName(allName);
                        //6.2判断不是接口,实例化
                        if(!clazz.isInterface()){
                            //6.3判断类上面是否有注解@Bean
                            Bean annotation = clazz.getAnnotation(Bean.class);
                            if(annotation != null){
                                //6.4实例化
                                Object instance = clazz.getConstructor().newInstance();
                                //7)把对象实例化之后,放到map集合beanFactory
                                //7.1判断当前类如果有接口,让接口class作为map的key
                                if (clazz.getInterfaces().length>0){
                                    beanFactory.put(clazz.getInterfaces()[0],instance);
                                }else {
                                    beanFactory.put(clazz,instance);
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    
    //属性注入
    private void loadDi() throws IllegalAccessException {
        //实例化对象在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注解,把对象进行设置(注入)
                    field.set(obj,beanFactory.get(field.getType()));
                }
            }
        }
    }


}

测试:

package com.qcby;

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

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;

public class TestUser {
    public static void main(String[] args) throws IOException, ClassNotFoundException, InvocationTargetException, NoSuchMethodException, InstantiationException, IllegalAccessException {
        ApplicationContext context =
                new AnnotationApplicationContext("com.qcby");
        UserService userService = (UserService) context.getBean(UserService.class);
        System.out.println(userService);
        userService.add();
    }
}

标签:java,com,IoC3,qcby,clazz,import,IoC,public,Spring4
From: https://blog.csdn.net/m0_73902080/article/details/142287600

相关文章

  • Spring4-IoC2-基于注解管理bean
    目录开启组件扫描使用注解定义bean@Autowired注入场景一:属性注入场景二:set注入场景三:构造方法注入场景四:形参注入场景五:只有一个构造函数,无注解场景六:@Autowired和@Qualifier注解联合@Resource注入场景一:根据name注入场景二:name未知注入场景三:其他情况Spring全注......
  • 【编程底层思考】理解控制反转Inverse of Control,IOC 和 依赖注入Dependency Injecti
    RodJohnson是第一个高度重视以配置文件来管理Java实例的协作关系的人,他给这种方式起了一个名字:控制反转(InverseofControl,IOC)。后来MartineFowler为这种方式起了另一个名称:依赖注入(DependencyInjection),因此不管是依赖注入,还是控制反转,其含义完全相同。当某个Java对象(......
  • Spring6详细学习笔记(IOC+AOP)
    一、Spring系统架构介绍1.1、定义Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。Spring官网Spring是一款主流的JavaEE轻量级开源框架,目的是用于简化Java企业级引用的开发难度和开发周期。从简单性、可测试性和松耦合度的角度而言,任何Java应用都可以从S......
  • 面试官:谈谈你对 IoC 和 AOP 的理解!
    这是一道超级常见的Spring面试题。这篇文章会从下面从以下几个问题展开对IoC&AOP的解释:什么是IoC?IoC解决了什么问题?IoC和DI的区别?什么是AOP?AOP解决了什么问题?AOP的应用场景有哪些?AOP为什么叫做切面编程?AOP实现方式有哪些?首先声明:IoC&AOP......
  • ioc
    publicclassIoc:IServiceProvider{privateIoc_root;privateConcurrentDictionary<Type,ServiceRegistry>_registries=newConcurrentDictionary<Type,ServiceRegistry>();privateConcurrentDictionary<Type,object?>_s......
  • Spring框架之IOC介绍
    Spring之IOC简介首先,官网中有这样一句话:SpringFrameworkimplementationoftheInversionofControl(IoC)principle.这句话翻译过来就是:Spring实现控制反转(IOC)原理,由此可以得出,InversionofControl(IOC)是一个名为控制反转的原理,而Spring实现了他。而实现这个原理或者说设......
  • IoC&AOP详解
    1.IoC1.1什么是IoC    IoC即控制反转/反转控制。它是一种思想而不是一种技术实现,描述的是:Java开发领域对象的创建以及管理的问题    例如:现有类A依赖类B        传统开发方式:在类A中通过new关键字来创建一个类B的对象      ......
  • 了解依赖反转原则(DIP)、控制反转(IoC)、依赖注入(DI)及 IoC容器
    这篇文章将描述DIP、IoC、DI和IoC容器。大多数情况下,初学者开发人员会遇到DIP、IoC、DI和IoC容器的问题。他们混淆在一起,发现很难辨别他们之间的区别,不知道为什么他们需要使用他们。另一方面,很多人使用DI,IoC却不知道它能解决什么问题。关于这个话题有很多帖子......
  • IOC和DI的理解
    IOC与DI的理解1.1、IoC是什么Ioc—InversionofControl,即“控制反转”,不是什么技术,而是一种设计思想。在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不是传统的在你的对象内部直接控制。如何理解好Ioc呢?理解好Ioc的关键是要明确“谁控制谁,控制什么,为何是......
  • 如何使用Spring IOC的注解进行开发
    目录1、如何使用注解标记和扫描2、如何使用注解配置作用域和周期方法3、如何使用注解进行引用类型自动装配4、如何使用注解对基本类型属性赋值Spring IoC(Inversion of Control,控制反转)容器通过注解提供了一种简洁且强大的方式来进行依赖注入和配置管理。注解开发使得......