方面捕获额外的切入点
我在 Spring Boot 服务启动时收到这些消息。
Unable to proxy interface-implementing method [public final void org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest,javax.servlet.ServletResponse,javax.servlet.FilterChain) throws javax.servlet.ServletException,java.io.IOException] because it is marked as final: Consider using interface-based JDK proxies instead!
Unable to proxy interface-implementing method [public final void org.springframework.web.filter.GenericFilterBean.init(javax.servlet.FilterConfig) throws javax.servlet.ServletException] because it is marked as final: Consider using interface-based JDK proxies instead!
问题是我无法弄清楚我的切入点选择了哪些类导致了这种情况:
我的方面文件:
@Around("execution(public * com.torchai..*.*(..)) "
+ "&& loggingEnabledAndNotDisabled()"
+ "&& !allPublicControllerMethodsNotDisabled()"
+ "&& !allPublicControllerLayerMethodsNotDisabled()"
+ "&& !allPublicServiceMethodsNotDisabled()"
+ "&& !allPublicServiceLayerMethodsNotDisabled()")
public Object allPublicMethodsNotDisabledAndNotControllerOrService(
final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return log(proceedingJoinPoint, LogEvent.LAYER_OTHER);
}
@AfterThrowing(
pointcut = "execution(public * com.torchai..*.*(..)) "
+ "&& loggingEnabledAndNotDisabled()"
+ "&& !allPublicControllerMethodsNotDisabled()"
+ "&& !allPublicControllerLayerMethodsNotDisabled()"
+ "&& !allPublicServiceMethodsNotDisabled()"
+ "&& !allPublicServiceLayerMethodsNotDisabled()",
throwing = "t")
public void allPublicMethodsNotDisabledAndNotControllerOrService(
final JoinPoint joinPoint, final Throwable t) {
onException(joinPoint, t, LogEvent.LAYER_OTHER);
}
我没有粘贴所有支持的切入点,但您可以看到它们对于 @Around 是相同的
和@AfterThrowing
。这些切点此时不应选择任何内容。
我发现真正有趣的是,如果我完全注释掉 @Around
代码,问题仍然存在。
但是,如果我保留 @Around
代码并注释掉 @AfterThrowing
,问题就消失了。
因此,即使这两件事在它们选择的内容方面应该是等效的,但出于某种原因 @AfterThrowing
正在选择导致问题的内容。
更新
@kriegaex 感谢您的回复。这是我的其他切入点。只是想让事情变得简单,不包括它们。
@Pointcut("@annotation(com.torchai.service.aspect.annotations.AspectLog) "
+ "|| @target(com.torchai.service.aspect.annotations.AspectLog)")
public void methodOrClassLoggingEnabled() {
}
@Pointcut("!@annotation(com.torchai.service.aspect.annotations.AspectNoLog)")
public void methodLoggingNotDisabled() {
}
@Pointcut("methodOrClassLoggingEnabled() && methodLoggingNotDisabled()")
public void loggingEnabledAndNotDisabled() {
}
/**
* Any public methods in classes which are specifically annotated as a Controller
*/
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *) ||"
+ "within(@org.springframework.stereotype.Controller *)")
public void allPublicControllerMethods() {
}
/**
* Any public methods in classes which are specifically annotated as a Service
*/
@Pointcut("within(@org.springframework.stereotype.Service *)")
public void allPublicServiceMethods() {
}
// Controller classes are enabled by default, so don't need to be specifically enabled.
@Pointcut("allPublicControllerMethods() "
+ "&& methodLoggingNotDisabled()")
public void allPublicControllerMethodsNotDisabled() {
}
// Service classes are enabled by default, so don't need to be specifically enabled.
@Pointcut("allPublicServiceMethods() "
+ "&& methodLoggingNotDisabled()")
public void allPublicServiceMethodsNotDisabled() {
}
// Components which aren't Service classes, but in the service package need to be enabled with @AspectLog
@Pointcut("execution(public * com.torchai.service..service..*(..)) "
+ "&& loggingEnabledAndNotDisabled()")
public void allPublicServiceLayerMethodsNotDisabled() {
}
// Components which aren't Controller classes, but in the controller package need to be enabled with @AspectLog
@Pointcut("execution(public * com.torchai.service..controller..*(..)) "
+ "&& loggingEnabledAndNotDisabled()")
public void allPublicControllerLayerMethodsNotDisabled() {
}
@Around("allPublicControllerMethodsNotDisabled() "
+ "|| allPublicControllerLayerMethodsNotDisabled()")
public Object logController(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return log(proceedingJoinPoint, LogEvent.LAYER_CONTROLLER);
}
@Around("allPublicServiceMethodsNotDisabled() "
+ "|| allPublicServiceLayerMethodsNotDisabled()")
public Object logService(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return log(proceedingJoinPoint, LogEvent.LAYER_SERVICE);
}
我理解该消息的基本含义,尽管不可否认,我不确定如何做 JDK 代理。但我认为其实没有必要。我们确实有一个实现了 OncePerRequestFilter
的 Filter 类,但我不能确定这就是被选中的那个,因为它没有说。
但我真正的困惑不仅仅是一个我没有预料到的类被拾取,而且它似乎只被 @AfterThrowing
拾取,而不是被 @Around< /代码> .为什么这些不完全相同?
更新 #2(几分钟后)
我认为这可能与我使用的 execution
有关,而不是您对 within
的建议。我不完全理解其中的区别。但 @AfterThrowing
和 @Around
中的定义仍然相同。即使我使用执行
,它仍然需要匹配其他条件。
更新 #3
我创建了一个显示问题的存储库: https://github.com/peterkronenberg/aoptest< /a>
在启动时,Springboot 发出以下消息:
2022-03-24 15:58:57.261 INFO 35104 --- [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy interface-implementing method [public final void org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest,javax.servlet.ServletResponse,javax.servlet.FilterChain) throws javax.servlet.ServletException,java.io.IOException] because it is marked as final: Consider using interface-based JDK proxies instead!
2022-03-24 15:58:57.261 INFO 35104 --- [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy interface-implementing method [public final void org.springframework.web.filter.GenericFilterBean.init(javax.servlet.FilterConfig) throws javax.servlet.ServletException] because it is marked as final: Consider using interface-based JDK proxies instead!
2022-03-24 15:58:57.310 ERROR 35104 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Exception starting filter [authFilter]
服务未启动,这不是我最初看到的。但也许这提供了更多线索。但是,如果我禁用了 Aspect 代码,只需注释掉 AspectLayer
类中的 @Aspect
注释,那么它似乎就可以工作。 不知何故,我的方面代码和过滤器代码之间存在冲突,
我不希望我的方面代码选取我的 AuthFilter 类。我相信这就是导致问题的原因,尽管我不确定为什么
I've been getting these messages at startup of my Spring Boot service.
Unable to proxy interface-implementing method [public final void org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest,javax.servlet.ServletResponse,javax.servlet.FilterChain) throws javax.servlet.ServletException,java.io.IOException] because it is marked as final: Consider using interface-based JDK proxies instead!
Unable to proxy interface-implementing method [public final void org.springframework.web.filter.GenericFilterBean.init(javax.servlet.FilterConfig) throws javax.servlet.ServletException] because it is marked as final: Consider using interface-based JDK proxies instead!
The problem's I can't figure out what classes are getting selected by my Pointcut that is causing this:
My Aspect file:
@Around("execution(public * com.torchai..*.*(..)) "
+ "&& loggingEnabledAndNotDisabled()"
+ "&& !allPublicControllerMethodsNotDisabled()"
+ "&& !allPublicControllerLayerMethodsNotDisabled()"
+ "&& !allPublicServiceMethodsNotDisabled()"
+ "&& !allPublicServiceLayerMethodsNotDisabled()")
public Object allPublicMethodsNotDisabledAndNotControllerOrService(
final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return log(proceedingJoinPoint, LogEvent.LAYER_OTHER);
}
@AfterThrowing(
pointcut = "execution(public * com.torchai..*.*(..)) "
+ "&& loggingEnabledAndNotDisabled()"
+ "&& !allPublicControllerMethodsNotDisabled()"
+ "&& !allPublicControllerLayerMethodsNotDisabled()"
+ "&& !allPublicServiceMethodsNotDisabled()"
+ "&& !allPublicServiceLayerMethodsNotDisabled()",
throwing = "t")
public void allPublicMethodsNotDisabledAndNotControllerOrService(
final JoinPoint joinPoint, final Throwable t) {
onException(joinPoint, t, LogEvent.LAYER_OTHER);
}
I'm not pasting in all the supporting Pointcuts, but you can see they are the same for @Around
and @AfterThrowing
. These points cuts should not be selecting anything at this point.
What I find really interesting is if I totally comment out the @Around
code, the problem is still there.
But if I leave the @Around
code and comment out @AfterThrowing
, the problem is gone.
So even though these 2 things should be equivalent in terms of what they select, for some reason @AfterThrowing
is selecting something that is causing the problem.
Update
@kriegaex Thanks for your through response. Here are my other pointcuts. Was just trying to keep things simple by not including them.
@Pointcut("@annotation(com.torchai.service.aspect.annotations.AspectLog) "
+ "|| @target(com.torchai.service.aspect.annotations.AspectLog)")
public void methodOrClassLoggingEnabled() {
}
@Pointcut("!@annotation(com.torchai.service.aspect.annotations.AspectNoLog)")
public void methodLoggingNotDisabled() {
}
@Pointcut("methodOrClassLoggingEnabled() && methodLoggingNotDisabled()")
public void loggingEnabledAndNotDisabled() {
}
/**
* Any public methods in classes which are specifically annotated as a Controller
*/
@Pointcut("within(@org.springframework.web.bind.annotation.RestController *) ||"
+ "within(@org.springframework.stereotype.Controller *)")
public void allPublicControllerMethods() {
}
/**
* Any public methods in classes which are specifically annotated as a Service
*/
@Pointcut("within(@org.springframework.stereotype.Service *)")
public void allPublicServiceMethods() {
}
// Controller classes are enabled by default, so don't need to be specifically enabled.
@Pointcut("allPublicControllerMethods() "
+ "&& methodLoggingNotDisabled()")
public void allPublicControllerMethodsNotDisabled() {
}
// Service classes are enabled by default, so don't need to be specifically enabled.
@Pointcut("allPublicServiceMethods() "
+ "&& methodLoggingNotDisabled()")
public void allPublicServiceMethodsNotDisabled() {
}
// Components which aren't Service classes, but in the service package need to be enabled with @AspectLog
@Pointcut("execution(public * com.torchai.service..service..*(..)) "
+ "&& loggingEnabledAndNotDisabled()")
public void allPublicServiceLayerMethodsNotDisabled() {
}
// Components which aren't Controller classes, but in the controller package need to be enabled with @AspectLog
@Pointcut("execution(public * com.torchai.service..controller..*(..)) "
+ "&& loggingEnabledAndNotDisabled()")
public void allPublicControllerLayerMethodsNotDisabled() {
}
@Around("allPublicControllerMethodsNotDisabled() "
+ "|| allPublicControllerLayerMethodsNotDisabled()")
public Object logController(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return log(proceedingJoinPoint, LogEvent.LAYER_CONTROLLER);
}
@Around("allPublicServiceMethodsNotDisabled() "
+ "|| allPublicServiceLayerMethodsNotDisabled()")
public Object logService(final ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
return log(proceedingJoinPoint, LogEvent.LAYER_SERVICE);
}
I understand the basic meaning of the message, although admittedly, I'm not sure how to do the JDK proxy instead. But I don't think it really necessary. We do have a Filter class which implements OncePerRequestFilter
, but I can't be sure that that is the one getting picked up, because it doesn't say.
But my real confusion is not just that a class is getting picked up that I didn't expect, but that it seems to only get picked up by the @AfterThrowing
and not by @Around
. Why wouldn't these be exactly the same?
Update #2 (a few minutes later)
I'm thinking this might have something to do with my used of execution
as opposed to your suggestion of within
. I don't fully understand the difference. But still, the definitions in @AfterThrowing
and @Around
are the same. And even where I'm using execution
, it still needs to match the other conditions.
Update #3
I've created a repo that shows the problem: https://github.com/peterkronenberg/aoptest
At startup, Springboot issues these messages:
2022-03-24 15:58:57.261 INFO 35104 --- [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy interface-implementing method [public final void org.springframework.web.filter.OncePerRequestFilter.doFilter(javax.servlet.ServletRequest,javax.servlet.ServletResponse,javax.servlet.FilterChain) throws javax.servlet.ServletException,java.io.IOException] because it is marked as final: Consider using interface-based JDK proxies instead!
2022-03-24 15:58:57.261 INFO 35104 --- [ main] o.s.aop.framework.CglibAopProxy : Unable to proxy interface-implementing method [public final void org.springframework.web.filter.GenericFilterBean.init(javax.servlet.FilterConfig) throws javax.servlet.ServletException] because it is marked as final: Consider using interface-based JDK proxies instead!
2022-03-24 15:58:57.310 ERROR 35104 --- [ main] o.a.c.c.C.[Tomcat].[localhost].[/] : Exception starting filter [authFilter]
The service doesn't start up, which is not what I was seeing originally. But maybe that provides more clues. But if I disabled the Aspect code, simply by commenting out the @Aspect
annotation in the AspectLayer
class, then it seems to work.
Somehow, there is a conflict between my Aspect code and my Filter code
I do not want my AuthFilter class to be picked up by my Aspect code. I believe that's what is causing the problem, although I'm not sure why
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
让我们检查带有一些额外换行符的错误消息:
这意味着
OncePerRequestFilter
的Filter
类Spring AOP 正在尝试代理它。OncePerRequestFilter
实现了Filter
的接口方法doFilter
,但由于某种原因将其声明为final
。即,代理过滤器时,无法代理来自父类的final方法。如果稍后您在代理实例上调用它,它实际上最终会出现在原始对象中。您无法使用方面、顾问程序或方法拦截器来连接它。现在,关于您对 Spring AOP 完全针对某些类的惊讶,您需要了解许多切入点正在动态评估,特别是当它们包含诸如
this()
、之类的内容时target()
、@(target)
等需要运行时信息。用户常常会惊讶于他们的通用切入点似乎“代理了世界”,甚至经常包括 Spring 自己的框架 bean。通常,您可以通过使用诸如&& 之类的内容来确定切入点的范围来限制这一点。在(org.acme.myapp..**)内。你可以尝试一下。由于无法看到您的许多切入点,我只能推测它们可能包含什么内容,但就像软件开发中经常出现的那样,魔鬼在于细节。
问题编辑后更新:就像我之前推测的那样,您正在使用动态切入点,例如
@target
和@annotation
以及一堆inside(@org.springframework..* *)
内容也针对 Spring 自己的 bean。但我缺少的是一些特定于应用程序的包范围&&在(org.acme.myapp..**)
内,就像我之前建议的那样。所以我之前所说的一切仍然有效。您既没有报告是否尝试过该操作以及效果如何,也没有说明是否发现扩展了OncePerRequestFilter
和GenericFilterBean
的 bean。Let us inspect the error message with some extra line breaks:
What that means is that
Filter
class extendingOncePerRequestFilter
andOncePerRequestFilter
implements an interface methoddoFilter
fromFilter
, but for some reason declares itfinal
. I.e., when proxying the filter, the final method from the parent class cannot be proxied. If later you call it on the proxy instance, it actually ends up in the original object. You cannot hook into it with aspects, advisors or method interceptors.Now with regard to your astonishment that some classes are being targeted at all by Spring AOP, you need to understand that many pointcuts are being evaluated dynamically, especially if they contain things like
this()
,target()
,@(target)
etc. which need runtime information. Users are often surprised that their generic pointcuts seem to "proxy the world", often even including Spring's own framework beans. Usually, you can limit that by scoping the pointcuts with something like&& within(org.acme.myapp..**)
. You can try that. Not being able to see your many pointcuts, I can only speculate what they might contain, but like so often in software development the devil is in the details.Update after question edit: Like I speculated before, you are using dynamic pointcuts such as
@target
and@annotation
and a bunch ofwithin(@org.springframework..* *)
stuff which also targets Spring's own beans. But what I am missing is some application-specific package scoping&& within(org.acme.myapp..**)
, like I suggested before. So all of what I said before still holds. Neither have you reported back on whether you tried that and what the effect was, nor have you said if you found the bean(s) extendingOncePerRequestFilter
andGenericFilterBean
.