AOP的实现方式一

一.什么是AOP

AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。

AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。

利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

 使用Spring接口

接口:

package top.lostyou.service;

public interface UserService {
    public void add();
    public void delete();
    public void update();
    public void query();
}

 

真实对象:

package top.lostyou.service;

public class UserServiceImp implements UserService {
    public void add() {
        System.out.println("增加了一个用户!");
    }

    public void delete() {
        System.out.println("删除了一个用户");
    }

    public void update() {
        System.out.println("更新了一个用户");
    }

    public void query() {
        System.out.println("查询了一个用户");
    }
}

 

使用spring的代理后,我们可以使用一些spring的一些接口来完成动态代理,这些接口都是前辈们写好的,我们可以像套模板一样直接使用

MethodBeforeAdvice 接口允许你在目标方法执行之前插入自定义逻辑。它只有一个需要实现的方法:

  • before(Method method, Object[] args, Object target) throws Throwable;

    • method: 即将被调用的目标方法。
    • args: 传递给目标方法的参数数组。
    • target: 目标对象,即包含即将被执行的方法的对象实例。

通过实现这个接口并重写 before 方法,你可以在目标方法执行前做一些事情

AfterReturningAdvice 接口允许你在目标方法成功执行之后插入自定义逻辑。注意,如果目标方法抛出了异常,那么这个通知不会被执行。它也只有一个需要实现的方法:

afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable;

  • returnValue: 目标方法的返回值。
  • method: 已经被执行的方法。
  • args: 传递给目标方法的参数数组。
  • target: 目标对象。

通过实现这个接口并重写 afterReturning 方法,你可以在目标方法正常完成后做一些处理

动态代理接口:

package top.lostyou.log;

import org.springframework.aop.MethodBeforeAdvice;

import java.lang.reflect.Method;

public class Log implements MethodBeforeAdvice {
    // method:要执行目标对象的方法
    // args: 参数
    //target:目标对象
    public void before(Method method, Object[] args, Object target) throws Throwable {
        System.out.println(target.getClass().getName()+"的"+method.getName()+"被执行了");
    }
}

package top.lostyou.log;

import org.springframework.aop.AfterReturningAdvice;

import java.lang.reflect.Method;

public class AfterLog implements AfterReturningAdvice {
    public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
        // returnValue :返回值
        System.out.println("被执行了"+ method.getName()+"方法,返回值为:"+returnValue);
    }
}

 

spring配置bean 和 aop

<?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
        http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 注册bean -->
    <bean id="userServiceImp" class="top.lostyou.service.UserServiceImp"/>
    <bean id="log" class="top.lostyou.log.Log"/>
    <bean id="afterLog" class="top.lostyou.log.AfterLog"/>

    <!-- 方式一:使用原生的spring API接口 -->
    <!-- 配置AOP:需要导入约束 -->
    <aop:config>
        <!-- 切入点  expression:表达式 , execution(要执行的位置! * * * * * * ) -->
        <aop:pointcut id="poincut" expression="execution(* top.lostyou.service.UserServiceImp.*(..))"/>
        <!-- 执行环绕增加!  -->
        <aop:advisor advice-ref="log" pointcut-ref="poincut"/>
        <aop:advisor advice-ref="afterLog" pointcut-ref="poincut"/>
    </aop:config>
</beans>

 

这里要注意的是,我们所配置的切入点,有一个模板公式:

expression表达式:其中  execution(* * * * * *)

这六个  *  号的意思为:修饰符  返回值  包名.类名/接口名.方法名(参数列表)

使用是一般用  *  号占位,代表“所有”

 

测试类:

import org.springframework.context.support.ClassPathXmlApplicationContext;
import top.lostyou.service.UserService;
import top.lostyou.service.UserServiceImp;

public class tsetMy {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        // 动态代理的必须是接口:重点
        UserService imp = (UserService)context.getBean("userServiceImp");
        imp.add();
    }
}

 如果测试失败可以尝试导入依赖:

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

Spring AOP 和 AspectJ 都是用于实现面向切面编程(AOP)的技术,但它们的工作方式和使用场景有所不同。Spring AOP 默认是基于代理(Proxy-based)的轻量级AOP框架,它非常适合用来解决应用中大多数横切关注点的问题,比如日志记录、事务管理和安全性等。然而,Spring AOP 有一些限制:

  1. 代理机制:Spring AOP 主要使用JDK动态代理来代理接口,或者在没有实现接口的情况下使用CGLIB代理类。这意味着它只能对方法调用进行拦截,对于同一对象内部的方法调用(即通过this关键字调用的方法),无法提供通知。

  2. 功能限制:Spring AOP 的功能集较AspectJ来说较为基础,虽然足以应对许多日常场景,但在需要更强大、更灵活的AOP能力时(如更复杂的切入点表达式或字段级别的通知),则显得力不从心。

在这种情况下,引入 aspectjweaver 库就变得必要了,尤其是当你希望利用 AspectJ 提供的全功能AOP支持时。通过将 Spring AOP 与 AspectJ 结合使用,可以克服上述限制:

  • 完全性:AspectJ 支持编译期、编译后、加载时和运行时编织(weaving)。这允许你在更多的场景下应用切面逻辑,包括但不限于方法调用、字段访问/修改、对象构造等。
  • 性能优化:尽管 Spring AOP 是基于代理的,因此在某些情况下可能不如 AspectJ 编织效率高,但是结合使用两者可以在保证灵活性的同时提高性能和能力。
  • 复杂切入点的支持:AspectJ 提供了比Spring AOP更为丰富和强大的切入点语言,能够更加精确地控制何时何地应用通知。

因此,如果你的项目需要上述提到的高级功能,或者你正在使用一些特定的Spring组件或第三方库,这些组件或库要求或推荐使用 AspectJ 进行更深程度的集成和增强,那么即使已经导入了 Spring AOP,你也可能需要同时导入 aspectjweaver 依赖来满足这些需求。

 

posted @ 2023-02-21 20:02  回忆也交给时间  阅读(40)  评论(0)    收藏  举报