Java web 環境搭建
Java web 項目搭建
Java Spring IOC用法
spring提供了兩個核心功能,一個是IoC(控制反轉),另一個即是Aop(面向切面編程),IoC有助於應用對象之間的解耦,AOP則能夠實現橫切關注點(如日誌、安全、緩存和事務管理)與他們所影響的對象之間的解耦。html
AOP主要包含了通知、切點和鏈接點等術語,介紹以下java
通知(Advice)
通知定義了切面是什麼以及什麼時候調用,什麼時候調用包含如下幾種web
Before 在方法被調用以前調用通知
After 在方法完成以後調用通知,不管方法執行是否成功
After-returning 在方法成功執行以後調用通知
After-throwing 在方法拋出異常後調用通知
Around 通知包裹了被通知的方法,在被通知的方法調用以前和調用以後執行自定義的行爲正則表達式
切點(PointCut)
通知定義了切面的什麼和什麼時候,切點定義了何處,切點的定義會匹配通知所要織入的一個或多個鏈接點,咱們一般使用明確的類的方法名稱來指定這些切點,或是利用正則表達式定義匹配的類和方法名稱來指定這些切點。
切點的格式以下spring
execution(* com.ganji.demo.service.user.UserService.GetDemoUser (..) )
express
鏈接點(JoinPoint)
鏈接點是在應用執行過程當中可以插入切面的一個點,這個點能夠是調用方法時,拋出異常時,甚至是修改一個字段時,切面代碼能夠利用這些鏈接點插入到應用的正常流程中,並添加新的行爲,如日誌、安全、事務、緩存等。編程
現階段的AOP框架
AOP框架除了Spring AOP以外,還包括AspectJ、JBoss AOP;
上述框架的區別是Spring AOP只支持到方法鏈接點,另外兩個還支持字段和構造器鏈接點。緩存
同依賴注入同樣,AOP在spring中有兩種配置方式,一是xml配置的方式,二是自動註解的模式。安全
在xml中,咱們使用以下AOP配置元素聲明切面框架
AOP配置元素 | 描述 ------------ | ------------- `<aop:advisor>` | 定義AOP通知器 `<aop:after>` | 定義AOP後置通知(無論該方法是否執行成功) `<aop:after-returning>` | 在方法成功執行後調用通知 `<aop:after-throwing>` | 在方法拋出異常後調用通知 `<aop:around>` | 定義AOP環繞通知 `<aop:aspect>` | 定義切面 `<aop:aspect-autoproxy>` | 定義`@AspectJ`註解驅動的切面 `<aop:before>` | 定義AOP前置通知 `<aop:config>` | 頂層的AOP配置元素,大多數的<aop:*>包含在<aop:config>元素內 `<aop:declare-parent>` | 爲被通知的對象引入額外的接口,並透明的實現 `<aop:pointcut>` | 定義切點
咱們在service層添加com.ganji.demo.service.aspect.XmlAopDemoUserLog
類,裏面實現了攔截方法,具體以下
package com.ganji.demo.service.aspect; import org.aspectj.lang.ProceedingJoinPoint; /** * Created by admin on 2015/9/2. */ public class XmlAopDemoUserLog { // 方法執行前通知 public void beforeLog() { System.out.println("開始執行前置通知 日誌記錄"); } // 方法執行完後通知 public void afterLog() { System.out.println("開始執行後置通知 日誌記錄"); } // 執行成功後通知 public void afterReturningLog() { System.out.println("方法成功執行後通知 日誌記錄"); } // 拋出異常後通知 public void afterThrowingLog() { System.out.println("方法拋出異常後執行通知 日誌記錄"); } // 環繞通知 public Object aroundLog(ProceedingJoinPoint joinpoint) { Object result = null; try { System.out.println("環繞通知開始 日誌記錄"); long start = System.currentTimeMillis(); //有返回參數 則需返回值 result = joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("總共執行時長" + (end - start) + " 毫秒"); System.out.println("環繞通知結束 日誌記錄"); } catch (Throwable t) { System.out.println("出現錯誤"); } return result; } }
咱們在web層,web-inf/dispatcher-servlet.xml
中定義切面,具體以下
<!--定義切面 指定攔截方法時 作什麼--> <bean id="xmlAopDemoUserLog" class="com.ganji.demo.service.aspect.XmlAopDemoUserLog"></bean> <aop:config> <aop:aspect ref="xmlAopDemoUserLog"> <!--指定切面--> <!--定義切點--> <aop:pointcut id="logpoint" expression="execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..))"></aop:pointcut> <!--定義鏈接點--> <aop:before pointcut-ref="logpoint" method="beforeLog"></aop:before> <aop:after pointcut-ref="logpoint" method="afterLog"></aop:after> <aop:after-returning pointcut-ref="logpoint" method="afterReturningLog"></aop:after-returning> <aop:after-throwing pointcut-ref="logpoint" method="afterThrowingLog"></aop:after-throwing> </aop:aspect> </aop:config>
在controller下調用,調用具體以下
DemoUserEntity demoUser=userService.GetDemoUser(1);
這是運行起來 咱們將看到打印出以下日誌
開始執行前置通知 日誌記錄
開始執行後置通知 日誌記錄
方法成功執行後通知 日誌記錄
若是經過xml配置,咱們還能夠實現環繞通知,環繞通知的目的是把前置通知和後置通知的信息共享起來。同時還能夠爲通知傳遞方法的參數,在切面攔截中驗證參數的有效性。
在上述2.1中咱們經過xml配置的形式 實現了AOP編程,如今咱們經過不配置xml,配置註解的形式實現AOP。
使用配置註解,首先咱們要將切面在spring上下文中聲明成自動代理bean,咱們須要在web層的web-inf/dispatcher-servlet.xml
文件中配置以下一句話便可
<aop:aspectj-autoproxy />
固然咱們須要在xml的根目錄beans下引用aop的命名空間和xsi
xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
@Aspect
註解聲明一個切面,只須要在類名上添加@Aspect
屬性便可,具體的鏈接點,咱們用@Pointcut
和@Before
、@After
等標註。具體以下
在聲明前 咱們須要依賴配置pom
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.6.11</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.6.11</version> </dependency>
聲明切面類,包含了註解@Aspect
以及什麼時候(如@Before
)執行通知
package com.ganji.demo.service.aspect; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; import org.springframework.stereotype.Service; /** * Created by admin on 2015/9/2. */ @Aspect @Service public class XmlAopDemoUserLog { // 配置切點 及要傳的參數 @Pointcut("execution(* com.ganji.demo.service.user.UserService.GetDemoUser(..)) && args(id)") public void pointCut(int id) { } // 配置鏈接點 方法開始執行時通知 @Before("pointCut(id)") public void beforeLog(int id) { System.out.println("開始執行前置通知 日誌記錄:"+id); } // 方法執行完後通知 @After("pointCut(id)") public void afterLog(int id) { System.out.println("開始執行後置通知 日誌記錄:"+id); } // 執行成功後通知 @AfterReturning("pointCut(id)") public void afterReturningLog(int id) { System.out.println("方法成功執行後通知 日誌記錄:"+id); } // 拋出異常後通知 @AfterThrowing("pointCut(id)") public void afterThrowingLog(int id) { System.out.println("方法拋出異常後執行通知 日誌記錄"+id); } // 環繞通知 @Around("pointCut(id)") public Object aroundLog(ProceedingJoinPoint joinpoint,int id) { Object result = null; try { System.out.println("環繞通知開始 日誌記錄"+id); long start = System.currentTimeMillis(); //有返回參數 則需返回值 result = joinpoint.proceed(); long end = System.currentTimeMillis(); System.out.println("總共執行時長" + (end - start) + " 毫秒"); System.out.println("環繞通知結束 日誌記錄"); } catch (Throwable t) { System.out.println("出現錯誤"); } return result; } }
按照上述兩個步驟,使用註解實現Aop便可,這裏依賴了IOC。