javascript
Spring-AOP 使用@AspectJ
- 概述
- 準備工作
- 實例
- 通過編碼的方式使用AspectJ切面
- 通過配置的方式使用AspectJ切面
- 自動生成代理的方式
- 基于Schema的aop命名空間配置的方式
概述
我們之前一個系列的文章,分別使用Pointcut和Advice接口描述切點和增強,并用Advisor整合二者描述切面,@AspectJ則采用注解來描述切點、增強,二者只是表述方式不同,描述內容的本質是完全相同的。
準備工作
在使用@AspectJ之前,必須確保使用的Java5.0以及以上的版本,否則無法使用注解。
Spring在處理@AspectJ注解表達式時,需要將Spring的asm模塊添加到類路徑中。asm是輕量級的字節碼處理框架,因為Java的反射機制無法獲取入參名,Spring就利用asm處理@AQspectJ中所描述的方法入參名
如果是maven工程,需要在pom.xml添加aspectj.weaver和aspectj.tools類包的依賴。
實例
代碼已托管到Github—> https://github.com/yangshangwei/SpringMaster
通過編碼的方式使用@AspectJ切面
@AspectJ采用不同的方式對AOP進行描述。
我們依舊采用我們一直使用的服務生的例子
package com.xgj.aop.spring.advisor.aspectJ.aspectJByCode;public class NaiveWaiter implements Waiter {@Overridepublic void greetTo(String name) {System.out.println("NaiveWaiter Greet To " + name);}@Overridepublic void serverTo(String name) {System.out.println("NaiveWaiter Server To " + name);}}下面使用@AspectJ注解定義一個切面
package com.xgj.aop.spring.advisor.aspectJ.aspectJByCode;import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;/*** * * @ClassName: PreGreetingAspect* * @Description: 切面類* * @author: Mr.Yang* * @date: 2017年8月24日 下午3:21:15*/// 通過@Aspect將PreGreetingAspect標注為一個切面 @Aspect public class PreGreetingAspect {// 定義切點和增強類型@Before("execution(* greetTo(..))")public void beforeGreeting() {// 增強的橫切邏輯System.out.println("How are you ?");} }從上述代碼中,我們可以看到這個切面沒有實現任何特殊的接口,它只是一個普通的POJO,特殊之處在于使用了@AspectJ注解。
首先,在PreGreetingAspect類定義出標注了@AspectJ注解,這樣,第三方處理程序就可以通過類是否擁有@AspectJ注解來判斷其是否是一個切面。
其次,在beforeGreeting()方法處標注了@Before注解,并未改注解提供了成員值“execution(* greetTo(..))”
@Before(“execution(* greetTo(..))”)注解提供了兩個信息: @Before注解白該增強是前置增強,而成員值是一個@AspectJ切點表達式。 意思為:在目標類的greetTo方法上織入增強,greetTo()方法可以帶帶任意的入參和任意的返回值。
最后beforeGreeting()方法是增強說是所使用的橫切邏輯,該橫切邏輯在目標方法前調用。
我們通過下圖來先看下這種關系 《切面的信息構成》
PreGreetingAspect類通過注解和代碼,將切點、增強類型和增強的橫切邏輯柔和到一個類中,使切面的定義渾然天成。 其實相當于我們之前說的BeforeAdivce、NameMatchMethodPoincut和DefaultPointcutAdvisor三者聯合表達的信息。
下面我們通過AspectProxyFactory為NaiverWaiter生成織入PreGreetingAspect切面的代碼
package com.xgj.aop.spring.advisor.aspectJ.aspectJByCode;import org.junit.Test; import org.springframework.aop.aspectj.annotation.AspectJProxyFactory;/*** * * @ClassName: PreGreetingAspectTest* * @Description:* * @author: Mr.Yang* * @date: 2017年8月24日 下午3:21:29*/ public class PreGreetingAspectTest {@Testpublic void test() {// 目標類Waiter target = new NaiveWaiter();// 實例化切面代理工廠AspectJProxyFactory aspectJProxyFactory = new AspectJProxyFactory();// 設置目標對象aspectJProxyFactory.setTarget(target);// 添加切面類aspectJProxyFactory.addAspect(PreGreetingAspect.class);// 生成織入切面的代理對象Waiter proxy = aspectJProxyFactory.getProxy();// 調用業務方法proxy.greetTo("XiaoGongJiang");proxy.serverTo("XiaoGongJiang");} }運行結果
How are you ? NaiveWaiter Greet To XiaoGongJiang NaiveWaiter Server To XiaoGongJiang從輸出結果,我們可以知道代理對象的greetTo()方法已經被織入了切面類所定義的增強邏輯。
通過配置的方式使用@AspectJ切面
雖然可以通過編程的方式織入切面,但是一般情況下,我們都是通過Spring的配置完成切面織入工作。
自動生成代理的方式
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><!-- 通過配置使用@AspectJ --><!-- 目標Bean --> <bean id="waiter" class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.NaiveWaiter"/> <!-- 使用了@AspectJ注解的切面類 --> <bean class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.PreGreetingAspect"/> <!-- 自動代理創建器,自動將@AspectJ注解切面類織入目標Bean中 --> <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator"/></beans>測試:
package com.xgj.aop.spring.advisor.aspectJ.aspectJByConf;import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;/*** * * @ClassName: PreGreetingAspectTest* * @Description:* * @author: Mr.Yang* * @date: 2017年8月24日 下午3:21:29*/ public class PreGreetingAspectTest {@Testpublic void test() {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ.xml");Waiter naiveWaiter = ctx.getBean("waiter", Waiter.class);naiveWaiter.greetTo("XiaoGongJiang");naiveWaiter.serverTo("XiaoGongJiang");} }運行結果:
2017-08-24 17:29:48,644 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24177697: startup date [Thu Aug 24 17:29:48 BOT 2017]; root of context hierarchy 2017-08-24 17:29:48,754 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ.xml] How are you ? NaiveWaiter Greet To XiaoGongJiang NaiveWaiter Server To XiaoGongJiang基于Schema的aop命名空間配置的方式
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:aop="http://www.springframework.org/schema/aop"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop.xsd"><!-- 使用基于Schema的aop命名空間進行配置 --><!-- 基于@AspectJ切面的驅動器 --> <aop:aspectj-autoproxy/><!-- 目標Bean --> <bean id="waiter" class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.NaiveWaiter"/> <!-- 使用了@AspectJ注解的切面類 --> <bean class="com.xgj.aop.spring.advisor.aspectJ.aspectJByConf.PreGreetingAspect"/></beans>首先在配置文件中引入aop的命名空間;然后通過aop命名空間的<aop:aspectj-atuoproxy/>自動為Spring容器中哪些匹配@AspectJ切面的bean 創建代理,完成切面織入。
當然了,Spring在內部依舊使用AnnotationAspectJAutpProxyCreator進行自動代理的創建工作,但具體的實現細節被<aop:aspectj-atuoproxy/>隱藏起來了。
<aop:aspectj-atuoproxy/>有一個proxy-target-class屬性,默認為false,標識使用JDK動態代理技術織入增強。 當配置 <aop:aspectj-autoproxy proxy-target-class="true"/>表示使用CGLib動態代理技術織入增強。
不過即使 proxy-target-class設置為false,如果目標類沒有聲明接口,Spring將自動使用CGLib動態代理
測試
package com.xgj.aop.spring.advisor.aspectJ.aspectJByConf;import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class PreGreetingAspectSchemaTest {@Testpublic void test() {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ_schema.xml");Waiter naiveWaiter = ctx.getBean("waiter", Waiter.class);naiveWaiter.greetTo("XiaoGongJiang");naiveWaiter.serverTo("XiaoGongJiang");} }運行結果
2017-08-24 17:30:28,141 INFO [main] (AbstractApplicationContext.java:583) - Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@24177697: startup date [Thu Aug 24 17:30:28 BOT 2017]; root of context hierarchy 2017-08-24 17:30:28,244 INFO [main] (XmlBeanDefinitionReader.java:317) - Loading XML bean definitions from class path resource [com/xgj/aop/spring/advisor/aspectJ/aspectJByConf/conf-aspectJ_schema.xml] How are you ? NaiveWaiter Greet To XiaoGongJiang NaiveWaiter Server To XiaoGongJiang通過輸出結果,我們可以看到實現了同樣的效果。
總結
以上是生活随笔為你收集整理的Spring-AOP 使用@AspectJ的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Java-Java5.0注解解读
- 下一篇: Spring-AOP 自动创建代理之An