有在ABC.java定义了两个方法
public void method1(){
.........
method2();
...........
}
public void method2(){
...............
...............
}
我想有AOP对方法2。所以呼叫,我创建一个类,AOPLogger.java,具有在方法CheckAccess设置方面的功能
在配置文件中,我不喜欢的东西下面
<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>
但是,当我的方法2是所谓的,AOP的功能没有得到调用即checkAccess方法没有得到调用AOPLogger类的。
任何事情我失踪?
Answer 1:
The aspect is applied to a proxy surrounding the bean. Note that everytime you get a reference to a bean, it's not actually the class referenced in your config, but a synthetic class implementing the relevant interfaces, delegating to the actual class and adding functionality, such as your AOP.
In your above example you're calling directly on the class, whereas if that class instance is injected into another as a Spring bean, it's injected as its proxy, and hence method calls will be invoked on the proxy (and the aspects will be triggered)
If you want to achieve the above, you could split method1
/method2
into separate beans, or use a non-spring-orientated AOP framework.
The Spring doc (section "Understanding AOP Proxies") details this, and a couple of workarounds (including my first suggestion above)
Answer 2:
它可以通过自我注射使用来完成。 您可以通过调用注入实例内的方法:
@Component
public class Foo {
@Resource
private Foo foo;
public void method1(){
..
foo.method2();
..
}
public void method2(){
..
}
}
既然Spring 4.3,您还可以使用@Autowired做到这一点。
对于4.3,@Autowired也考虑用于注射的自我引用,即引用回到当前注入的豆。
Answer 3:
我有同样的问题,我克服了通过实现Spring的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();
...........
}
希望这可以帮助。
Answer 4:
Spring AOP框架是基于“代理”,它是在这里很好的解释: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-understanding- AOP-代理
当春天构建配置有一个方面(如“ABC”在你的例子)一个bean,它实际上创造了一个“代理”对象,就像真正的豆。 代理只是委托调用“真正”的对象,而是通过创建这个间接,代理都有机会实现“建议”。 例如,你的建议可以记录每个方法调用的消息。 在此方案中,如果现实对象(“方法1”)的方法调用同一个对象的其它方法(比如,方法2),这些电话发生没有在图片代理,所以没有机会为它实施的任何建议。
在你的榜样,当方法1()被调用时,代理将有机会做什么以往任何时候都应该做的,但如果方法1()调用方法2(),有在画面没有任何方面。 如何过,如果方法2是由别的豆叫,代理就可以进行咨询。
希望这可以帮助。
谢谢,Raghu
Answer 5:
使用@Autowired
它的工作原理。 而不是调用内部方法的this.method()
你可以这样做:
@Autowired
Foo foo;
然后调用:
foo.method2();
Answer 6:
这是不可能的,你想达到什么。 一种解释是在春季参考文档 。
Answer 7:
正如指出春文档 ,章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面对正在使用的事实。 这还需要在创建代理时,一些额外的配置。
Answer 8:
你可以做自我注射这种方式,使这个类可以外Spring应用程序中使用。
@Component
public class ABC {
@Resource
private ABC self = this;
public void method1() {
self.method2();
}
public void method2() {
}
}
Answer 9:
注释与@EnableAspectJAutoProxy(exposeProxy =真)调用并调用实例方法用((类)AopContext.currentProxy())方法();
严格来说这是不推荐,因为它增加了耦合
Answer 10:
我很惊讶没有人提到这一点,但我认为,我们可以使用Spring提供ControlFlowPointcut。
ControlFlowPointcut看着堆栈跟踪且仅当它发现在堆栈跟踪的特定方法的切入点匹配。 基本上切入点匹配只有当一个方法被称为在特定上下文。
在这种情况下,我们可以创建像切入点
ControlFlowPointcut cf = new ControlFlowPointcut(MyClass.class, "method1");
现在,使用ProxyFactory通过创建MyClass的实例的代理,并调用方法1()。
在上述情况下,只方法2()将被告知,因为它是从方法1()调用。
文章来源: Spring AOP not working for method call inside another method