关于spring:深入aoc

1次阅读

共计 1303 个字符,预计需要花费 4 分钟才能阅读完成。

前言

应用切面一段时间,写个根本切面没有问题。
然而这次应用切面时遇到了问题,发现切面没有执行,找谬误又无从找起,只能硬看代码。
大略代码是这样的

public class ImportExcelServiceImpl {public void readFromFileAndSetAnswerSheets() {
        ...
        setAnswerSheet(currentRow);
        ...
    }
    
    @UpdateAnswerSheetTotalNumber
    public AnswerSheet setAnswerSheet(Row currentRow) {
        ...
        return answerSheet;
    }
}

这是被切办法

@Aspect
@Component
public class UpdateAnswerSheetTotalNumberAspect {@Pointcut("@annotation(....UpdateAnswerSheetTotalNumber)")
    public void annotationPointCut() {}
    
    @AfterReturning(value = "annotationPointCut()", returning = "answerSheet")
    public void after(AnswerSheet answerSheet) {...}

这是切面

起因

找了半天找不进去哪里错了,就去问了老师,老师看出了问题所在。
原来我的被切办法是 setAnswerSheet(), 调用被切办法是通过this.setAnswerSheet() 调用的,这就是对象内调用。而切面是基于代理模式,对象内调用办法是不走代理的,当然是不起作用的。

原来写的被切办法都是在一个对象中的办法调用另一个对象中的 a 办法的状况下。
此时 spring 会为被调用办法所在对象生成一个代理,此代理领有与服务雷同的办法,如果办法没有被执行切面,则在代理中间接将执行的办法转发给理论的服务,如果有切面,则会在代理中实现切面,这就是切面的原理。
咱们在类中打入断点

其中 userServiceImpl.frozen 使咱们的被切办法。注入的类名总是相似 UserServiceImpl$$EnhancerBySpringCGLIB$$1c76af9d。为了让调用方取得UserServiceImpl 的援用,它必须继承自 UserServiceImpl。而后,该代理类会覆写所有publicprotected办法,并在外部将调用委托给原始的 UserServiceImpl 实例。~~~~

解决

解决的方法就是本人注入本人

class A {

  @Autowired
  A a;
  
  public void test() {
      // 这样应用切不到,是对象的外部调用
    this->setXxx();
    
    // 这样用就能够,因为注入的 a 实际上是 a 的代理
    a->setXxx();}
  
  @Xxxxx
  public xxx setXxx() {}
}

而这种依赖注入只能应用 @Autowired 的模式,不能应用构造函数的模式,构造函数模式会造成依赖注入的死循环。

总结

原来只会用 AOP 而不懂 AOP 的原理,认为他就如同 @before 的作用一样简略,直到遇到问题,能力了解 aop 的原理。

正文完
 0