【问题标题】:Spring - Autowire fails when adding an aspect-backed annotation to overridden methodSpring - 将支持方面的注释添加到覆盖的方法时,Autowire 失败
【发布时间】:2014-11-16 08:10:07
【问题描述】:

我有一个实现 org.springframework.security.core.userdetails.UserDetailsS​​ervice 的身份验证服务并定义为:

@Service
public class AuthService implements UserDetailsService {
    // Autowires ..

    @Override
    //@Logged(successMessage = "User %s logged in")
    public UserDetails loadUserByUsername(String username) { .. }
}

它被自动装配到 WebSecurityConfigurerAdapter 的扩展中,用于配置身份验证:

// Annotations ...
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private AuthService authService;

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception { 
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        auth.userDetailsService(authService).passwordEncoder(encoder);
    }
    // Other security config stuff ...
}

最后,我创建了一个名为@Logged 的​​自定义注解,它被一个切面拾取,该切面围绕通知应用到被注解的方法并执行一些日志记录逻辑。让我们说,如果你只传递一个参数给它,它会记录成功的返回。

将@Logged 注解应用于覆盖的 AuthService.loadUserByUsername 方法会导致应用程序在启动时崩溃,并显示有关无法将 AuthService 自动连接到 SecurityConfig 的消息。如果我不将注释放在该覆盖方法上,一切都会完美无缺 - 身份验证工作(完成自动装配)并且日志注释在系统的其他部分工作。

问题

为什么会发生这种情况,可以解决吗?

我真的很想用我喜欢的日志注释来记录那个确切的方法。 谢谢:)

技术细节

带有 Boot 的 Spring 4,Jetty 9

堆栈跟踪(部分):

2014-09-22 12:41:05 WARN AbstractLifeCycle - 失败 org.springframework.boot.context.embedded.jetty.ServletContextInitializerConfiguration$InitializerListener@8bb473: org.springframework.beans.factory.BeanCreationException: 使用名称创建 bean 时出错'org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration':自动装配依赖注入失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配方法:public void org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.setFilterChainProxySecurityConfigurer(org.springframework.security.config.annotation.ObjectPostProcessor, java.util.List) 抛出 java.lang.Exception;嵌套异常是 org.springframework.beans.factory.BeanExpressionException:表达式解析失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:创建名为“securityConfig”的 bean 时出错:注入自动装配的依赖项失败;嵌套异常是 org.springframework.beans.factory.BeanCreationException:无法自动装配字段:私有 com.bluepixelflag.services.AuthService com.bluepixelflag.config.SecurityConfig.authService;嵌套异常是 java.lang.IllegalArgumentException: Can not set com.bluepixelflag.services.AuthService field com.bluepixelflag.config.SecurityConfig.authService to com.sun.proxy.$Proxy90

【问题讨论】:

    标签: spring spring-security spring-aop


    【解决方案1】:

    Spring 正在使用代理向AuthService 添加方面。如果没有注释,它只会使用一个简单的类。

    改变

    private AuthService authService;

    private UserDetailsService authService;

    它应该可以工作。或者,使用 cglib 代理而不是 JDK 动态代理。

    另外:使用切面进行日志记录的目的是尽量避免每次日志调用只写一行代码。如果您对要记录的每个方法调用都使用方面注释,那么您并没有节省任何复杂性(实际上您已经增加了它),还不如在代码中调用一个记录器。

    【讨论】:

    • 感谢您的工作解决方案!我认为默认情况下所有@Service 注释类都是代理的 - 如果您能进一步澄清我错过的内容,我将不胜感激。关于日志记录——虽然我同意基于方面的日志记录是一对一交易的(我自己开发的方面支持多个异常,每个都有自己的消息),但需要引入大型 try-catch 块来记录消息会使代码混乱很多恕我直言。另外,我需要学习 AOP,而日志记录是探索的完美领域 :) 再次感谢您的帮助和时间!
    • @hoodieman 我收回 - 如果你的方面也尝试/捕获,那么它比普通的方法调用更好。就个人而言,我更喜欢单个故障屏障(请参阅oracle.com/technetwork/java/effective-exceptions-092345.html)以确保未捕获的异常只记录一次,但您的解决方案听起来也不错。
    猜你喜欢
    • 2019-04-09
    • 2010-11-11
    • 2021-05-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-01-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多