springmvc中aop對controller切面編程(轉)

概述:

最近在開發一個基礎應用服務系統,利用加密的token標識來校驗訪問者的身份。幾乎每個接口都須要校驗token。故打算採用aop面向切面編程,一次性對全部接口進行身份認證;java

碰見的問題:

切面配置沒有問題的狀況下,junit單元測試調用controller裏面的方法,能夠觸發切點,實現切面編程。可是web部署到tomcat後,直接url訪問觸發切點失敗!web

詳情描述:

切面類

import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 
 * @Description: TODO(  token的校驗    )
 * @author: mayao
 * @date 2016年10月20日 下午5:47:37
 */
@Aspect
@Component
public class UserTokenInterceptor {

    //controller包的子包裏面任何方法
    @Pointcut("execution(public * com.test.controller.*.*(..))")
    public void checkToken(){
    }

    @Before("checkToken()")
    public void beforeCheckToken(){
        System.out.println("調用方法以前。。。。");
    }

    @AfterReturning("checkToken()")
    public void afterCheckToken(){
        System.out.println("調用方法結束以後。。。。");
    }

    //拋出異常時才調用  
    @AfterThrowing("checkToken()")  
    public void afterThrowing()  
    {  
        System.out.println("校驗token出現異常了......");  
    }


}

 

控制器

/**
 * 
 * @Description: TODO( 請求token )
 * @author: mayao
 * @date 2016年10月19日 下午5:11:25
 */

@Controller
@RequestMapping("/mayao")
public class TokenController {

    @RequestMapping(value="/test",method=RequestMethod.GET)
    public void test(){
        System.out.println("調用controller裏面的方法!!!");
    }

}

 

配置文件

applicationContext.xml 部分代碼片斷spring

<!-- 自動掃描項目下面的包 ,將帶有註解的類 歸入spring容器管理   掃描service、dao -->
    <context:component-scan base-package="com.test"></context:component-scan>
    <!-- 配置使Spring採用CGLIB代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />
  •  

spring-mvc.xml 部分代碼片斷express

<!-- 默認的註解映射的支持 -->
    <mvc:annotation-driven />

    <!-- 自動掃描該包,使SpringMVC認爲包下用了@controller註解的類是控制器 -->
    <context:component-scan base-package="com.test.controller" />

 

 

junit測試代碼

@Test
    public void controllerAOPTest(){
        ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("classpath*:applicationContext.xml");
        ctx.start();
        TokenController token = (TokenController)ctx.getBean(TokenController.class);
        token.test();
    }

 

 

測試結果

調用方法以前。。。。
調用controller裏面的方法!!!
調用方法結束以後。。。。

 

 

測試時成功的!!編程

而後啓動tomcat,訪問連接 http://localhost/項目名/mayao/test,結果是:調用controller裏面的方法!!! 
切點沒有觸發!!spring-mvc

緣由:

通過查找資料及本身驗證得出: 
1.是父子容器的問題 
2.個人切面代碼和鏈接點,通知都沒有問題,問題出在了配置信息上面。tomcat

<!-- 配置使Spring採用CGLIB代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" />

 

 

(部分借鑑)CGLIB代理配置在了applicationContext.xml 核心配置文件中,該配置文件會被ContextLoaderListenerclass加載,spring會建立一個WebApplicationContext上下文,稱爲父上下文(父容器) ,保存在ServletContext中,key爲WebApplicationContext.ROOT_WEB_APPLICATION_CONTEXT_ATTRIBUTE的值。mvc

而spring-mvc.xml是DispatcherServlet,能夠同時配置多個,每一個 DispatcherServlet有一個本身的上下文對象(WebApplicationContext),稱爲子上下文(子容器),子上下文能夠訪問父上下文中的內容,但父上下文不能訪問子上下文中的內容。 它也保存在 ServletContext中,key是」org.springframework.web.servlet.FrameworkServlet.CONTEXT」+Servlet名稱app

當spring加在父容器的時候就會去找切入點,可是這個時候切入的controller是在子容器中的,父容器是沒法訪問子容器,因此就攔截不到。若是將上述的配置文件放到spring-mvc.xml中,那麼問題就解決了。我已經測試能夠經過URL訪問觸發切點了。單元測試

解決方法:

將配置信息:
    <!-- 配置使Spring採用CGLIB代理 -->
    <aop:aspectj-autoproxy proxy-target-class="true" /> 
從applicationContext.xml移到spring-mvc.xml中就能夠了

 

 

 

總結:

歸根結底來講,實際上是bean的代理問題,涉及普通的bean,service,controller。下面的要注意。

Spring MVC 和 Spring 整合的時候,SpringMVC的spring-mvc.xml文件中配置掃描包,不要包含 service的註解,Spring的applicationContext.xml文件中配置掃描包時,不要包含controller的註解。

錯誤以下:

<!-- spring-mvc.xml  -->
<context:component-scan base-package="com.test">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

<!-- applicationContext.xml  -->
 <context:component-scan base-package="com.test">           
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

Spring MVC啓動時的配置文件,包含組件掃描、url映射以及設置freemarker參數,讓spring不掃描帶有@Service註解的類。爲何要這樣設置?

由於spring-mvc.xml與applicationContext.xml不是同時加載,若是不進行這樣的設置,那麼,spring就會將全部帶@Service註解的類都掃描到容器中,等到加載applicationContext.xml的時候,會由於容器已經存在Service類,使得cglib將不對Service進行代理,直接致使的結果就是在applicationContext 中的事務配置不起做用,發生異常時,沒法對數據進行回滾。以上就是緣由所在。

不過沒必要太小心這個,實際應用中這樣的配置(指定service,controller掃描的)也不多。

相關文章
相關標籤/搜索