【Spring系列】- 手写模拟Spring框架

简单模拟Spring

生命不息,写作不止 继续踏上学习之路 , 学之分享笔记 总有一天我也能像各位大佬一样 一个有梦有戏的人 @怒放吧德德分享学习心得,欢迎指正,大家一起学习成长!
上次已经学习了Java的设计模式 , 接下来就先来学习一下如何手写模拟简易的Spring,通过动手实践,才会更好的了解spring底层原理,今天就简单的模拟Spring容器是如何创建,bean又是如何注入的 。来看一下本次案例的spring类图
【Spring系列】- 手写模拟Spring框架

文章插图
Spring容器模拟spring,首先就是需要一个容器 , 是Spring的核心,一切Spring bean都存储在Spring容器内,并由其通过IoC技术管理 。Spring容器也就是一个bean工厂(BeanFactory) 。应用中bean的实例化,获?。俚榷际怯烧飧鯾ean工厂管理的 。就像我们刚开始学习的时候接触的ApplicationContext,就是spring的容器 , 他就是为了完成容器的配置,初始化,管理bean的 。因此笔者自己创建了一个LydApplicationContext来模拟简单的spring容器 。
开始使用首先通过new LydApplicationContext(AppConfig.class)实例化对象,在通过applicationContext.getBean("userService")去获得bean对象 。然而在容器的初始化可是做了许多的事情 , 包括扫描、实例化bean等等操作 。初始容器创建:
public class LydApplicationContext {    private Class configClass;    public LydApplicationContext(Class configClass) { // 构造方法        this.configClass = configClass;    }}Spring扫描底层实现Spring容器建好之后我们就需要通过配置文件的注解获取扫描路径,我们需要获取所有的bean,并且需要实例对象 。在此我们需要一个配置文件,就是使用new LydApplicationContext(AppConfig.class) 实例携带的配置类,当然这里有好多的形式,也可以是通过xml文件来处理 。
配置文件AppConfig.java这个就是为了提供扫描的包路径的 , 不做任何操作,所以不需要其他代码 。
@ComponentScan("com.lyd.service") // 扫描路径,扫描这个包下的public class AppConfig {}通过注解存放这个包路径 , 在后面可以通过这个注解来获取包路径,所以就需要我们创建一个ComponentScan注解 。
编写ComponentScan注解这个注解是用来spring容器扫描包为之提供包路径 。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface ComponentScan {    // 指定扫描路径    String value() default "";}编写Component注解在Spring中,通过Component注解将bean注入Spring容器中,这里我们也采用高这个注解 。
@Target(ElementType.TYPE)@Retention(RetentionPolicy.RUNTIME)public @interface Component {    String value() default "";}获取包路径既然已经通过注解将包路径存在配置类中,接下来就可以通过这个注解来得到 。但是,在这里需要注意的是,我们扫描的并非是java源文件,而是编译后的class文件 。我们需要在LydApplicationContext的构造方法中去实现 。首先 , 我们需要通过isAnnotationPresent方法先判断是否存在ComponentScan注解 , 在通过类的getAnnotation方法来得到注解 。这样就可以直接得到注解上的值 。这个值就是我们写入的包路径,注意,这里的路径是com.lyd.service,而我们需要用替换方法将'.'替换成'/',因为在后面获取资源路径的时候 , 用的是com/lyd/service这种形式,也就是相对路径 。接下来需要获取资源路径 , 这个时候就需要用到类加载器LydApplicationContext.class.getClassLoader() , 类加载器中有一个getResource(path)方法,这个可以根据传入的路径获取相应的资源,最后是能够拼出我们需要的绝对路径 。
if (configClass.isAnnotationPresent(ComponentScan.class)) {    ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);    // 1.1 扫描路径:只是个包名,扫描的是java的class文件,而并非源文件,com.lyd.service    String path = componentScanAnnotation.value();    // 1.2 将路径文件替换成/的形式    path = path.replace(".","/");    // 1.3 通过类加载器获取资源路径    ClassLoader classLoader = LydApplicationContext.class.getClassLoader();    URL resource = classLoader.getResource(path);    // 1.4 转成文件形式,主要是为了获取他的绝对地址    File file = new File(resource.getFile());    System.out.println(file);}

推荐阅读