網上大多數介紹AspectJ的文章都是和Spring容器混用的,但有時咱們想本身寫框架就須要拋開Spring造輪子,相似使用原生AspectJ達到面向切面編程。步驟很簡單,只須要兩步。java
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.3</version> </dependency>
<plugin> <groupId>org.codehaus.mojo</groupId> <artifactId>aspectj-maven-plugin</artifactId> <version>1.10</version> <configuration> <source>1.8</source> <target>1.8</target> <complianceLevel>1.8</complianceLevel> </configuration> <executions> <execution> <goals> <goal>compile</goal> </goals> </execution> </executions> </plugin>
@Aspect public class AspectDemo { @Pointcut("execution(* cn.yueshutong.App.say())") private void pointcut() {} // signature @Before("pointcut()") public void before(){ System.out.println("Hello"); } }
App.javaspring
public class App { public static void main( String[] args ) { System.out.println( new App().say() ); } public String say() { return "World"; } }
這一步就和日常使用Spring AOP註解沒有什麼區別了。編程
咱們都知道,Spring AOP是經過動態代理生成一個代理類,這種方式的最大缺點就是對於對象內部的方法嵌套調用不會走代理類,好比下面這段代碼:框架
@Component public class TestComponent { @TestAspect public void work(){ //do sth } public void call(){ work(); } }
緣由很簡單,對象內部的方法調用該對象的其餘方法是經過自身this進行引用,並非經過代理類引用。而AspectJ則不一樣,AspectJ是經過織入的方式將切面代碼織入進原對象內部,並不會生成額外的代理類。關於這一點,咱們反編譯看一下切點代碼:maven
//原方法 public void say() { System.out.println(this.getClass().getName()); hi(); } //反編譯 public void say() { ResourceAspect.aspectOf().before(); System.out.println(this.getClass().getName()); this.hi(); }
深究下去,在Spring AOP中,咱們只有調用代理類的切點方法才能觸發Before方法,由於代理類本質上是對原類的一層封裝,原類是沒有變化的,原類的方法內部的this指向的依舊是原類,這就致使了原類方法內部的嵌套調用沒法被代理類感知到,而AspectJ的織入就不一樣了,它會動態改變你的原類代碼,將Before等方法所有寫入進你的原方法中,這就保證了面向切面編程的萬無一失。兩種方式,各有利弊,如何使用還須要視狀況而行。this
關於更多的AspectJ的介紹,能夠參考下面這一篇,寫的至關不錯。插件