【JAVAEE框架】浅谈 AOP 及代码实现

举报
追zhui 发表于 2025/11/13 20:42:14 2025/11/13
【摘要】 >  哈喽~大家好呀,>>  >>  >>  🥇个人主页:[个人主页](https://blog.csdn.net/aasd23?spm=1000.2115.3001.5343)       >>  🥈 系列专栏:[【云原生系列】](https://blog.csdn.net/aasd23/category_11852592.html?spm=1001.2014.3001.5482)>>...
>  哈喽~大家好呀,
>
>  
>
>  
>
>  🥇个人主页:[个人主页](https://blog.csdn.net/aasd23?spm=1000.2115.3001.5343)       
>
>  🥈 系列专栏:[【云原生系列】](https://blog.csdn.net/aasd23/category_11852592.html?spm=1001.2014.3001.5482)
>
>  🥉与这篇相关的文章:      
>
>  
>
>  |      |      |
>  | ---- | ---- |
>  |      |      |
>  |      |      |

一、前言

上篇讲到 AOP 它是基于代理模式下进行的,这篇来讲讲代码是如何实现。

1、实现需要的知识点

AspectJ 中常用的通知有四种类型:

(1)前置通知

(2)后置通知

(3)环绕通知

(4)最终通知

(5)定义切入点

2、定义切入点

切入点:简单的说,就是连接点的查询条件

示例

```XML
<aop:config>
<aop:pointcut id="pointcut"
            expression="execution(public void addNewUser(entity.User))"/>
</aop:config>
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

表达式匹配规则举例

> public * addNewUser(entity.User): “*”表示匹配所有类型的返回值。
> public void *(entity.User): “*”表示匹配所有方法名。
> public void addNewUser(..): “..”表示匹配所有参数个数和类型。
> \* com.service.*.*(..):匹配com.service包下所有类的所有方法。
> \* com.service..*.*(..):匹配com.service包及其子包下所有类的所有方法

二、原生代码实现

pom导入 aop 需要的依赖

```XML
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

创建 userService.java

用来做方法测试类

```java
public class UserService {

    public Integer addUser(int n) {
        Integer r = 0;

        r = 100 / n;
        System.out.println("addUser 运行了");
        System.out.println(r);

        return r;
    }

    public int deleteUser(String id) {
        System.out.println("删除:" + id);
        return 1;
    }

}
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

编写 UserAspect.java

```java
    // 前置通知
    // JoinPoint: 连接点,改对象包含目标方法的相关信息
    public void before(JoinPoint jp){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "方法执行了,参数: " + Arrays.toString(jp.getArgs()));
    }

    // 后置通知
    public void after(JoinPoint jp){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "之后方法执行了,参数: " + Arrays.toString(jp.getArgs()));
    }

    // 异常通知
    public void errorNation(JoinPoint jp, Throwable e){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "方法出错了,错误是: " + e.getMessage());
    }

    // 返回通知

    public void ReturnNation(JoinPoint jp, Object ret){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "方法的返回结果是: " + ret);
    }
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

applicationContext.xml 文件

```XML
<?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-4.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
">

<bean id="UserAspect" class="com.itxzw.user.UserAspect"/>

<bean id="UserService" class="com.itxzw.user.UserService"/>

<aop:config>

<aop:pointcut id="pointcut" expression="execution(public * com.itxzw.user.UserService.*(..))"/>

<aop:aspect ref="UserAspect">
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
<aop:after-throwing method="errorNation" throwing="e" pointcut-ref="pointcut"/>
<aop:after-returning method="ReturnNation" returning="ret" pointcut-ref="pointcut"/>

<!-- <aop:around method="roundNation" pointcut-ref="pointcut"/>-->
</aop:aspect>

</aop:config>

</beans>
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

![img](https://img-blog.csdnimg.cn/d103e1395e014fe9b4a236fe97a5da38.png)

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)编辑

 编写测试类

```java
    @Test
    public void Test01(){

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserService userService = (UserService) context.getBean("UserService");

        userService.addUser(10);

        System.out.println(userService);

    }
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

效果

![img](https://img-blog.csdnimg.cn/48613527cfb54eb1a7e6b9b1ac7961e0.png)![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)编辑

底层原理就是采用了代理模式

 三、注解实现

1、注解

前置通知@Before:前置增强处理,在目标方法前织入增强处理

后置通知@AfterReturning:后置增强处理,在目标方法正常执行(不出现异常)后织入增强处理

环绕通知@Around:环绕增强处理,在目标方法的前后都可以织入增强处理

最终通知@After:最终增强处理,不论方法是否抛出异常,都会在目标方法最后织入增强处理

异常通知@AfterThrowing:异常增强处理,在目标方法抛出异常后织入增强处理

定义切入点@Pointcut

2、Spring AOP配置元素

![img](https://img-blog.csdnimg.cn/85f07e510d564170aaf047bf5d3f18e3.png)

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)编辑

 3、注解实现

注解方式将Bean的定义信息和Bean实现类结合在一起,Spring提供的注解有
 @Component:实现Bean组件的定义
 @Repository   :用于标注DAO类
 @Service   :用于标注业务类
 @Controller   :用于标注控制器类

> @Repository("userDao") 
> public class UserDaoImpl implements UserDao {
> …
> }
> 与在XML配置文件中编写
> <bean id="userDao" 
> class="dao.impl.UserDaoImpl" /> 
> 等效

使用@Autowired注解实现Bean的自动装配,默认按类型匹配,可以使用@Qualifier指定Bean的名称

> @Service("userService") 
> public class UserServiceImpl implements UserService { 
> @Autowired
> @Qualifier("userDao")
> private UserDao dao; 
> …… 
> }
>
> 可以对类的成员变量进行标注
> @Service("userService") 
> public class UserServiceImpl implements UserService { 
> private UserDao dao;
> @Autowired
> public void setDao((@Qualifier("userDao") UserDao dao) {
>  this.dao = dao;
> } 
> …… 
> }
>
> 也可以对方法的入参进行标注

使用注解信息启动Spring容器

> <beans xmlns="http://www.springframework.org/schema/beans"
> xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
> xmlns:context="http://www.springframework.org/schema/context"
> xsi:schemaLocation="......
> http://www.springframework.org/schema/context
> http://www.springframework.org/schema/context/spring-context-3.2.xsd">
> <!-- 扫描包中注解标注的类 -->
> <context:component-scan base-package="service,dao" />
> </beans>
>
> 指定需要扫描的基类包,多个包可用逗号隔开

示例

UserAspect.java

```java
@Component
@Aspect
public class UserAspect {

    // 定义切入点
    @Pointcut("execution(public * com.itxzw..*.*(..))")
    public void pointcut(){}

    // 前置通知
    // JoinPoint: 连接点,改对象包含目标方法的相关信息
    @Before("pointcut()")
    public void before(JoinPoint jp){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "方法执行了,参数: " + Arrays.toString(jp.getArgs()));
    }

    // 后置通知
    @After("pointcut()")
    public void after(JoinPoint jp){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "之后方法执行了,参数: " + Arrays.toString(jp.getArgs()));
    }

    // 异常通知
    @AfterThrowing(pointcut = "pointcut()", throwing = "e")
    public void errorNation(JoinPoint jp, Throwable e){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "方法出错了,错误是: " + e.getMessage());
    }

    // 返回通知
    @AfterReturning(pointcut = "pointcut()", returning = "ret")
    public void ReturnNation(JoinPoint jp, Object ret){
        System.out.println(jp.getTarget() + "的" + jp.getSignature().getName() + "方法的返回结果是: " + ret);
    }

    // 环绕通知
    @Around("pointcut()")
    public void roundNation(ProceedingJoinPoint jp){
        Object t = jp.getTarget();
        String name = jp.getSignature().getName();
        String args = Arrays.toString(jp.getArgs());
        Object rel;

        try {
            System.out.println(t + "的" + name + "方法执行了,参数是:" + args);

            rel = jp.proceed(jp.getArgs());

            System.out.println(t + "的" + name + "方法结果是:" + rel);
        }catch (Throwable e){
            System.out.println(t + "的" + name + "方法出错了:" + e.getMessage());
        }finally {
            System.out.println(t + "的" + name + "方法结束了");
        }
    }

}
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

UserService.java

```java
@Component(value = "userService")
public class UserService {

    public Integer addUser(int n) {
        Integer r = 0;


        r = 100 / n;
        System.out.println("addUser 运行了");
        System.out.println(r);

        return r;
    }

    public int deleteUser(String id) {
        System.out.println("删除:" + id);
        return 1;
    }

}
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

applicationContext.xml

```XML
<?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:context="http://www.springframework.org/schema/context"
   xmlns:aop="http://www.springframework.org/schema/aop"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
   http://www.springframework.org/schema/aop
   http://www.springframework.org/schema/aop/spring-aop-4.0.xsd
   http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-3.2.xsd">


<!--xmlns:context="http://www.springframework.org/schema/context"-->

<!-- <bean id="address" class="com.itxzw.user.model.Address">-->

<!-- </bean>-->

<!-- 开启扫描-->
<context:component-scan base-package="com.itxzw.user" />

<!-- 开启Aspect生成代理对象-->
<aop:aspectj-autoproxy proxy-target-class="false"/>

</beans>
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

测试

```java
    @Test
    public void test02(){

        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

        UserService userService = (UserService) context.getBean("userService");

        userService.addUser(10);

    }
```

![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)

效果

![img](https://img-blog.csdnimg.cn/3881099ebe4c471581ed0560b519b70f.png)![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)编辑







> **不积跬步无以至千里,趁年轻,使劲拼,给未来的自己一个交代!向着明天更好的自己前进吧!**
>
>
> ![img](https://img-blog.csdnimg.cn/02bed6ae9d27419b804c4605db6cee66.gif)![点击并拖拽以移动](data:image/gif;base64,R0lGODlhAQABAPABAP///wAAACH5BAEKAAAALAAAAAABAAEAAAICRAEAOw==)编辑
【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。