使用Spring AOP 详解

使用Spring AOP

与AspectJ的静态代理不同,Spring AOP使用的动态代理,所谓的动态代理就是说AOP框架不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。

如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

为了验证以上的说法,可以做一个简单的测试。首先测试实现接口的情况。

定义一个接口

1

2

3

public interface Person {

    String sayHello(String name);

}

实现类

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Component

public class Chinese implements Person {

    @Timer

    @Override

    public String sayHello(String name) {

        System.out.println("-- sayHello() --");

        return name + " hello, AOP";

    }

    public void eat(String food) {

        System.out.println("我正在吃:" + food);

    }

}

这里的@Timer注解是我自己定义的一个普通注解,用来标记Pointcut。

定义Aspect

1

2

3

4

5

6

7

8

9

10

11

12

13

@Aspect

@Component

public class AdviceTest {

    @Pointcut("@annotation(com.listenzhangbin.aop.Timer)")

    public void pointcut() {

    }

    @Before("pointcut()")

    public void before() {

        System.out.println("before");

    }

}

运行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@SpringBootApplication

@RestController

public class SpringBootDemoApplication {

    //这里必须使用Person接口做注入

    @Autowired

    private Person chinese;

    @RequestMapping("/test")

    public void test() {

        chinese.sayHello("listen");

        System.out.println(chinese.getClass());

    }

    public static void main(String[] args) {

        SpringApplication.run(SpringBootDemoApplication.class, args);

    }

}

输出

1

2

3

before

-- sayHello() --

class com.sun.proxy.$Proxy53

可以看到类型是com.sun.proxy.$Proxy53,也就是前面提到的Proxy类,因此这里Spring AOP使用了JDK的动态代理。

再来看看不实现接口的情况,修改Chinese

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

@Component

public class Chinese {

    @Timer

//    @Override

    public String sayHello(String name) {

        System.out.println("-- sayHello() --");

        return name + " hello, AOP";

    }

    public void eat(String food) {

        System.out.println("我正在吃:" + food);

    }

}

运行

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

@SpringBootApplication

@RestController

public class SpringBootDemoApplication {

    //直接用Chinese类注入

    @Autowired

    private Chinese chinese;

    @RequestMapping("/test")

    public void test() {

        chinese.sayHello("listen");

        System.out.println(chinese.getClass());

    }

    public static void main(String[] args) {

        SpringApplication.run(SpringBootDemoApplication.class, args);

    }

}

输出

1

2

3

before

-- sayHello() --

class com.listenzhangbin.aop.Chinese$$EnhancerBySpringCGLIB$$56b89168

可以看到类被CGLIB增强了,也就是动态代理。这里的CGLIB代理就是Spring AOP的代理,这个类也就是所谓的AOP代理,AOP代理类在切点动态地织入了增强处理。

猜你喜欢

转载自blog.csdn.net/qswdcs1/article/details/81208685