source

다른 메서드 내부에서 메서드 호출에 대해 스프링 AOP가 작동하지 않습니다.

factcode 2023. 10. 26. 21:53
반응형

다른 메서드 내부에서 메서드 호출에 대해 스프링 AOP가 작동하지 않습니다.

ABC.java에는 두가지 방법이 정의되어 있습니다.

public void method1(){
   .........
   method2();
  ...........
}


public void method2(){
  ...............
  ...............  
}

method2에 AOP를 의뢰하고 싶습니다.그래서 반을 하나 만들었는데,AOPlogger.java, 메서드에서 제공되는 측면 기능 확인Access
컨피규레이션 파일에서 아래와 같은 작업을 했습니다.

<bean id="advice" class="p.AOPLogger" />
<aop:config>
  <aop:pointcut id="abc" expression="execution(*p.ABC.method2(..))" />
  <aop:aspect id="service" ref="advice">
    <aop:before pointcut-ref="abc" method="checkAccess" />          
  </aop:aspect>
</aop:config>

그러나 method2가 호출되면 AOP 기능이 호출되지 않습니다. 즉, checkAccess method는 AOPlogger 클래스가 호출되지 않습니다.

제가 놓친게 있나요?

그 양상은 콩을 둘러싼 프락시에 적용됩니다.빈에 대한 참조를 얻을 때마다 실제로는 구성에서 참조되는 클래스가 아니라 실제 클래스에 위임하고 AOP와 같은 기능을 추가하는 관련 인터페이스를 구현하는 합성 클래스입니다.

위의 예에서 클래스 인스턴스가 Spring bean으로 다른 인스턴스에 주입되면 프록시로 주입되므로 메서드 호출이 프록시에서 호출됩니다(그리고 요소가 트리거됩니다).

위의 것을 달성하고 싶다면, 당신은 분할할 수 있습니다.method1/method2별도의 콩으로 만들거나 스프링 방향이 아닌 AOP 프레임워크를 사용합니다.

Spring 문서("AOP 프록시 이해" 섹션)에는 이 내용과 몇 가지 해결 방법이 자세히 나와 있습니다(위의 첫 번째 제안 포함).

2022년 업데이트:

저는 개인적으로 여기에 설명된 트랜잭션 처리자 클래스를 훨씬 더 깨끗하고 유연하게 사용하는 것을 선호합니다.

원래 답변:

자가 주사로 가능합니다.주입된 인스턴스를 통해 내부 메서드를 호출할 수 있습니다.

@Component
public class Foo {
    @Resource
    private Foo foo;
    
    public void method1(){
        ..
        foo.method2();
        ..
    }
    public void method2(){
        ..
    }
}

Spring 4.3부터는 @Autowired를 사용할 수도 있습니다.

4.3에서 @Autowired는 주입에 대한 자체 참조, 즉 현재 주입된 콩에 대한 참조도 고려합니다.

봄 AOP 프레임워크는 "프록시" 기반이라고 이해 AOP 프록시의 문서에서 잘 설명하고 있습니다.

Spring은 예에서 "ABC"와 같이 측면으로 구성된 빈을 구성할 때 실제 빈과 같은 역할을 하는 "프록시" 객체를 생성합니다.프록시는 단순히 호출을 "실제" 개체에 위임하지만, 이 방향을 생성함으로써 프록시는 "조언"을 구현할 수 있는 기회를 얻습니다.예를 들어, 각 메서드 호출에 대한 메시지를 기록할 수 있습니다.이 방식에서, 실제 객체("method1")의 메소드가 동일한 객체(예: method2)의 다른 메소드를 호출하는 경우, 그러한 호출은 그림에서 프록시 없이 발생하므로, 그 메소드가 어떠한 조언도 구현할 기회가 없습니다.

예를 들어, method1()이 호출되면 프록시는 자신이 해야 할 일을 수행할 수 있는 기회를 얻지만 method1()이 method2()을 호출하면 그림에 측면이 없습니다.그러나 다른 빈에서 method2를 호출하면 프록시는 조언을 수행할 수 있습니다.

저도 같은 고민을 겪었고 스프링스를 실행하여 극복하였습니다.ApplicationContextAware,BeanNameAware아래와 같이 대응하는 방법을 구현합니다.

class ABC implements ApplicationContextAware,BeanNameAware{

      @Override
      public void setApplicationContext(ApplicationContext ac) throws BeansException {
          applicationContext=ac;
      }

      @Override
      public void setBeanName(String beanName) {
          this.beanName=beanName;
      }
      private ApplicationContext applicationContext;
      private String beanName;
}

그 다음에 교체했습니다.this.와 함께((ABC) applicationContext.getBean(beanName)).같은 클래스의 메소드를 부르면서 말이죠.이렇게 하면 프록시를 통해서만 같은 클래스의 메서드에 대한 호출이 발생합니다.

그렇게method1()에의 변경.

 public void method1(){
    .........
    ((ABC) applicationContext.getBean(beanName)).method2();
    ...........
  }

도움이 되길 바랍니다.

으로.@Autowired그건 효과가 있다.내부 방법을 다음과 같이 부르는 대신this.method(), 할 수 있습니다.

@Autowired
Foo foo;

그리고 전화를 걸었습니다.

foo.method2();

게으르다! 나도 같은 문제가 있었습니다.저는 레이지와 함께 오토와이어드를 사용하는데 작동합니다.

@Component
public class Foo {

    @Lazy
    @Autowired
    private Foo foo;
    
    public void method1(){
        ..
        foo.method2();
        ..
    }
    public void method2(){
        ..
    }
}

당신이 이루고 싶은 것은 가능하지 않습니다.설명은 스프링 참조 설명서에 있습니다.

Spring 문서 5.6.1장 AOP 프록시의 이해에 표시된 바와 같이, 다음과 같은 다른 방법이 있습니다.

public class SimplePojo implements Pojo {

    public void foo() {
        // this works, but... gah!
        ((Pojo) AopContext.currentProxy()).bar();
    }

    public void bar() {
        // some logic...
    }
}

비록 작가가 이런 식으로 추천하지는 않지만요.이유:

이것은 당신의 코드를 Spring AOP에 완전히 결합시키고, 그것은 클래스 자체가 AOP 상황에서 사용되고 있다는 사실을 인식하게 하고, 그것은 AOP에 직면하여 날아갑니다.또한 프록시를 생성할 때 추가 구성이 필요합니다.

@EnableAspect로 통화 주석 달기JAutoProxy(Proxy = true로 노출) 및 (Class) AopContext.currentProxy()를 사용하여 인스턴스 메서드를 호출합니다.방법 ();

이는 커플링으로 증가하므로 엄격하게 권장되지 않습니다.

아무도 이에 대해 언급하지 않아 놀랍지만 Spring에서 제공하는 ControlFlowPointcut을 사용할 수 있을 것 같습니다.

ControlFlowPointcut은 스택 트레이스를 보고 스택 트레이스에서 특정 메서드를 찾은 경우에만 포인트 컷을 일치시킵니다.기본적으로 포인트컷은 메소드가 특정 컨텍스트에서 호출될 때만 일치합니다.

이 경우에는 다음과 같은 포인트 컷을 만들 수 있습니다.

ControlFlowPointcut cf = new ControlFlowPointcut(MyClass.class, "method1");

ProxyFactory를 사용하여 MyClass 인스턴스에 프록시를 만들고 method1()을 호출합니다.

위의 경우 method1()에서 호출되므로 method2()만 권장됩니다.

다른 방법은 메서드 2()를 다른 클래스 파일로 모드화하는 것이며 해당 클래스에는 @Component로 주석이 달립니다.그런 다음 필요할 때 @Autowired를 사용하여 주입합니다.이런 식으로 AOP가 그걸 가로챌 수 있습니다.

예:

You were doing this...


Class demo{
   method1(){
    -------
    -------
    method2();
    -------
    -------
   }

   method2(){
    ------
    -----
   }
}

Now if possible do this :

@Component
class NewClass{
    method2(){
    ------
    -----
   }
}


Class demo{

 @AutoWired
 NewClass newClass;

   method1(){
    -------
    -------
    newClass.method2();
    -------
    -------
   }

}

다음 질문을 참조할 수 있습니다: https://stackoverflow.com/a/30611671/7278126

이것은 해결책이지만 요령을 부릴 것입니다. 여기서 핵심은 이것 대신에 같은 빈(프록시)을 사용하여 'method2'를 호출하는 것입니다.

많은 연구 끝에 다음과 같이 매력적으로 작용하는 것을 발견했습니다.하지만 ASPECTJ 위빙에는 언제나 더 좋은 방법이 있습니다.시간의 본질은 자기 기준을 사용합니다.

@Autowired
private ApplicationContext applicationContext;
private <<BEAN>> self;

<>은 AOP와 함께 기록하거나 다른 용도로 사용해야 하는 동일한 클래스임을 유의하시기 바랍니다.

@PostConstruct
private void init() {
    self = applicationContext.getBean(MyBean.class);
}

이 변경을 통해 통화 내용을 이동하기만 하면 됩니다.

this.methodName(args) -> self.methodName(args)

이것이 애플리케이션에서 성능 로깅만을 위한 솔루션을 사용하고자 하는 모든 사람들에게 도움이 되기를 바랍니다.

이렇게 할 수 있습니다.

@Autowired // to make this bean refers to proxy class 

ABC self;

public void method1(){

   .........

   self.method2();

  ...........

}


public void method2(){

  ...............

  ...............  

}

AOP는 호출자가 호출자와 같은 클래스일 경우 함수를 감쌀 수 없도록 합니다.

그러나 자기 주입을 사용함으로써 위를 달성하기 위해 아래 작업을 수행할 수 있습니다.

public class Test {


  @Autowire 
  private Test test;


  public void method1(){
     .........
     test.method2();
    ...........
  }


  public void method2(){
    ...............
    ...............  
  }
}

내가 자기 주사를 한 것을 알아차리다.

  @Autowire 
  private Test test;

방법 2는 제가 전화를 했습니다.test.method2();대신에this.method2()

이 클래스를 Spring 어플리케이션 외부에서 사용할 수 있도록 이 방법으로 자가 주입을 수행할 수 있습니다.

@Component
public class ABC {

    @Resource
    private ABC self = this;

    public void method1() {
        self.method2();
    }

    public void method2() {

    }

}

언급URL : https://stackoverflow.com/questions/13564627/spring-aop-not-working-for-method-call-inside-another-method

반응형