Spring实现Aop的三种方式及遇到的一些问题

本文详细介绍了如何在Spring框架中使用AOP实现切面编程,包括接口方式、自定义切面和注解方式的应用,以及版本问题的解决方案。重点讲解了横切关注点、切面、通知、代理和切入点的概念,并通过示例展示了如何配置切面并观察其在实际操作中的效果。
摘要由CSDN通过智能技术生成

测试环境:
jdk1.8
maven3.6.3

一、Pom依赖

//这些依赖不能以注解方式实现Aop,下文有详细的相关错误说明

<dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.3.2</version>
    </dependency>
         <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.5.4</version>
        </dependency>
        <dependency>
            <groupId>org.apache.geronimo.bundles</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.6.8_2</version>
    </dependency>

二、实现的方式

关于Aop的一些名词解释:

  • 横切关注点:我们想要给目标类添加的业务功能,如:日志、安全、缓存等。
  • 切面(ASPECT):横切关注点 被模块化的特殊对象。即,它是一个类。
  • 通知(Advice):切面必须要完成的工作。即,它是切面类中的一个方法。
  • 目标(Target):被通知对象。也就是需要增加功能的目标类。
  • 代理(Proxy):向目标对象应用通知之后创建的对象。
  • 切入点(PointCut):切面通知 执行的 “地点”的定义。
  • 连接点(JointPoint):与切入点匹配的执行点。
    (以上名词解释:参考了—狂神—的博客https://blog.csdn.net/weixin_44207403/article/details/106736102)
1.实现Spring提供的接口

在Spring-aop这个包下,有一些接口,实现这些接口,就生成了通知类。通知可以被织入或者说添加到目标类中去,达到增强其功能的作用;织入通知会生成代理类,我们后续在调用目标类的时候实际上调用的是代理类(代理类包含了对目标类的引用和一些扩展的方法-----我们织入的通知),该接口就是生成通知------也可以理解为这是一个特殊的切面,只有一个方法的切面。
aop包:
org.springframework.aop
以上的一些接口,直接或者间接的实现了Advice(通知)接口。实现这些接口,重写方法,生成通知。

实例如下:
(1)创建一个类,实现AfterReturningAdvice 接口

@Component
public class Log  implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        System.out.println("【Log】:"+method.getName()+"被执行了");
    }
}

(2)spring配置文件—配置

  <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* com.yh.pojo.aop.obj.Book.*(..))"/>
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"></aop:advisor>
    </aop:config>

(3) 测试

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("bean.xml");
        Book book = (Book) context.getBean("book");
        book.add();
    }
}

(4)结果

add方法被执行
【Log】:add被执行了
2.自定义切面

切面是对要增加的功能的抽象,是一个类,里面包含了一些方法,这些方法也就是通知。上面的那种方式可以添加一个通知,而切面可以是多个,并且切面可以是一个普通的Java类。(ps:如果增加一个业务功能需要执行多个方法的话,那么需要定义多个通知类,而切面只需要定义一个就够了)。

实例如下:
(1)定义切面

@Component
//定义一个普通的java类作为切面
public class Log2 {
    public void before(){
        System.out.println("这是一个切面的前置");
    }
    public  void after(){
        System.out.println("切面定义的后置通知");
    }
}

(2)spring配置文件—配置

 <aop:config>
        <aop:aspect id="myAspect" ref="log2">
            <aop:pointcut id="pointcut" expression="execution(* com.yh.pojo.aop.obj.Book.*(..))"/>
            <aop:before method="before" pointcut-ref="pointcut"></aop:before>
            <aop:after-returning method="after" pointcut-ref="pointcut"></aop:after-returning>
        </aop:aspect>
    </aop:config>

(3)测试类

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("bean.xml");
        Book book = (Book) context.getBean("book");
        book.add();
    }
}

(4)结果

这是一个切面的前置
add方法被执行
切面定义的后置通知

(5) 结论
切面类可以是普通java类,通过spring配置文件创建为切面,其中需要定义切入点,并将设置其方法作为前置通知、后置通知等。

3.注解方式

这种方式,是容易出错的地方,因为这东西跟jar包版本以及jdk环境之类的相关。上文引入的pom依赖是无法以注解方式运行的,会报错。具体报的错及解决方式会在下面做阐述。

使用方式:
(1)定义一个普通的java类,然后再类上添加@Aspect注解,表明他是一个切面,而不必像第二种方式那样再配置文件中声明定义。如下:

@Component //表示是Spring的一个Bean,可以被扫描进入Spring容器
@Aspect//表示切面
public class LogAnnoattion {
    @Pointcut(value = "execution(* com.yh.pojo.aop.obj.Book.*(..))")
    public void pointcut(){
    }
    @Before(value = "pointcut()")
    public  void logBefore(){
        System.out.println("声明----Before通知");
    }
    @AfterReturning(value = "pointcut()")
    public  void logAfter(){
        System.out.println("声明-----AfterReturning通知");
    }
}

(2)Spring配置文件----配置

 <aop:aspectj-autoproxy />//开启自动代理,即:为@Aspect标记的类的目标类创建代理,然后将该切面织入进入代理类中

(3)测试

public class Test {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context =
                new ClassPathXmlApplicationContext("bean.xml");
        Book book = (Book) context.getBean("book");
        book.add();
    }
}

(4)结果
在这里插入图片描述
对于上面的错误,我百度了很多博客,才找到一些有帮助的解释:aspectjweaver的版本太低了,要换成高版本的。aspectjweaver的依赖如下:

  <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.5.4</version>
        </dependency>

最初的 groupId都不是上面这个,上面是正确的依赖,不过被我调低了版本然后让它报错。我最开始的那个groupID即使被我调到了最新版本,也会报错,然后我就去MVN上面找了其他groupID的aspectjweaver,改完之后,就可以正常运行了 。

解决方式:
调高版本即可。

 <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.6</version>
        </dependency>

结果:

声明----Before通知
add方法被执行
声明-----AfterReturning通知

以上。(PS:如上述有错,欢迎指正,谢谢!!!)
在这里插入图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值