【问题标题】:Aspect not executed in Spring方面未在 Spring 中执行
【发布时间】:2012-02-16 12:01:00
【问题描述】:

我正在编写一个几乎完全受登录保护的网站(我正在使用 Spring Security)。但是,某些页面不受保护(主页、登录页面、注册页面、忘记密码页面……),而我想要实现的是:

  • 如果用户在访问这些非安全页面时没有登录, 正常显示
  • 如果用户已经登录,重定向到 主页(或到redirectTo 注释元素中指定的页面)

当然我想避免把它放在每个控制器方法中:

if(loggedIn())
{
    // Redirect
}
else
{
    // Return the view
}

出于这个原因,我想使用 AOP。

我创建了注解@NonSecured,并编写了以下方面:

@Aspect
public class LoggedInRedirectAspect
{
    @Autowired
    private UserService userService;

    @Around("execution(@my.package.annotation.NonSecured * *(..))")
    public void redirect(ProceedingJoinPoint point) throws Throwable
    {
        System.out.println("Test");
        point.proceed();
    }
}

示例注释方法:

@Controller
@RequestMapping("/")
public class HomeController
{
    @NonSecured(redirectTo = "my-profile")
    @RequestMapping(method = RequestMethod.GET)
    public String index(Model model,
                        HttpServletRequest request) throws Exception
    {
        // Show home page
    }
}

applicationContext.xml 重要位:

<context:annotation-config />
<context:component-scan base-package="my.package" />

<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

<bean id="loggedInRedirectAspect" class="my.package.aspect.LoggedInRedirectAspect" />
<aop:aspectj-autoproxy proxy-target-class="true">
    <aop:include name="loggedInRedirectAspect" />
</aop:aspectj-autoproxy>

问题是方面中的方法redirect(...) 永远不会被调用。 Aspects 工作正常,事实上,Aspect 中的以下方法将被调用: 以下建议被调用,但不会被控制器方法调用。

@Around("execution(* *(..))")
public void redirect(ProceedingJoinPoint point) throws Throwable
{
    point.proceed();
}

我的切入点做错了吗?

谢谢。

更新:这个问题中的最后一个 sn-p 被调用,但仍然没有被控制器方法调用。

【问题讨论】:

    标签: spring spring-mvc spring-aop


    【解决方案1】:

    @satoshi,我认为您遇到的问题是因为您使用的是 Spring-AOP,它只能为具有接口的 bean 创建 AOP 代理 - 在您的情况下,控制器没有接口。

    修复方法可能是使用 AspectJ 进行编译时间/加载时间编织,不使用 Spring AOP 或在类路径中包含 cglib jar 并强制创建基于 cglib 的代理:

    <aop:aspectj-autoproxy proxy-target-class="true"/>
    

    更新: 编译时编织可以使用 maven 插件完成,showWeaveInfo 配置将准确显示哪些类已被编织:

    <plugin>
        <groupId>org.codehaus.mojo</groupId>
        <artifactId>aspectj-maven-plugin</artifactId>
        <version>1.0</version>
        <dependencies>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjrt</artifactId>
                <version>1.6.10</version>
            </dependency>
            <dependency>
                <groupId>org.aspectj</groupId>
                <artifactId>aspectjtools</artifactId>
                <version>1.6.10</version>
            </dependency>
        </dependencies>
        <executions>
            <execution>
                <goals>
                    <goal>compile</goal>
                    <goal>test-compile</goal>
                </goals>
            </execution>
        </executions>
        <configuration>
            <outxml>true</outxml>
            <verbose>true</verbose>
            <showWeaveInfo>true</showWeaveInfo>
            <aspectLibraries>
                <aspectLibrary>
                    <groupId>org.springframework</groupId>
                    <artifactId>spring-aspects</artifactId>
                </aspectLibrary>
            </aspectLibraries>
            <source>1.6</source>
            <target>1.6</target>
        </configuration>
    </plugin>
    

    【讨论】:

    • 您能否在控制器类@satoshi 中使用断点进行调试 - 如果已使用 cglib 成功创建代理,就像您的情况一样,您应该在调试中看到它反映在控制器类的类型中变量(与日食)。如果该类型似乎不是代理,则 CGLIB 尚未生效 - 我建议使用编译时编织 - 然后您可以打开 weaver 的详细选项以查看哪些类实际上正在编织
    • 你是对的@BijuKunjummen,似乎没有为控制器创建代理(类型是 HomeController,我看不到对堆栈中任何代理/aop 方法的任何调用痕迹)。所以,正如你所说,CGLIB 尚未生效。抱歉,我是 Spring 新手,编译时编织如何帮助我?我该如何使用它?谢谢
    • 我已经更新了我的答案@satoshi,其中包含有关编译时编织的详细信息 - 我无法进入评论窗口,这就是使用 maven 使用编译时编织的详细信息更新答案的原因。
    • 你好@BijuKunjummen,我终于休息了一段时间回来了。我将您的 sn-p 添加到我的 maven 配置(pom.xml)中,现在它可以工作了!唯一的问题是,我不明白我做了什么。我真的很想知道为什么这种变化使它起作用!无论如何,非常感谢你:)
    • @Autowired 可能无法在方面工作 - 因为方面不是由 Spring 管理的,所以将依赖项注入方面的一种方法是使用 aspectOf 工厂方法 - 这是 AspectJ 在行动手册中的示例: &lt;bean id="cacheAspect" class="ajia.caching.CacheAspect" factory-method="aspectOf"&gt; &lt;property name="cache" ref="cache"/&gt; &lt;/bean&gt;
    【解决方案2】:

    通常我会为此使用拦截器而不是方面。例如,创建一个 RequestInitializeInterceptor 它将检查安全主体并相应地重定向。方面对于这项工作来说是多余的。拦截器将充当对特定控制器的每个请求的前端控制器,并决定是否允许传输请求。

     public class RequestInitializeInterceptor extends HandlerInterceptorAdapter {
    
      // Obtain a suitable logger.
      private static Log logger = LogFactory
          .getLog(RequestInitializeInterceptor.class);
    
      /**
       * In this case intercept the request BEFORE it reaches the controller
       */
      @Override
      public boolean preHandle(HttpServletRequest request,
          HttpServletResponse response, Object handler) throws Exception {
        try {
    
          logger.info("Intercepting: " + request.getRequestURI());
    
          // Your logic to redirect accordingly
         if (userAuthenticated) {
           response.sendRedirect(URL);
           return false;
        }
          return true;
        } catch (SystemException e) {
          logger.info("request update failed");
          return false;
        }
      }
    }
    

    希望这会有所帮助。

    【讨论】:

    • 感谢您的回答,@Abhi。我想我忽略了一个重要的点。 @NonSecured 注释有一个“redirectTo”元素,我可以在其中指定当用户已经登录时重定向请求的位置。我更新了原始问题。鉴于此要求,我不知道如何使用拦截器...
    • 拦截器将拦截所有get请求,您可以从请求中获取安全主体以评估用户是否经过身份验证,并根据用户状态只需执行response.sendredirect
    • 但这意味着我必须在拦截器中编写所有决策逻辑,我认为这是一种非常肮脏的方式,不是吗?有很多if 只是为了检测请求是否需要重定向......
    • 正确理解您的问题,如果条件正确,这将只是一个问题。 “如果用户已经登录,则重定向到主页”否则做任何事情......无论如何这是您的应用程序逻辑,并且对于方面也是相同的:)
    • 好吧,但是这个逻辑只能发生在指定页面(登录、注册等)上,所以在拦截器中我必须检查是否应用“过滤器”。
    【解决方案3】:

    什么对有用,请检查以下几点:

    • aspectjweaver.jar 位于类路径(1.6.8 或更高版本)
    • Aspect 类同时使用@Aspect@Component 进行注释
    • 您启用了 spring aspectJ-auto-proxy

    Java 配置:

    @Configuration
    @ComponentScan("io.mc.springaspects")
    @EnableAspectJAutoProxy
    public class SpringConfiguration {
    }
    

    方面:

    @Aspect
    @Component
    public class AnnotationAspect {
       ...
    }
    

    马文:

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.8.9</version>
    </dependency>
    

    【讨论】:

      猜你喜欢
      • 2011-09-20
      • 2013-01-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多