gpt4 book ai didi

java - 我如何(或应该)将方面建议应用于动态代理?

转载 作者:行者123 更新时间:2023-12-01 21:22:25 25 4
gpt4 key购买 nike

假设我的 Spring AOP 配置如下

@Configuration
@EnableAspectJAutoProxy
@ComponentScan
class Config { ... }

我有一些接口(interface),ProxiableInterface。我用

来实现它
ProxiableInterface pi = (ProxiableInterface) Proxy.newProxyInstance(
applicationContext.getClassLoader(),
new Class[] {ProxiableInterface.class},
(proxy, method, args) -> { ... });

我还有一个方面:

@Aspect
class SomeAspect {
@Around("execution(package.ProxiableInterface.*)")
Object doStuffAround(ProceedingJoinPoint pjp) { ... }
}

当我调用 ProxiableInterface 上的方法时,不会调用 Aspect 方法。有没有一种方法可以“注册”此代理以便得到建议?我可以简单地在代理的 InvocableHandler 中执行该建议的操作,但这会导致代码重复,因为该建议也已适用于代码的其他区域。

最佳答案

我找到的解决方案是使用org.springframework.aop.aspectj.annotation.AspectJProxyFactory

在我的例子中,一个额外的复杂性是我想要代理的类是抽象的,而不是接口(interface),这意味着 Spring 必须使用 CGLIB 而不是 JDK 代理来代理它。然而,事实证明,这在某种程度上更有用,而不是令人讨厌。

首先,我有一个抽象类:

public abstract class Something {

abstract void doWhatever();

@Override
public final boolean equals(Object o) {
return this == o;
}

@Override
public final int hashCode() {
return System.identityHashCode(this);
}

@Override
public final String toString() {
return getClass().getName() + " " + hashCode();
}
}

(我重写了一些对象方法并将它们设为final,因为否则它们会被代理,但在这种情况下,我需要为它们编写建议。)

然后我有一个 AspectJProxyFactory 和一个具有原型(prototype)范围的 bean,如下所示:

@Configuration
@EnableAspectJAutoProxy
class Config {

private static final AspectJProxyFactory proxyFactory = new AspectJProxyFactory();
static {
proxyFactory.setTargetClass(Something.class);
proxyFactory.addAspect(SomeAspect.class);
}

@Bean
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
Something something() {

return proxyFactory.getProxy();
}
}

请注意,Something 必须是 Spring AOP 才能识别的 bean。这是方面:

@Aspect
public class SomeAspect {

@Around("execution(void org.luc.Something.doWhatever())")
void around(ProceedingJoinPoint pjp) throws Throwable {

System.out.println(pjp.getThis().toString() + ": I've been advised");
}
}

这样我就可以从代理工厂获取不同的实例,这将由 AOP 自动代理通知。

    Something something1 = applicationContext.getBean(Something.class);
Something something2 = applicationContext.getBean(Something.class);

Assert.assertEquals(something1, something1);
Assert.assertNotEquals(something1, something2);

something1.doWhatever();
something2.doWhatever();

这会打印出类似的内容:

org.luc.Something$$EnhancerBySpringCGLIB$$cadae9a8 638486177: I've been advised org.luc.Something$$EnhancerBySpringCGLIB$$cadae9a8 426019904: I've been advised

关于java - 我如何(或应该)将方面建议应用于动态代理?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38923984/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com