静态AOP
2018-07-28 本文已影响6人
黄二的NPE
静态代理
代理分为静态代理和动态代理。静态代理由程序员创建或工具生成代理类的源码,再编译代理类,所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了;而动态代理是指在代码运行期间生成的代理类,他的字节码文件在程序运行之前是找不到的。
我们来看一个简单的静态代理的实现:
//接口
public interface CatService {
void save();
}
//实现类(操作目标类)
public class CatServiceImpl implements CatService{
@Override
public void save() {
System.out.println("保存了一只猫...");
}
}
//代理类
public class CatServiceProxy implements CatService {
CatService catService;
public CatServiceProxy(CatService catService) {
this.catService = catService;
}
@Override
public void save() {
System.out.println("我是代理类,在操作之前");
catService.save();
System.out.println("我是代理类,在操作之后");
}
}
//调用和测试
public static void main(String[] args) {
CatService catService = new CatServiceImpl();
CatService catServiceProxy = new CatServiceProxy(catService);
catServiceProxy.save();
}
通过上面代码的几步操作,一个简单的静态代理类就完成了。在这个例子中,CatServiceProxy就是我们的静态代理类,它代理了CatServiceImpl。
Aspectj
说到静态Aop的鼻祖,那非aspectj莫属。编译的时候,aspectj早已把我们的通知织入到代码中。我们写个小小的demo(基于maven和idea)来见识一下:
- pom.xml 引入相关的配置,在dependencies中引入aspectjrt,aspectjtools,aspectjweaver,在plugins中引入编译插件aspectj-maven-plugin。
<dependencies>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.8.9</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.7.4</version>
</dependency>
</dependencies>
<build>
<plugins>
<!-- AspectJ 编译插件 -->
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.8</version>
<executions>
<execution>
<goals>
<goal>compile</goal> <!-- use this goal to weave all your main classes -->
<goal>test-compile</goal> <!-- use this goal to weave all your test classes -->
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
- 设置idea
-
file->settings->plugins->搜索aspectj,把搜出来的结果都打勾
idea设置 -
设置编译器,编译aj文件需要自己的编译器
设置编译器
- 编写一个很简单的Java类
public class HelloService {
public void sayHello(){
System.out.println("hello world");
}
}
- 编写aspectJ文件(HelloServiceAspectJ.aj 注意.aj做后缀)
你会发现这语法跟spring aop差不多,其实spring aop也是从aspectj中借鉴
@Aspect
public aspect HelloServiceAspectj {
@Before(value = "execution(* aspectj.HelloService.sayHello(..))")
public void sayHelloBefore() {
System.out.println("我是aspect");
}
}
- 编写运行类
public class AspectjMain {
public static void main(String[] args) {
HelloService helloService = new HelloService();
helloService.sayHello();
}
}
运行以后,我们想要的结果也出来了。但是这是怎么实现的呢?我们说aspectj是静态aop,也就是说运行前已经生成相应的aop文件了,那么编译后的文件是怎么样的呢?
HelloService.class
public class HelloService {
public HelloService() {
}
public void sayHello() {
HelloServiceAspectj.aspectOf().sayHelloBefore();
System.out.println("hello world");
}
}
我们可以看到输出hello world之前,先调用了HelloServiceAspectj.aspectOf().sayHelloBefore();
我们先来看看这又是什么?
@Aspect
public class HelloServiceAspectj {
static {
try {
ajc$postClinit();
} catch (Throwable var1) {
ajc$initFailureCause = var1;
}
}
public HelloServiceAspectj() {
}
@Before("execution(* aspectj.HelloService.sayHello(..))")
public void sayHelloBefore() {
System.out.println("我是aspect");
}
public static HelloServiceAspectj aspectOf() {
if(ajc$perSingletonInstance == null) {
throw new NoAspectBoundException("aspectj_HelloServiceAspectj", ajc$initFailureCause);
} else {
return ajc$perSingletonInstance;
}
}
public static boolean hasAspect() {
return ajc$perSingletonInstance != null;
}
}
可以看到实际上是调用了HelloServiceAspectj 的sayHelloBefore的方法。
在这里,我认为aspectj已经不是利用代理来实现aop了。