AOP实现方式

AOP底层实现原理主要有三种:

  • 代理:在运行时生成代理类字节码。
    • JDK动态代理,只能针对接口代理。
    • cglib,可以针对类和接口。
  • ajc编译器增强:编译器在编译class类文件时,把通知的代码织入到目标类的字节码中。
  • agent类加载:agent在加载目标类时,修改目标类的字节码,织入增强功能。

proxy

JDK动态代理

cglib

ajc编译器

1. 创建目标类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Service
public class MyService {

private static final Logger log = LoggerFactory.getLogger(MyService.class);

public void test(){
log.info("test()");
test2();
}

public void test2(){
log.info("test2()");
}
}

2. 创建切面

1
2
3
4
5
6
7
8
9
10
11
@Aspect
//@Component
public class MyAspect {

private static final Logger log = LoggerFactory.getLogger(MyAspect.class);

@Before("execution(* com.spring.study.aop.service.MyService.*())")
public void before(){
log.info("before()");
}
}

3. maven增加编译插件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>aspectj-maven-plugin</artifactId>
<version>1.14.0</version>
<configuration>
<complianceLevel>1.8</complianceLevel>
<source>8</source>
<target>8</target>
<showWeaveInfo>true</showWeaveInfo>
<verbose>true</verbose>
<Xlint>warning</Xlint>
<encoding>UTF-8</encoding>
</configuration>
</plugin>

4. 编译,IDEA编译路径:maven->plugins->aspectj:complie
5. 结果如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Service
public class MyService {
private static final Logger log = LoggerFactory.getLogger(MyService.class);

public MyService() {
}

public void test() {
MyAspect.aspectOf().before();
log.info("test()");
this.test2();
}

public void test2() {
MyAspect.aspectOf().before();
log.info("test2()");
}
}

参考资料如下:

aspectj-maven-plugin开源项目
aspectj-maven-plugin

agent类加载

增加VM参数:-javaagent:D:\Code\Tools\Maven\Repository\org\aspectj\aspectjweaver\1.9.5
在类加载时对目标类进行增强

JDK代理

JDK代理特点:

  1. JDK代理只能针对接口进行代理。
  2. JDK代理类和目标类是兄弟关系,实现共同的接口。代理类和目标类之间不可以转换。
  3. 目标类可以是fianl类型。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
// 测试类如下
public class JdkProxyTest {

interface Foo{
void foo();
void foo2();
}

static class FooImpl implements Foo{
@Override
public void foo() {
System.out.println("foo");
}

@Override
public void foo2() {
System.out.println("foo2");
}
}

public static void main(String[] args) {
ClassLoader loader = JdkProxyTest.class.getClassLoader();
FooImpl target = new FooImpl();
Foo proxy = (Foo) Proxy.newProxyInstance(loader, new Class[]{Foo.class}, (p, method, args1) -> {
System.out.println("before invoke foo ");
//目标.方法
//方法.invoke(目标,参数)
Object result = method.invoke(target,args1);
System.out.println("after invoke foo ");
return result;
});
proxy.foo();
proxy.foo2();
}
}

执行结果如下:

1
2
3
4
5
6
7
//输出结果如下:
before invoke foo
foo
after invoke foo
before invoke foo
foo2
after invoke foo

CGLIB代理

CGLIB代理特点:

  1. 代理类是子类,目标类是父类:意味着目标类不能是final。
  2. final方法也不能增强。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
public class CglibProxyTest {

static class Target {
public void foo() {
System.out.println("foo");
}

public final void foo2() {
System.out.println("foo2");
}
}

public static void main(String[] args) {
Target target = new Target();
Target proxy = (Target) Enhancer.create(Target.class, (MethodInterceptor) (obj, method, args1, methodProxy) -> {
System.out.println("before");
//方法反射调用
Object result = method.invoke(target, args1);
//methodProxy.invoke可以避免反射进行调用.内部不是用的反射,需要目标类
//Object result = methodProxy.invoke(target,args1);
//methodProxy.invokeSuper可以避免反射进行调用.内部不是用的反射,需要代理类自己
//Object result = methodProxy.invokeSuper(obj,args1);
System.out.println("after");
return result;
});
proxy.foo();
proxy.foo2();
}
}

执行结果如下:

1
2
3
4
before
foo
after
foo2