【Spring】手动实现简易AOP和IOC

前言

XML:通过Dom4j对XML进行解析和验证。
IOC:通过获取要创建对象的Class类型、构造函数后,通过反射来实现。
AOP:通过使用JDK动态代理Cglib动态代理实现。

一、解析XML

1.1、解析bean标签

/**
  * 解析bean标签
  * @param xmlBean bean标签
  */
 private void parseBeanDefinitionXML(Element xmlBean){
     String beanId = xmlBean.attributeValue("id");
     if (beanDefinitionMap.containsKey(beanId)) {
         return;
     }
     String beanClass = xmlBean.attributeValue("class");
     BeanDefinition beanDefinition = new BeanDefinition();
     beanDefinition.setId(beanId);
     beanDefinition.setClassName(beanClass);
     List<Element> xmlConstructor = xmlBean.elements();
     //  无参bean,则解析完成
     if (UsualUtil.isNull(xmlConstructor)) {
         beanDefinitionMap.put(beanId, beanDefinition);
         return;
     }
     List<BeanDefinition.ConstructArg> constructArgs = new ArrayList<>();
     //  解析参数
     for (Element xmlConstructArg : xmlConstructor) {
         //  目前仅解析constructor-arg
         if ("constructor-arg".equals(xmlConstructArg.getName())) {
             String typeClass = xmlConstructArg.attributeValue("type");
             String value = xmlConstructArg.attributeValue("value");
             String refName = xmlConstructArg.attributeValue("ref");
             BeanDefinition.ConstructArg constructArg = new BeanDefinition.ConstructArg();
             constructArg.setType(typeClass);
             constructArg.setValue(value);
             constructArg.setRef(refName);
             //  非引用其他bean
             if (UsualUtil.isNull(refName)) {
                 if (typeClass.endsWith("List")) {
                     Element xmlCollection = xmlConstructArg.elements().get(0);
                     String valueTypeClass = xmlCollection.attributeValue("value-type");
                     constructArg.setItemType(valueTypeClass);
                     List<String> itemValue = new ArrayList<>();
                     for (Element xmlItem : xmlCollection.elements()) {
                         itemValue.add(xmlItem.getStringValue());
                     }
                     constructArg.setItemValue(itemValue);
                 }
             }
             constructArgs.add(constructArg);
         }
     }
     beanDefinition.setConstructArgs(constructArgs);
     beanDefinitionMap.put(beanId, beanDefinition);
 }

1.2、解析aspect标签

/**
  * 解析aspect标签
  * @param xmlAspect aspect标签
  * @param useCglib 是否使用cglib
  */
 private void parseAspectXML(Element xmlAspect, boolean useCglib) {
//    <aop:config>
//        <aop:aspect ref="aspect">
//            <aop:before method="run" pointcut="execution(public void org.tree.aspect.AspectProcessor.before())"/>
//            <aop:after method="run" pointcut="execution(public void org.tree.aspect.AspectProcessor.after())"/>
//        </aop:aspect>
//    </aop:config>
     String refName = xmlAspect.attributeValue("ref");
     if (aspectDefinitionMap.containsKey(refName)) {
         return;
     }
     AspectDefinition aspectDefinition = new AspectDefinition();
     aspectDefinition.setUseCglib(useCglib);
     aspectDefinition.setRef(refName);
     List<AspectDefinition.Advice> advices = new ArrayList<>();
     for (Element xmlAdvice : xmlAspect.elements()) {
         AspectDefinition.Advice advice = new AspectDefinition.Advice();
         advice.setType(xmlAdvice.getName());
         //  execution(public void org.tree.aspect.AspectProcessor.before())
         String pointcutStr = xmlAdvice.attributeValue("pointcut");
         pointcutStr = pointcutStr.replace("execution", "");
         pointcutStr = pointcutStr.substring(0, pointcutStr.length() - 1);
         //  public void org.tree.aspect.AspectProcessor.before()
         String[] strings = pointcutStr.split(" ");
         advice.setMethod(xmlAdvice.attributeValue("method"));
         advice.setProxyMethod(strings[2].substring(strings[2].lastIndexOf('.') + 1, strings[2].length() - 2));
         advice.setProxyClass(strings[2].substring(0, strings[2].lastIndexOf('.')));
         advices.add(advice);
     }
     aspectDefinition.setAdvices(advices);
     aspectDefinitionMap.put(refName, aspectDefinition);
 }

二、加载Bean

加载Bean时,本文实现的是通过构造函数注入参数,所以无法解决循环依赖的问题。
浅说下发现构造函数循环依赖的原理:当要加载一个bean时,记录下当前bean的加载状态为“正在创建中”,准备好构造函数所需要的参数,如果参数是未加载的,则取加载其参数,当加载的参数发现自己正处于“正在创建中”的状态时,则此刻这两个bean之间发生循环依赖了。

2.1、getBean

/**
  * 通过bean实例名字获取实例
  * @param id bean实例名字
  * @return bean实例
  */
 public Object getBean(String id) throws Exception {
     if (beanFactory.containsKey(id)) {
         return beanFactory.get(id);
     }
     if (!beanDefinitionMap.containsKey(id)) {
         return null;
     }
     BeanDefinition beanDefinition = beanDefinitionMap.get(id);
     List<BeanDefinition.ConstructArg> constructArgs = beanDefinition.getConstructArgs();
     if (UsualUtil.isNull(constructArgs)) {
         //  创建bean前操作
         if (beanPostProcessor != null) {
             beanPostProcessor.preInitBean(objectFactory.get(id), id);
         }
         Object beanObj = Class.forName(beanDefinition.getClassName()).getConstructor().newInstance();
         //  如果该bean被aop引用
         beanObj = doEnhanceBean(beanDefinition, beanObj);
         //  创建bean后操作
         if (beanPostProcessor != null) {
             beanPostProcessor.postInitBean(beanObj, id);
         }
         beanFactory.put(id, beanObj);
         return beanObj;
     }
     return doCreateBean(beanDefinition);
 }

2.2、doCreateBean

/**
  * 创建bean
  * @param beanDefinition bean标签
  * @return bean实例
  * @throws Exception 空
  */
 private Object doCreateBean(BeanDefinition beanDefinition) throws Exception{
     //  标记该bean正在创建实例中
     objectFactory.put(beanDefinition.getId(), Class.forName(beanDefinition.getClassName()).getConstructor().newInstance());
     List<BeanDefinition.ConstructArg> constructArgs = beanDefinition.getConstructArgs();
     Class<?>[] paramTypes = new Class[constructArgs.size()];
     Object[] paramValues= new Object[constructArgs.size()];
     int paramIndex = 0;
     for (BeanDefinition.ConstructArg constructArg : constructArgs) {
         //  构造函数参数为引用
         if (!UsualUtil.isNull(constructArg.getRef())) {
             //  该引用bean已经创建实例
             if (beanFactory.containsKey(constructArg.getRef())) {
                 Object refBeanObj = beanFactory.get(constructArg.getRef());
                 paramTypes[paramIndex] = refBeanObj.getClass();
                 paramValues[paramIndex] = refBeanObj;
                 paramIndex++;
             //  该引用bean正在创建实例中,循环引用
             } else if (objectFactory.containsKey(constructArg.getRef())) {
                 throw new Exception("Both id '" + beanDefinition.getId() + "' and '" + constructArg.getRef() + "' are circular reference");
             //  该引用bean未创建实例
             } else {
                 Object refBeanObj = doCreateBean(beanDefinitionMap.get(constructArg.getRef()));
                 paramTypes[paramIndex] = refBeanObj.getClass();
                 paramValues[paramIndex] = refBeanObj;
                 paramIndex++;
             }
             continue;
         }
         paramTypes[paramIndex] = Class.forName(constructArg.getType());
         //  构造函数参数为非引用类型, 且是非集合类型
         if (!(constructArg.getType().endsWith("List"))) {
             paramValues[paramIndex++] = Class.forName(constructArg.getType()).getConstructor(String.class).newInstance(constructArg.getValue());
             continue;
         }
         List<Object> objParamList = new ArrayList<>();
         for (String itemValue : constructArg.getItemValue()) {
             objParamList.add(Class.forName(constructArg.getItemType()).getConstructor(String.class).newInstance(itemValue));
         }
         paramValues[paramIndex++] = objParamList;
     }
     //  创建bean前操作
     if (beanPostProcessor != null) {
         beanPostProcessor.preInitBean(objectFactory.get(beanDefinition.getId()), beanDefinition.getId());
     }
     Object beanObj = Class.forName(beanDefinition.getClassName()).getConstructor(paramTypes).newInstance(paramValues);
     //  如果该bean被aop引用
     beanObj = doEnhanceBean(beanDefinition, beanObj);
     //  创建bean后操作
     if (beanPostProcessor != null) {
         beanPostProcessor.postInitBean(beanObj, beanDefinition.getId());
     }
     beanFactory.put(beanDefinition.getId(), beanObj);
     //  标记该bean没有正在创建
     objectFactory.remove(beanDefinition.getId());
     return beanObj;
 }

三、增强Bean

3.1、doEnhanceBean

/**
  * 创建增强bean
  * @param beanDefinition bean标签
  * @param beanObj bean对象
  * @return 增强bean
  * @throws Exception 空
  */
 private Object doEnhanceBean(BeanDefinition beanDefinition, Object beanObj) throws Exception {
     if (aspectDefinitionMap.containsKey(beanDefinition.getId())) {
         AspectDefinition aspectDefinition = aspectDefinitionMap.get(beanDefinition.getId());
         for (AspectDefinition.Advice advice : aspectDefinition.getAdvices()) {
             //  增强beanObj
             beanObj = doCreateProxy(beanObj, advice.getMethod(), advice.getProxyClass(), advice.getProxyMethod()
                     , "before".equals(advice.getType()), aspectDefinition.isUseCglib());
         }
     }
     return beanObj;
 }

3.2、doCreateProxy

/**
  * 创建代理对象
  * @param beanObj bean实例
  * @param joinPointMethod 要代理的bean方法
  * @param strProxyClass 代理类
  * @param strProxyMethod 代理类的方法
  * @param isBefore 通知类型
  * @param useCglib 是否使用cglib
  * @return 代理对象
  * @throws Exception 空
  */
 private Object doCreateProxy(Object beanObj, String joinPointMethod, String strProxyClass, String strProxyMethod
         , boolean isBefore, boolean useCglib) throws Exception {
     Class<?> clazz = Class.forName(strProxyClass);
     Object proxyObject = clazz.getConstructor().newInstance();
     Method proxyMethod = clazz.getMethod(strProxyMethod);
     //  如果使用cglib动态代理
     if (useCglib) {
         Enhancer enhancer = new Enhancer();
         enhancer.setSuperclass(beanObj.getClass());
         /*
          * 设置被代理类执行方法时的逻辑
          * o 被代理类生成的对象实例(子类)
          * method 被代理类的方法
          * args 方法的参数
          * methodProxy 被代理类的方法的代理方法
          */
         enhancer.setCallback((MethodInterceptor) (o, method, args, methodProxy) -> {
             //  当方法是我们要代理的方法时
             if (method.getName().equals(joinPointMethod)) {
                 if (isBefore) {
                     proxyMethod.invoke(proxyObject);
                 }
                 //  调用父类的方法
                 methodProxy.invokeSuper(o, args); // 使用beanObj会报错,因为参数需要的是生成的子类
                 if (!isBefore) {
                     proxyMethod.invoke(proxyObject);
                 }
             } else { // 如果不写,则是全放空(由于生成的是子类,其他方法全空,不调用父类的【被代理类】)
                 methodProxy.invokeSuper(o, args); // 调用父类的方法
             }
             return o;
         });
         return enhancer.create();
     }
     /*
      * clazz 加载被代理类的加载器
      * interfaces 被代理类实现的所有接口
      * 增强方法
      *  o 被代理类的对象实例
      *  method 被代理类实现的所有接口的方法,且要执行
      *  args 方法需要的参数
      */
     // 代理一个类,该类通过loader加载,且实现interfaces接口
     return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), beanObj.getClass().getInterfaces(), (o, method, args) -> {
         //  当方法为我们要代理的方法时,执行特定增强
         if (method.getName().equals(joinPointMethod)) {
             if (isBefore) {
                 proxyMethod.invoke(proxyObject);
             }
             //  调用被代理类实际的方法
             method.invoke(beanObj, args); // 这里写beanObj不报错是因为它是AspectInterface的子类, 但不能写o,会死循环(调用了代理的自己,又再次调用)
             if (!isBefore) {
                 proxyMethod.invoke(proxyObject);
             }
         } else {
             method.invoke(beanObj, args);
         }
         //  返回值就是代理类执行代理方法的返回值
         return o;
     });

四、类图在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值