控制器中的Spring AOP切入点

时间:2015-10-02 08:38:58

标签: spring spring-mvc aop spring-aop

我已经定义了这个类方面适用于服务(除非用户具有角色MANAGER,否则不允许访问,但控制器没有限制(?)

@Aspect
public class DeviceAspect extends ServiceSupport {


    @Pointcut("execution(* fo.belecam.services.client.ManageLicenseService.*(..))")
    public void manage() {
    }

    @Pointcut("execution(* fo.belecam.services.client.AwardService.*(..))")
    public void award() {
    }

    @Pointcut("execution(* fo.belecam.services.client.DeviceService.*(..))")
    public void handleDeviceServiceMethod() {
    }

    @Pointcut("execution(* fo.belecam.controller.manage.ImportController.*(..))")
    public void handleImportController() {
    }


    @Before("fo.belecam.services.aop.DeviceAspect.handleImportController() || fo.belecam.services.aop.DeviceAspect.handleDeviceServiceMethod() || fo.belecam.services.aop.DeviceAspect.manage() || fo.belecam.services.aop.DeviceAspect.award()")
    @After ("fo.belecam.services.aop.DeviceAspect.handleImportController() || fo.belecam.services.aop.DeviceAspect.handleDeviceServiceMethod() || fo.belecam.services.aop.DeviceAspect.manage() || fo.belecam.services.aop.DeviceAspect.award()")
    public void before(JoinPoint _jp) {
        User user = getUser();
        if(user == null || user.getUserRole() != UserRole.MANAGER) {
            throw new NoSufficientRoleException(user == null ? null : user.getUserRole(), UserRole.MANAGER);
        }
    }

}

和ImportController:

@SuppressWarnings("deprecation")
public class ImportController extends AbstractFormController {


    private String view;

    private String successView;

    @Autowired
    protected UserService userService;

    @Autowired
    private ManageDeviceService manageDeviceService;

    public String getView() {
        return view;
    }

    public void setView(String view) {
        this.view = view;
    }

    public String getSuccessView() {
        return successView;
    }

    public void setSuccessView(String successView) {
        this.successView = successView;
    }


    @Override
    public ModelAndView processFormSubmission(final HttpServletRequest request,
            HttpServletResponse response, Object command, BindException errors)
            throws Exception {

        final ModelAndView mav = new ModelAndView(getView());

        FileUploadCommand file = (FileUploadCommand)command;

        MultipartFile multipartFile = file.getFile();

        if(multipartFile!=null && multipartFile.getSize()>0) {
            Workbook workbook = Workbook.getWorkbook(multipartFile.getInputStream());
            DataCollector dataCollector = new XLSDataCollector(workbook, true);
            final List<Application> applications = manageDeviceService.loadApplications (dataCollector.getDataCollection());
            List<ApplicationImporterError> importationErrors = manageDeviceService.validateApplications(applications);
            savedApplications.add(manageDeviceService.getApplicationById(application.getId(), true));


        }
        return mav;
    }

    @Override
    public ModelAndView showForm(HttpServletRequest request, HttpServletResponse arg1, BindException errors)
            throws Exception {

        return new ModelAndView(getView());
    }



    }

    /**
     * @param applications
     * @param competentBody
     * @return
     * @throws Exception
     */
    private List<Application> saveApplications(List<Application> applications,User user) throws Exception {

        return manageDeviceService.saveImportedApplications (applications, user);
    }

    /**
     * @param session
     * @return
     */
    public User getUser(HttpSession session) {

        User user = (User) session.getAttribute(Const.SESSION_USER);
        if (user == null) {
            user = new User();
        }
        return user;
    }
}

当我以UserRole.MANAGER身份登录时,调用(JoinPoint _jp)之前的方法,否则不是

我知道,当我只是在浏览器中粘贴网址时,不会调用之前的方法(JoinPoint _jp).... http://127.0.0.1:7001/devices/manage/import.do

3 个答案:

答案 0 :(得分:1)

Spring的基于动态代理的AOP的一个限制是,它只能建议公共连接点 - 来自文档:

http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html

  

由于Spring的AOP框架基于代理的特性,根据定义,受保护的方法既不是针对JDK代理(这不适用),也不针对CGLIB代理(这在技术上可行,但不建议用于AOP)目的)。因此,任何给定的切入点都只能与公共方法匹配!   如果您的拦截需要包括受保护/私有方法甚至构造函数,请考虑使用Spring驱动的本机AspectJ编织而不是Spring的基于代理的AOP框架。这构成了具有不同特征的不同AOP使用模式,因此在做出决定之前一定要先熟悉编织。

您的许多控制器方法都是protected,因此虽然您的控制器已注册为Spring bean(可能) - 但不建议使用非公共方法。

答案 1 :(得分:1)

我遇到了同样的问题,其中Repository的建议正在运行,但是对Controller的建议却没有。最后我找到了解决方案。简而言之,您需要确保在Servlet上下文中加载AOP定义,而不是在不同的上下文中加载。

就我而言,我的Spring AOP定义在tools-config.xml中定义。从这里移动后

<context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:spring/tools-config.xml</param-value>
</context-param>

<listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

到这里,

<servlet>
    <servlet-name>petclinic</servlet-name>
    <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    <init-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring/mvc-core-config.xml, classpath:spring/tools-config.xml</param-value>
    </init-param>
    <load-on-startup>1</load-on-startup>
</servlet>

对Controller的建议正在发挥作用。

答案 2 :(得分:0)

问题可能在于控制器对象本身会调用您尝试拦截的方法(它们最初都受到保护),从抽象控制器直接调用其覆盖方法之一。 Spring AOP的工作方式是在对象周围创建一个拦截方法的代理,但只有在通过Spring注入的依赖从外部调用该方法时才有效。这不是这里的情况 - 因为该方法是从它自己的对象中调用的,所以该调用绕过了为“外部世界”包装对象的任何代理。