凡是过往,皆为序章

0%

Spring_05(AspectJ具体实现)

AspectJ的Spring实现。


实现步骤

使用AspectJ框架实现Aop。

使用aop:目的是给已经存在的一些类和方法,增加额外的功能。前提是不改变原来的类的代码。

使用AspectJ实现Aop的基本步骤:

  1. 新建Maven项目

  2. 加入依赖

    • spring依赖

    • aspectJ依赖

    • junit单元测试

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.11</version>
      <scope>test</scope>
      </dependency>

      <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.2.9.RELEASE</version>
      </dependency>

      <!-- aspectj -->
      <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aspects</artifactId>
      <version>5.2.9.RELEASE</version>
      </dependency>
  3. 创建目标类:接口和他的实现类。

    要做的是给类中的方法增加功能。

  4. 创建切面类:就是一个普通类,有如下几个要求:

    • 在类的上面加上注解 @AspectJ

    • 在类中定义方法,方法就是切面要执行的功能代码。

      在方法的上面加入AspectJ中的通知注解,例如@Before

      还需要指定切入点的表达式execution()

  5. 创建spring的配置文件:声明对象,把对象交给容器统一管理(声明对象可以使用注解或者xml配置文件)

    • 声明目标对象

    • 声明切面类对象

    • 声明AspectJ框架中的自动代理生成器标签。

      自动代理生成器:用来完成代理对象的自动创建功能的。

  6. 创建测试类,从spring容器中获取目标对象(实际就是代理对象)

    通过代理执行方法,实现aop的功能增强

@Before前置通知-方法有JoinPoint参数

在目标方法执行之前执行。被注解为前置通知的方法,可以包含一个JoinPoint类型参数。该类型的对象本身就是切入点表达式。通过该参数,可获取切入点表达式、方法签名、目标对象等。

不光前置通知的方法,可以包含一个JoinPoint类型参数,所有的通知方法均可包含该参数。

具体代码实现

首先是目标类的实现代码:

1
2
3
4
5
6
7
8
9
10
11
package com.thorine.ba01;

// 目标类
public class SomeServiceImpl implements SomeService {
@Override
public void doSome(String name, Integer age) {
// 给doSome方法增加一个功能,在doSome()执行之前,输出方法的执行时间
System.out.println("=====目标方法doSome()执行=====");

}
}

切面类

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
37
package com.thorine.ba01;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Date;

/**
* @Aspect : 是AspectJ框架中的注解
* 作用:表示当前类是切面类
* 切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
*/
@Aspect
public class MyAspect {
/**
* 定义方法,方法是实现切面功能的。
* 方法的定义要求:
* 1、共有方法 public
* 2、方法无返回值
* 3、方法名称自定义
* 4、可以有参数,可以无参数。若有参数,不是自定义的,是有几个参数类型可以使用
*/

/**
* @Before:前置通知注解
* 属性:value,是切入点表达式,表达切面的功能执行的位置。
* 特点:
* 1.在目标方法前先执行
* 2.不会改变目标方法的执行结果
* 3.不会影响目标方法的执行
*/
@Before(value = "execution(public void com.thorine.ba01.SomeServiceImpl.doSome(String,Integer))")
public void myBefore(){
// 就是切面要执行的功能代码
System.out.println("前置通知,切面功能:在目标方法之前输出执行时间:" + new Date());
}
}

spring配置文件 ApplicationContext.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">

<!-- 把对象交给spring容器,由spring容器统一创建,管理对象 -->

<!-- 声明目标对象 -->
<bean id="someService" class="com.thorine.ba01.SomeServiceImpl" />

<!-- 声明切面类对象 -->
<bean id="myAspect" class="com.thorine.ba01.MyAspect"/>

<!--
声明自动代理生成器:使用aspectJ框架内部的功能,创建目标对象的代理对象。
创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象
所以目标对象就是被修改后的代理对象

aop:aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
-->
<aop:aspectj-autoproxy />

</beans>

然后在测试类中创建对象,测试目标方法。

1
2
3
4
5
6
7
8
9
@Test
public void test01(){
String config = "applicationContext.xml";
ApplicationContext ctx = new ClassPathXmlApplicationContext(config);
// 从容器中获取目标对象
SomeService proxy = (SomeService) ctx.getBean("someService");
// 通过代理的对象执行方法,实现目标方法执行时,增强了功能
proxy.doSome("zs",20);
}

输出结果,得到增强功能了的目标方法。

~感谢你请我吃糖果~
-------------本文结束,感谢您的阅读,欢迎评论留言!-------------