数百万次 addAspect(sameAspect) 有什么缺点吗?

问题描述 投票:0回答:1

我正在编写的代码需要拦截对对象#2(外部库的一部分)的调用,该对象由对象#1(也在外部库中)即时实例化/检索。

因此,我拦截对象#1,然后向对象#2 添加一个方面;这样我可以获得调用次数、抛出的异常、响应时间等

// My aspect intercepts object #1 that retrieves object #2 and adds the aspect
Object obj2 = joinPoint.proceed();
AspectJProxyFactory proxyFactory = new AspectJProxyFactory(obj2);
proxyFactory.addAspect(this);

现在,由于

obj2
将被检索数百万次,当一遍又一遍地调用(添加方面)时,
proxyFactory.addAspect(this);
会随着时间的推移而降低应用程序的性能,或者这个调用是幂等的并且几乎没有副作用吗?

注意:我猜 obj2 只会被实例化几次,然后它会一遍又一遍地成为同一个对象,但我对此不能肯定,因为它是一个外部的、封闭的源码库。

java spring aspectj
1个回答
0
投票

就像我在评论中所说,只需使用本机 AspectJ,最好通过 加载时编织 (LTW),因为这样您还可以拦截第三方类,而无需繁琐的编译后二进制编织和现有 JAR 的重新打包。超级简单,超级高效。

FWIW,你的 Spring AOP 问题很有趣,值得考虑一下。如果您出于某种原因对重复和冗余地创建代理工厂、代理并将它们链接到方面时的性能不满意,只需将目标实例缓存在弱哈希映射中,使用原始实例作为键,使用代理作为值。它基本上看起来像这样:

package de.scrum_master.spring.q77417629;

public class MyPojo {
  public void doPojoStuff() {}
}
package de.scrum_master.spring.q77417629;

import org.springframework.stereotype.Component;

@Component
public class MyComponent {
  private final MyPojo myPojo;

  public MyComponent() {
    myPojo = new MyPojo();
  }

  public MyPojo doComponentStuff() {
    return myPojo;
  }
}

如您所见,组件始终返回相同的 POJO 实例,即它应该是可缓存的。

package de.scrum_master.spring.q77417629;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;
import org.springframework.stereotype.Component;

import java.util.WeakHashMap;

@Aspect
@Component
public class MyAspect {
  private final WeakHashMap<Object, Object> proxyTargets = new WeakHashMap<>();

  @Around("execution(* MyComponent.doComponentStuff())")
  public Object interceptMyComponent(ProceedingJoinPoint joinPoint) throws Throwable {
    Object result = joinPoint.proceed();
    if (proxyTargets.containsKey(result)) {
      System.out.println("Existing proxy target " + result);
      return proxyTargets.get(result);
    }
    System.out.println("New proxy target " + result);
    AspectJProxyFactory proxyFactory = new AspectJProxyFactory(result);
    proxyFactory.addAspect(this);
    Object proxy = proxyFactory.getProxy();
    proxyTargets.put(result, proxy);
    return proxy;
  }

  @Before("within(de.scrum_master.spring.q77417629..*)")
  public void log(JoinPoint joinPoint) {
    System.out.println(joinPoint);
  }
}
package de.scrum_master.spring.q77417629;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@SpringBootApplication
@Configuration
@EnableAspectJAutoProxy
public class DemoApplication {
  public static void main(String[] args) {
    try (ConfigurableApplicationContext context = SpringApplication.run(DemoApplication.class, args)) {
      // The POJO is not proxied yet,i.e. the aspect should not fire
      new MyPojo().doPojoStuff();
      new MyPojo().doPojoStuff();
      new MyPojo().doPojoStuff();

      MyComponent component = context.getBean(MyComponent.class);

      // The first time doComponentStuff() is intercepted by the aspect, the proxy factory
      // should bind an aspect to its return value, a MyPojo instance. The subsequent
      // doPojoStuff() call should immediately be intercepted by the second aspect advice.
      component.doComponentStuff().doPojoStuff();
      // All future doComponentStuff() is interceptions should use the cached MyPojo instance.
      component.doComponentStuff().doPojoStuff();
      component.doComponentStuff().doPojoStuff();
    }
  }
}

控制台日志显示其工作原理:

execution(MyPojo de.scrum_master.spring.q77417629.MyComponent.doComponentStuff())
New proxy target de.scrum_master.spring.q77417629.MyPojo@43e7f104
execution(void de.scrum_master.spring.q77417629.MyPojo.doPojoStuff())
execution(MyPojo de.scrum_master.spring.q77417629.MyComponent.doComponentStuff())
Existing proxy target de.scrum_master.spring.q77417629.MyPojo@43e7f104
execution(void de.scrum_master.spring.q77417629.MyPojo.doPojoStuff())
execution(MyPojo de.scrum_master.spring.q77417629.MyComponent.doComponentStuff())
Existing proxy target de.scrum_master.spring.q77417629.MyPojo@43e7f104
execution(void de.scrum_master.spring.q77417629.MyPojo.doPojoStuff())
© www.soinside.com 2019 - 2024. All rights reserved.