Spring之IOC原理实现

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

1 反射

反射 (Reflection) 是 Java 的特征之一,它允许运行中的 Java 程序获取自身的信息,并且可以操作类或对象的内部属性。
Oracle 官方说明:

Reflection enables Java code to discover information about the fields, methods and constructors of loaded classes, and to use reflected fields, methods, and constructors to operate on their underlying counterparts, within security restrictions.
The API accommodates applications that need access to either the public members of a target object (based on its runtime class) or the members declared by a given class. It also allows programs to suppress default reflective access control.

Java反射机制

  • 是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;
  • 对于任意一个对象,都能够调用它的任意方法和属性;
1.1 创建实体类
package com.giser.java.reflect;

/**
 * @author giserDev
 * @description
 * @date 2024-01-03 21:54:07
 */
public class Car {
    //属性
    private String name;
    private int age;
    private String color;

    //无参数构造
    public Car() {
    }

    //有参数构造
    public Car(String name, int age, String color) {
        this.name = name;
        this.age = age;
        this.color = color;
    }

    //普通方法
    private void run() {
        System.out.println("私有方法执行。。。");
    }

    //get和set方法
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getColor() {
        return color;
    }
    public void setColor(String color) {
        this.color = color;
    }

    @Override
    public String toString() {
        return "Car{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", color='" + color + '\'' +
                '}';
    }
}
1.2 反射测试
1.2.1 获取class对象
    @Test
    public void test01() throws Exception {
        // 1 通过类名获取
        Class<Car> carClazz1 = Car.class;

        // 2 通过对象获取
        Class<? extends Car> carClazz2 = new Car().getClass();

        // 3 通过Class.forName()获取
        Class<?> carClazz3 = Class.forName("com.giser.java.reflect.Car");

        // 实例化
        Car car = carClazz1.getConstructor().newInstance();
        System.out.println(car);
    }
1.2.2 获取构造方法
    @Test
    public void test02() {
        Class carClazz = Car.class;
        // 获取所有的public构造方法
//        Constructor[] consArr = carClazz.getConstructors();
//        for (Constructor constructor : consArr) {
//            System.out.println("方法名称:" + constructor.getName() + ", 参数个数:" + constructor.getParameterCount());
//        }

        // 获取所有声明的构造方法:包括共有和私有
//        Constructor[] consArr = carClazz.getDeclaredConstructors();
//        for (Constructor constructor : consArr) {
//            System.out.println("方法名称:" + constructor.getName() + ", 参数个数:" + constructor.getParameterCount());
//        }

        // 指定有参数构造创建对象
//        try {
//            Constructor constructor =
//                    carClazz.getConstructor(String.class, int.class, String.class);
//            Car o = (Car) constructor.newInstance("路虎", 12, "白色");
//            System.out.println(o);
//        } catch (Exception e) {
//            System.out.println(e);
//        }

        //2 构造private
        try {
            Constructor c2 = carClazz.getDeclaredConstructor(String.class, int.class, String.class);
            // 调用私有的构造方法时,需先设置访问权限
            c2.setAccessible(true);
            Car o = (Car)c2.newInstance("宝马", 15, "白色");
            System.out.println(o);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
1.2.3 获取属性
    @Test
    public void test03() throws Exception {
        Class<Car> carClass = Car.class;
        Car car = carClass.getDeclaredConstructor().newInstance();
        // 获取public属性
//        Field[] pubFields = carClass.getFields();
//        for (Field pubField : pubFields) {
//            System.out.println(pubField);
//        }

        // 获取所有的属性,包括私有属性
//        Field[] declaredFields = carClass.getDeclaredFields();
//        for (Field declaredField : declaredFields) {
//            System.out.println(declaredField);
//        }

        // 为私有属性赋值
        Field[] declaredFields = carClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (declaredField.getName().equals("name")){
                // 设置为可访问
                declaredField.setAccessible(true);
                declaredField.set(car, "路虎揽胜");
            }
        }
        System.out.println(car);

    }
1.2.4 获取方法
    @Test
    public void test04() throws Exception {
        Car car = new Car("奥迪A8",10,"白色");
        Class clazz = car.getClass();
        //1 public方法
        Method[] methods = clazz.getMethods();
        for (Method m1:methods) {
            if(m1.getName().equals("toString")) {
                //执行方法
                m1.invoke(car);
            }
        }

        //2 所有方法,包括public方法和private方法
        Method[] methodAll = clazz.getDeclaredMethods();
        for (Method m1 : methodAll) {
            if(m1.getName().equals("run")) {
                m1.setAccessible(true);
                //执行方法
                m1.invoke(car);
            }
        }
    }

2 实现IOC

2.1 定义两个注解

@GisBean 用于对象注入

/**
 * @author giserDev
 * @description 对象注入
 * @date 2024-01-05 16:17:48
 */
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface GisBean {
}

@GisDI 用于依赖注入

/**
 * @author giserDev
 * @description 依赖注入
 * @date 2024-01-05 16:18:02
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface GisDI {
}
2.2 定义一个接口

定义一个应用上下文:

/**
 * @author giserDev
 * @description 应用上下文对象接口
 * @date 2024-01-05 16:20:34
 */
public interface AppContext {

    /**
     * 根据类型获取bean对象
     *
     * @param clazz
     * @param <T>
     * @return
     */
    <T> T getBean(Class<T> clazz);

}

实现:

package com.giser.spring6.ioc.context;

import com.giser.spring6.ioc.annotation.GisBean;
import com.giser.spring6.ioc.annotation.GisDI;

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

/**
 * @author giserDev
 * @description 根据注解初始化应用上下文
 * @date 2024-01-05 16:23:02
 */
public class AnnotationAppContext implements AppContext {

    private Map<Class, Object> appContextMap = new HashMap<>();
    private static String rootPath;

    /**
     * 获取bean
     * @param clazz 类型全路径
     * @param <T> 类型
     * @return 对象
     */
    @Override
    public <T> T getBean(Class<T> clazz) {
        return (T) appContextMap.get(clazz);
    }

    public AnnotationAppContext(String basePackages) {
        // 扫描包路径,加载路径下的文件,根据是否存在相应注解创建bean对象
        try {
            // 解析包路径
            String realPath = basePackages.replaceAll("\\.", "\\\\");
            // 获取全路径
            Enumeration<URL> urlEnumeration = Thread.currentThread().getContextClassLoader().getResources(realPath);
            while (urlEnumeration.hasMoreElements()){
                URL url = urlEnumeration.nextElement();
                String urlPath = URLDecoder.decode(url.getFile(),"utf-8");
                rootPath = urlPath.substring(0, urlPath.length()-realPath.length());
                File file = new File(urlPath);
                loadBeans(file);
            }
            // 依赖注入
            initDI();
        } catch (Exception exception){
            exception.printStackTrace();
        }
    }

    /**
     * 从当前文件及其子文件下加载bean
     * @param file
     */
    private void loadBeans(File file) {
        if (file.isDirectory()){
            // 如果是文件夹
            File[] files = file.listFiles();

            if (files == null || files.length == 0){
                return;
            }

            Arrays.stream(files).forEach(this::loadBeans);
        } else {
            // 如果是文件,针对class文件进行处理
            if (file.getAbsolutePath().endsWith(".class")){
                // 获取包路径
                String clsFullPath = file.getAbsolutePath()
                        .substring(rootPath.length() - 1)
                        .replaceAll("\\\\", "\\.")
                        .replace(".class", "");

                // 实例化对象
                try {
                    Class<?> curClazz = Class.forName(clsFullPath);

                    // 只处理实现类中的注解,创建bean
                    if (!curClazz.isInterface()){
                        // 获取注解
                        GisBean annotation = curClazz.getAnnotation(GisBean.class);
                        if (annotation != null){
                            Object inst = curClazz.getConstructor().newInstance();
                            // 判断当前类是否存在接口
                            if (curClazz.getInterfaces().length > 0){
                                // 存在接口时
                                appContextMap.put(curClazz.getInterfaces()[0], inst);
                            } else {
                                // 不存在接口时
                                appContextMap.put(curClazz, inst);
                            }
                        }
                    }
                } catch (Exception e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    /**
     * 依赖注入
     */
    private void initDI() {
        for(Map.Entry<Class, Object> entry :appContextMap.entrySet()) {
            Object obj = entry.getValue();
            Class<?> curClazz = obj.getClass();
            Field[] declaredFieldArr = curClazz.getDeclaredFields();
            for(Field field : declaredFieldArr) {
                GisDI fieldAnnotation = field.getAnnotation(GisDI.class);
                if (fieldAnnotation != null){
                    field.setAccessible(true);
                    // 属性注入
                    try {
                        field.set(obj, appContextMap.get(field.getType()));
                    } catch (IllegalAccessException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }
}
2.3 测试
public interface UserDao {
    void print();
}
@GisBean
public class UserDaoImpl implements UserDao {

    @Override
    public void print() {
        System.out.println("Dao层执行结束");
    }
}
public interface UserService {
    void print();
}
@GisBean
public class UserServiceImpl  implements UserService {

    @GisDI
    private UserDao userDao;

    @Override
    public void print() {
        System.out.println("Service层执行结束");
    }
}

测试注入:

    @Test
    public void test001(){
        AppContext appContext = new AnnotationAppContext("com.giser.spring6.ioc");
        UserService userService = appContext.getBean(UserService.class);
        userService.out();
    }
  • 11
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值