【2】Spring手写模拟-依赖注入、初始化、AOP

这篇具有很好参考价值的文章主要介绍了【2】Spring手写模拟-依赖注入、初始化、AOP。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

【2】Spring手写模拟-依赖注入、初始化、AOP,spring,python,java

首先回顾一下我们之前的流程ApplicationContext 构造方法

  • 获取Spring配置类@ComponetScan 注解,扫描包,获取其路径及其对应的字节码文件
  • 逐个扫描字节码文件
    • 利用字节码文件获取类,查看是否包含@Componet 注解,并获取或者生成BeanName
    • 获取BeanDefinition ,包含其类和类型(单例,多例)
    • 将其信息保存在beanDefinitionMap <String beanName, Class clazz>
  • 创建单例对象保存在singletonObjects <BeanName, Object>

getBean(String beanName) 方法

  • BeanDefinition 获取类信息
  • 如果是单例,尝试在singletonObjects 获取对象
    • 如果获取到的bean为空,在creatBean() // 后续说为什么为空
    • 返回获取或者创建的对象
  • 如果是多例,直接creatBean() ,返回创建的对象

creatBean(Class clazz)

返回创建的对象

完善Component

如果Component 不包含BeanName

在扫描扫描包的时候,发现含有Component 注解的时候,查看其value值,如果为空,我们用方法将其类名首字母小写为BeanName


    try {
        Class<?> clazz = classLoader.loadClass(className);
        if(clazz.isAnnotationPresent(Component.class)){
            // 获得注解value值 beanName
            Component component = clazz.getAnnotation(Component.class);
            String beanName = component.value();

            // component未赋值
            if("".equals(beanName)){
                beanName  = Introspector.decapitalize(clazz.getSimpleName());
            }




            BeanDefinition beanDefinition=new BeanDefinition();
            beanDefinition.setType(clazz);

            if(clazz.isAnnotationPresent(Scope.class)){
                Scope scope = clazz.getAnnotation(Scope.class);
                beanDefinition.setScope(scope.value());
            } else {
                beanDefinition.setScope("singleton");
            }
            beanDefinitionMap.put(beanName, beanDefinition);




        }
    } catch (ClassNotFoundException e) {
        throw new RuntimeException(e);
    }


Autoware依赖注入

我们需要实现依赖注入, @Autoware注解,在什么时候注入依赖呢

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)  // 用在变量声明上
public @interface Autoware {
}
@Scope(value = "prototype")
@Component
public class UserService {
    @Autoware
    OrderService orderService;
    public void  test(){
        System.out.println("UserService - test");
    }

}


我们应该在创建对象的时候,扫描其FIELD是否有@Autoware注解,如果包含其注解

    private Object creatBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz=beanDefinition.getType();
        try {
            // 反射获取对象
            Object instance = clazz.getConstructor().newInstance();

            // 依赖注入
            for (Field f : clazz.getDeclaredFields()) {
                if(f.isAnnotationPresent(Autoware.class)){
                    f.setAccessible(true);
                    f.set(instance, getBean(f.getName())); // 通过获取其名字获取其对象 装载上去
                }
            }

            return instance;
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

    }/

这里就解答了为什么当时

如果获取到的bean为空,在creatBean() // 后续说为什么为空

我们是逐个创建对象,有可能当前创建的对象依赖后面的还未创建的对象

Aware回调

对于UserService 想知道自己的BeanName

创建BeanNameAware 接口,包含setBeanName(String beanName) 方法

package com.yqyang.spring;

public interface BeanNameAware {
    public void setBeanName(String beanName);
}

对于UserService 实现该接口

我们在creatBean() 时就能查看类是否instanceof 该接口,如果是可以回调UserService 实现的接口方法

    private Object creatBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz=beanDefinition.getType();
        try {
            // 反射获取对象
            Object instance = clazz.getConstructor().newInstance();

            // 依赖注入
            for (Field f : clazz.getDeclaredFields()) {
                if(f.isAnnotationPresent(Autoware.class)){
                    f.setAccessible(true);
                    f.set(instance, getBean(f.getName()));
                }
            }

            // Aware回调
            if(instance instanceof BeanNameAware){
                ((BeanNameAware) instance).setBeanName(beanName);
            }



            return instance;
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

    }

模拟Spring初始化机制

和上面差不多,定义InitializingBean 接口

package com.yqyang.spring;

public interface InitializingBean {
    public void afterPropertiesSet();
}

对于UserService 实现该接口

我们在creatBean() 时就能查看类是否instanceof 该接口,如果是可以回调UserService 实现的接口方法

    private Object creatBean(String beanName, BeanDefinition beanDefinition) {
        Class clazz=beanDefinition.getType();
        try {
            // 反射获取对象
            Object instance = clazz.getConstructor().newInstance();

            // 依赖注入
            for (Field f : clazz.getDeclaredFields()) {
                if(f.isAnnotationPresent(Autoware.class)){
                    f.setAccessible(true);
                    f.set(instance, getBean(f.getName()));
                }
            }

            // Aware回调
            if(instance instanceof BeanNameAware){
                ((BeanNameAware) instance).setBeanName(beanName);
            }

            // 初始化
            if (instance instanceof InitializingBean) {
                ((InitializingBean)instance).afterPropertiesSet();
            }



            return instance;
        } catch (InstantiationException e) {
            throw new RuntimeException(e);
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            throw new RuntimeException(e);
        } catch (NoSuchMethodException e) {
            throw new RuntimeException(e);
        }

    }

BeanPostProcessor

可能在初始化前后执行一些操作

定义BeanPostProcessor接口,返回值为Object为了后面的动态代理AOP

public interface BeanPostProcessor {
    public Object postProcessBeforeInitialization(String beanName, Object bean);
    public Object postProcessAfterInitialization(String beanName, Object bean);
}

我们需要在ApplicationContext添加变量

private ArrayList<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();

其获取是在扫描包时,获取实现该接口的对象,添加到beanPostProcessorList

try {
  Class<?> clazz = classLoader.loadClass(className);

  if (clazz.isAnnotationPresent(Component.class)) {

      if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
          BeanPostProcessor instance = (BeanPostProcessor) clazz.newInstance();
          beanPostProcessorList.add(instance);
      }

      Component component = clazz.getAnnotation(Component.class);
      String beanName = component.value();

      if (beanName.equals("")) {
          beanName = Introspector.decapitalize(clazz.getSimpleName());
      }


      BeanDefinition beanDefinition = new BeanDefinition();
      beanDefinition.setType(clazz);

      if (clazz.isAnnotationPresent(Scope.class)) {
          Scope scopeAnnotation = clazz.getAnnotation(Scope.class);
          beanDefinition.setScope(scopeAnnotation.value());
      } else {
          beanDefinition.setScope("singleton");
      }

      beanDefinitionMap.put(beanName, beanDefinition);

  }

creatBean() 初始化前后,遍历列表,获取各个对象执行方法

  • 这样如果有多个对象实现BeanPostProcessor ,也就是beanPostProcessorList 中有多个方法,创建一个对象的时候会导致各个实现该对象的方法重复执行,在实现接口的时候可以利用传入创建Bean的参数启到限制的作用,只让我们创建的对象执行。
    • beanName
    • instance
private Object createBean(String beanName, BeanDefinition beanDefinition){

        Class clazz = beanDefinition.getType();

        try {
            Object instance = clazz.getConstructor().newInstance();

            // 依赖注入
            for (Field f : clazz.getDeclaredFields()) {
                if (f.isAnnotationPresent(Autowired.class)) {
                    f.setAccessible(true);
                    f.set(instance, getBean(f.getName()));
                }
            }

            // Aware
            if (instance instanceof BeanNameAware) {
                ((BeanNameAware)instance).setBeanName(beanName);
            }

            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessBeforeInitialization(beanName, instance);
            }

            // 初始化
            if (instance instanceof InitializingBean) {
                ((InitializingBean)instance).afterPropertiesSet();
            }

            for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
                instance = beanPostProcessor.postProcessAfterInitialization(beanName, instance);
            }

            return instance;

        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (InvocationTargetException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        return null;
    }

测试类-记得放在扫描包下

@Component
public class YqyangBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(String beanName, Object bean) {
       if (beanName.equals("userService")) {
           System.out.println("1111");
       }

       return bean;
    }

    @Override
    public Object postProcessAfterInitialization(String beanName, Object bean) {

        if (beanName.equals("userService")) {
            System.out.println("2222");
        }

        return bean;
    }
}

【2】Spring手写模拟-依赖注入、初始化、AOP,spring,python,java

AOP

jdk实现动态代理需要接口,创建接口UserInterface

public interface UserInterface {

    public void test();
}

UserService 实现该接口

@Scope
@Component
public class UserService implements UserInterface {
    @Autoware
    OrderService orderService;
    public void  test(){
        System.out.println("UserService - test");
    }
}

在实现postProcessAfterInitialization 接口时,获取其动态代理对象,并且调用原来的方法。

@Component
public class ZhouyuBeanPostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(String beanName, Object bean) {
       if (beanName.equals("userService")) {
           System.out.println("1111");
       }

       return bean;
    }

    @Override
    public Object postProcessAfterInitialization(String beanName, Object bean) {

        if (beanName.equals("userService")) {
            Object proxyInstance = Proxy.newProxyInstance(ZhouyuBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
                @Override
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    System.out.println("代理逻辑");
                    return method.invoke(bean, args);
                }
            });
            return proxyInstance;
        }

        return bean;
    }
}

【2】Spring手写模拟-依赖注入、初始化、AOP,spring,python,java文章来源地址https://www.toymoban.com/news/detail-568276.html

到了这里,关于【2】Spring手写模拟-依赖注入、初始化、AOP的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • Spring Boot 系统初始化器详解

    Spring Boot 3.x系列文章 Spring Boot 2.7.8 中文参考指南(一) Spring Boot 2.7.8 中文参考指南(二)-Web Spring Boot 源码阅读初始化环境搭建 Spring Boot 框架整体启动流程详解 Spring Boot 系统初始化器详解 Spring Boot 有多种加载自定义初始化器的方法: 1、创建一个实现ApplicationContextInitializer接口的

    2024年02月11日
    浏览(48)
  • Spring初始化顺序- RabbitMq 无法自动创建队列

    项目中使用了RabbitMq, 并配置了自动创建topic, exchange,binding 等,但是通过测试发现,有一个队列始终无法自动创建,在对spring 源码以及rabbitmq 源码debug 后发现问题。 rabbitmq 配置了两套环境 , 以下为代码示例 Queue, Exchange, Binding 自动生成配置: 通过运行项目,发现队列,交换机

    2024年02月13日
    浏览(49)
  • 从零开始 Spring Boot 37:初始化 ApplicationContext

    图源:简书 (jianshu.com) 从前文可以知道,作为 Ioc 容器的 ApplicationContext,需要进行一系列步骤来初始化以最终就绪(对于 Web 应用来说就是可以提供Http服务)。 这些步骤大概可以分为以下内容: 准备上下文关联的 Environment 。 初始化 ApplicationContext( ApplicationContextInitializers

    2024年02月08日
    浏览(44)
  • Spring 填充属性和初始化流程源码剖析及扩展实现

    在上一篇博文 讲解 Spring 实例化的不同方式及相关生命周期源码剖析 介绍了 Spring 实例化的不同方式,本文主要围绕实例化过后对象的填充属性和初始化过程进行详细流程剖析 回顾前言知识,doCreateBean-createBeanInstance,通过 Supplier 接口、FactoryMethod、构造函数反射 invoke,创建

    2024年02月06日
    浏览(44)
  • 【仿写spring之ioc篇】四、实现bean的初始化阶段

    在Bean的初始化阶段有前置和后置方法,这个方法是通过BeanPostProcessor来管理的,下面我们对原有的项目结构做小小的更改。 对启动类作出修改,先检查有没有BeanPostProcessor的实现类,有的话就使用,没有就使用默认的。 第二次循环先检查是不是postProcessor,是的话就跳过就行

    2024年02月10日
    浏览(44)
  • Spring Boot实现第一次启动时自动初始化数据库

    在现在的后端开发中,只要是运用联系型数据库,信任SSM架构(Spring Boot + MyBatis)已经成为首选。 不过在咱们第一次运转或许布置项目的时分,一般要先手动衔接数据库,履行一个SQL文件以创立数据库以及数据库表格完结 数据库的初始化作业 ,这样咱们的SSM应用程序才能够

    2024年02月03日
    浏览(54)
  • 【Spring Boot 源码学习】ConditionEvaluationReport 日志记录上下文初始化器

    《Spring Boot 源码学习系列》 上篇博文《共享 MetadataReaderFactory 上下文初始化器》, Huazie 带大家详细分析了 SharedMetadataReaderFactoryContextInitializer 。而在 spring-boot-autoconfigure 子模块中预置的上下文初始化器中,除了共享 MetadataReaderFactory 上下文初始化器,还有一个尚未分析。 那么

    2024年04月13日
    浏览(43)
  • SpringBoot 底层机制分析【Tomcat 启动+Spring 容器初始化+Tomcat 如何关联Spring 容器】【下】

    😀前言 本篇博文是关于SpringBoot 底层机制分析实现,希望能够帮助你更好的了解SpringBoot 😊 🏠个人主页:晨犀主页 🧑个人简介:大家好,我是晨犀,希望我的文章可以帮助到大家,您的满意是我的动力😉😉 💕欢迎大家:这里是CSDN,我总结知识的地方,欢迎来到我的博客

    2024年02月13日
    浏览(45)
  • 【Spring】javaBean、依赖注入、面向切面AOP、使用注解开发

    有一定规范的Java实体类,类内提供了一些公共方法以便外界对该对象的内部属性进行操作 所有属性都是private,所有的属性都可以通过get/set方法进行访问,同时还需要有一个无参构造(默认就有) 高内聚,低耦合是现代软件的开发的设计模式 之前编写的图书管理系统具有高

    2024年02月08日
    浏览(86)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包