spring源码解析(七)

发布时间:2024年01月11日

通过代码模拟实现@Autowired,@Component,@Resource,@Component注解的简单的自我实现。

具体实现过程,请看代码注释以及代码。

测试类如下:

import com.itheima.AutowiredBeanPostProcessor;
import com.itheima.BeanFactory;
import com.itheima.BeanFactoryImpl;
import com.itheima.ResourceBeanPostProcessor;
import com.test.sub.C;

public class Test1 {
    public static void main(String[] args) {
        //创建一个我们自己编写的BeanFactory工厂类。
        // 直接通过工厂类即可获取标有,@Autowired,@Component,@Resource注解的对象
        BeanFactory beanFactory = new BeanFactoryImpl(MyConfig.class,
                new ResourceBeanPostProcessor(), new AutowiredBeanPostProcessor());
        A a = beanFactory.getBean(A.class);
        B b = beanFactory.getBean(B.class);
        C c = beanFactory.getBean(C.class);
        System.out.println(a);
        System.out.println(b);
        System.out.println(c);
        System.out.println("---------------");
        System.out.println(a.getB());
    }
}
BeanFactory抽象类:
public interface BeanFactory {

    /**
     * 将某个类型注册到 spring 容器
     * @param clz 类型
     */
    void register(Class<?> clz);

    /**
     * 获取 bean 实例
     * @param clz 类型
     * @return 对象实例
     * @param <T> 泛型
     */
    <T> T getBean(Class<T> clz);

    void replace(Class<?> clz, Object proxy);
}

?对应的实现类:

import java.util.*;

public class BeanFactoryImpl implements BeanFactory {

    private Map<Class<?>, Object> map = new HashMap<>(); // singletonObjects

    private List<BeanPostProcessor> list = new ArrayList<>();

    /**
     *
     * @param config  配置文件的class
     * @param processors  bean的后置增强器类
     */
    public BeanFactoryImpl(Class<?> config, BeanPostProcessor... processors) {
        list.addAll(Arrays.asList(processors));
        //如果配置 文件带有@ComponentScan注解
        if (config.isAnnotationPresent(ComponentScan.class)) {
            //获取配置文件上的注解
            ComponentScan cs = config.getAnnotation(ComponentScan.class);
            //获取注解中的value值
            String packageName = cs.value();
            try {
                //将带有@Component的注解的所有的类对象,加载到容器中
                ComponentScanner.scan(this, packageName);
            } catch (Exception e) {
                throw new RuntimeException(e);
            }
            // 原始对象 a, b
            /*map.forEach((clz,bean)->{
                // a -> a 代理 -> a @Autowired -> a @Resource
                for (BeanPostProcessor beanPostProcessor : list) {
                    beanPostProcessor.enhance(this, bean);
                }
            });*/

            for (BeanPostProcessor beanPostProcessor : list) {
                for (Object bean : map.values()) {
                    //执行增强类的增强方法
                    beanPostProcessor.enhance(this, bean);
                }
            }
        }
    }

    @Override
    public void register(Class<?> clz) {
        try {
            Object obj = clz.getDeclaredConstructor().newInstance();
            map.put(clz, obj);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public <T> T getBean(Class<T> clz) {
        Object obj = map.get(clz);
        return clz.cast(obj);
    }

    @Override
    public void replace(Class<?> clz, Object proxy) {
        map.put(clz, proxy);
    }
}

后置处理器接口类:

public interface BeanPostProcessor {

    /**
     * 增强 bean 的功能
     * @param beanFactory 容器
     * @param bean 待增强的 bean
     */
    void enhance(BeanFactory beanFactory, Object bean);

}

?

?

Autowired注解声明类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

//该注解用于指定被修饰的注解在运行时保留。这意味着注解信息将在运行时通过反射机制可以被读取和使用。
@Retention(RetentionPolicy.RUNTIME)
//表示当前的这个注解,可以标注在类字段上
@Target(ElementType.FIELD)
public @interface Autowired {
}

Autoeired的后置处理器类:

import com.itheima.aop.HeimaProxy;

import java.lang.reflect.Field;

public class AutowiredBeanPostProcessor implements BeanPostProcessor{
    @Override
    public void enhance(BeanFactory beanFactory, Object a) {
        if (a instanceof HeimaProxy proxy) {
            a = proxy.target();
        }
        // a.getClass() 得到的是代理类型
        // a.getClass().getSuperclass() 得到原始类型
        //获取当前对象a的所有属性并进行遍历
        for (Field field : a.getClass().getDeclaredFields()) {
            //如果属性a上包含注解类,Autowired.class
            if (field.isAnnotationPresent(Autowired.class)) {
                //获取标有@Autowird注解的属性的类型
                Class<?> type = field.getType();
                //从bean工厂类中,根据类型获取到该属性的对象
                Object b = beanFactory.getBean(type);
                //设置当前属性为可访问状态(private修饰的属性,同样可以访问了)
                field.setAccessible(true);
                try {
                    // 给代理对象继承过来的属性b进行了依赖注入
                    field.set(a, b);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
Resource注解声明类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Resource {
}

Resource后置处理器类:

import java.lang.reflect.Field;

public class ResourceBeanPostProcessor implements BeanPostProcessor{
    @Override
    public void enhance(BeanFactory beanFactory, Object a) {
        for (Field field : a.getClass().getDeclaredFields()) {
            if (field.isAnnotationPresent(Resource.class)) {
                Class<?> type = field.getType();
                Object b = beanFactory.getBean(type);
                field.setAccessible(true);
                try {
                    field.set(a, b);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }
}
ComponentScan注解声明类:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
    String value();
}

componnet注解声明类:

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 Component {
}
ComponentScanner类:
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 职责:找到某个 package 下所有加了 @Component 注解的类,把它们加入容器管理
 */
public class ComponentScanner {

    /**
     * 扫描加了 @Component 注解的类,注册到 BeanFactory
     * @param beanFactory 容器
     * @param packageName 包名
     * @throws Exception
     */
    public static void scan(BeanFactory beanFactory, String packageName) throws Exception {
        //获取指定包名下的所有的文件
        List<File> files = getClassFiles(packageName);
        String p = packageName.replace(".", "\\");
        for (File f : files) {
//            System.out.println(f);
            //截取正确的全路径包名
            // D:\黄埔班\mini-spring\target\classes\com\test\A.class => com.test.A
            String t = f.getAbsolutePath();
            t = t.substring(0, t.lastIndexOf(".class"));
            t = t.substring(t.lastIndexOf(p));
            t = t.replace("\\", ".");
//            System.out.println(t);
            //根据全路径包名,通过反射创建class
            Class<?> clz = Class.forName(t);
            //如果此类上有@Component注解,则将当前类对象注册到beanFactory中。
            if (clz.isAnnotationPresent(Component.class)) {
                beanFactory.register(clz);
            }
        }
    }

    /**
     * 根据包名,得到所有类文件
     * @param packageName 包名
     * @return 文件集合
     */
    private static List<File> getClassFiles(String packageName) throws URISyntaxException {
        //将包中的点,换成路径中的/
        packageName = packageName.replace(".", "/");
        //获取当前项目的类路径(java项目的类路径一般有两种:1.项目 编译后的target/classes 2.项目源码中的resource目录)
        URL resource = Thread.currentThread().getContextClassLoader().getResource(packageName);
        Path start =Path.of(resource.toURI());
        //遍历指定的文件夹下的所有文件
        try (Stream<Path> walk = Files.walk(start)) {
            List<File> list = walk.filter(p -> p.toString().endsWith(".class"))
                    .map(p -> p.toFile())
                    .collect(Collectors.toList());
            return list;
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
}

类A:

import com.itheima.Autowired;
import com.itheima.Component;
import com.itheima.Resource;

@Component
public class A {
    @Autowired
//    @Resource
    B b;

    public B getB() {
        return b;
    }

    public void setB(B b) {
        this.b = b;
    }

    public void foo() {
        System.out.println("foo");
    }
}

类B:

import com.itheima.Component;

@Component
public class B {
    public void bar() {
        System.out.println("bar");
    }
}

类c:

import com.itheima.Component;

@Component
public class C {
}

?持续更新中................,关注不迷路。

?

?

?

?

?

?

文章来源:https://blog.csdn.net/w_l666/article/details/135534750
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。