网上大多数介绍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的介绍,能够参考下面这一篇,写的至关不错。插件