ABC.java
中定义了两种方法public void method1(){
.........
method2();
...........
}
public void method2(){
...............
...............
}
我希望在 method2 的电话中使用AOP。所以, 我创建了一个类 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>
但是当我的method2被调用时,AOP功能没有被调用,即 checkAccess 方法没有被AOPLogger类调用。
我错过了什么?
答案 0 :(得分:56)
该方面适用于围绕bean的代理。请注意,每次获得对bean的引用时,它实际上不是配置中引用的类,而是实现相关接口的合成类,委托给实际类并添加功能,例如AOP。
在上面的示例中,您在类上直接调用 ,而如果将该类实例作为Spring bean注入到另一个类中,则将其作为代理注入,因此将调用方法调用在代理上(并且将触发方面)
如果要实现上述目标,可以将method1
/ method2
拆分为单独的bean,或使用非弹簧导向的AOP框架。
Spring doc (section "Understanding AOP Proxies")详细介绍了这一点,以及几个解决方法(包括我上面的第一个建议)
答案 1 :(得分:30)
可以通过自我注射使用来完成。您可以通过注入实例调用内部方法:
@Component
public class Foo {
@Resource
private Foo foo;
public void method1(){
..
foo.method2();
..
}
public void method2(){
..
}
}
从Spring 4.3开始,你也可以使用@Autowired。
从4.3开始,@ Autowired还考虑自我注射, 即引用回到当前注入的bean。
答案 2 :(得分:5)
我遇到了同样的问题,我通过实施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();
...........
}
希望这有帮助。
答案 3 :(得分:3)
Spring AOP框架是基于“代理”的,在这里解释得非常好: http://static.springsource.org/spring/docs/3.1.x/spring-framework-reference/html/aop.html#aop-understanding-aop-proxies
当Spring构造一个配置了方面的bean(在你的例子中就像“ABC”)时,它实际上创建了一个“代理”对象,就像真正的bean一样。代理只是将调用委托给“真实”对象,但通过创建这种间接,代理有机会实现“建议”。例如,您的建议可以为每个方法调用记录一条消息。在这个方案中,如果真实对象中的方法(“method1”)调用同一个对象中的其他方法(比如,method2),那些调用在图片中没有代理就会发生,因此它没有机会实现任何建议。
在你的例子中,当调用method1()时,代理将有机会做它应该做的事情,但是如果method1()调用method2(),则图片中没有方面。但是,如果从其他bean调用method2,代理将能够执行建议。
希望这有帮助。
谢谢, Raghu
答案 4 :(得分:2)
使用@Autowired
它有效。
您可以执行以下操作,而不是将内部方法调用为this.method()
:
@Autowired
Foo foo;
然后致电:
foo.method2();
答案 5 :(得分:0)
你想要实现的目标是不可能的。解释在Spring Reference Documentation。
答案 6 :(得分:0)
如Spring docs的第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却是这样。创建代理时,还需要一些其他配置。
答案 7 :(得分:0)
您可以通过这种方式进行自我注入,以便此类可以在Spring应用程序之外使用。
@Component
public class ABC {
@Resource
private ABC self = this;
public void method1() {
self.method2();
}
public void method2() {
}
}
答案 8 :(得分:0)
使用@EnableAspectJAutoProxy(exposeProxy = true)注释调用并使用((Class)AopContext.currentProxy())。method();调用实例方法
不建议这样做,因为它会增加耦合
答案 9 :(得分:0)
我很惊讶没有人提到这一点,但是我认为我们可以使用Spring提供的ControlFlowPointcut。
ControlFlowPointcut会查看stacktrace并仅在它在stacktrace中找到特定方法时才与切入点匹配。本质上,切入点只有在特定上下文中调用方法时才匹配。
在这种情况下,我们可以像
一样创建切入点。ControlFlowPointcut cf = new ControlFlowPointcut(MyClass.class, "method1");
现在,使用ProxyFactory在MyClass实例上创建一个代理,然后调用method1()。
在上述情况下,仅建议使用method2(),因为它是从method1()调用的。
答案 10 :(得分:0)
另一种解决方法是将method2()设置为其他类文件,并使用@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();
-------
-------
}
}
答案 11 :(得分:0)
您可以参考以下问题:https://stackoverflow.com/a/30611671/7278126
这是一种解决方法,但可以解决问题,这里的关键是使用相同的bean(代理)来代替“ method2”来调用。
答案 12 :(得分:0)
你可以这样做:
@Autowired // to make this bean refers to proxy class
ABC self;
public void method1(){
.........
self.method2();
...........
}
public void method2(){
...............
...............
}