<Spring>SpringAOP

文章介绍了AOP(面向切面编程)的概念,作为面向对象编程的补充,通过动态代理和注解实现对程序功能的扩展。动态代理部分展示了JDK的InvocationHandler实现,而Spring的AOP支持则利用AspectJ注解进行方法拦截,无需目标类实现接口。文章还提及了不同类型的通知(前置、后置、返回、异常)以及如何配置Spring的注解式AOP。
摘要由CSDN通过智能技术生成

AOP(Aspect Oriented Programming)是一种设计思想,是软件设计领域中的面向切面编程,它是面 向对象编程的一种补充和完善,它以通过预编译方式和运行期动态代理方式实现在不修改源代码的情况 下给程序动态统一添加额外功能的一种技术。

动态代理

  • 代理:将非核心逻辑剥离出来以后,封装这些非核心逻辑的类、对象、方法。
  • 目标:被代理“套用”了非核心逻辑代码的类、对象、方法。
public class CalcProxy {

    //构造前注入被代理的对象
    private Object target;

    public CalcProxy(Object target) {
        this.target = target;
    }

    public Object getProxy() {
        //ClassLoader:加载动态生成的代理类的类加载器
        ClassLoader classLoader = this.getClass().getClassLoader();
        //Interfaces:目标对象实现的所有接口的class对象所组成的数组
        Class<?>[] interfaces = target.getClass().getInterfaces();
        //invocationHandler:设置代理对象实现目标对象方法的过程,即代理类中如何重写接口中的抽象方法
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) {
                Object obj = null;
                try {
                    System.out.println("[动态代理][before] " + method.getName() + ",参数:" + Arrays.toString(args));
                    obj = method.invoke(target, args);
                    System.out.println("[动态代理][after] " + method.getName() + ",结果:" + obj);
                } catch (Exception e) {
                    System.out.println("[动态代理][throw] " + method.getName() + ",异常:" + e);
                    e.printStackTrace();
                } finally {
                    System.out.println("[动态代理][finally] " + method.getName());
                }
                return obj;
            }
        };
        return Proxy.newProxyInstance(classLoader, interfaces, invocationHandler);
    }
}

@Test
public void proxyTest() {
    CalcProxy calcProxy = new CalcProxy(new CalcImpl());
    Calc calc = (Calc) calcProxy.getProxy();
    int i = calc.abs(1, 2);
}
//[动态代理][before] abs,参数:[1, 2]
//[动态代理][after] abs,结果:2
//[动态代理][finally] abs

AOP

  • 说明:动态代理(InvocationHandler):JDK原生的实现方式,需要被代理的目标类必须实现接口。因 为这个技术要求代理对象和目标对象实现同样的接口(兄弟两个拜把子模式)。 cglib:通过继承被代理的目标类(认干爹模式)实现代理,所以不需要目标类实现接口。 AspectJ:本质上是静态代理,将代理逻辑“织入”被代理的目标类编译得到的字节码文件,所以最 终效果是动态的。weaver就是织入器。Spring只是借用了AspectJ中的注解。
  1. 引入依赖
<!-- spring-aspects会帮我们传递过来aspectjweaver -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.1</version>
</dependency>
  1. 编写切面类
@Aspect//标记为切面类
@Component//将此切面类交给spring管理
public class CalcAspect {
    
    @Pointcut("execution(* com.liliu.spring.aop.Calculator.*(..))")
    public void pointCut() {
    }

    //@Before("execution(public int com.liliu.spring.proxy.Calc.abs(int,int))")
    //@Before("execution(* com.liliu.spring.proxy.Calc.*(..))")
    @Before("pointCut()")//相当于try之前
    public void beforeAdvice(JoinPoint joinPoint) {
        System.out.println("[AOP][Before] " + joinPoint.getSignature() + ",参数:" + Arrays.toString(joinPoint.getArgs()));
    }

    @AfterReturning(value = "pointCut()", returning = "result")//相当于try之后
    public void afterReturningAdvice(JoinPoint joinPoint, Object result) {
        System.out.println("[AOP][AfterReturning] " + joinPoint.getSignature() + ",结果:" + result);
    }

    @After(value = "pointCut()")//相当于finally
    public void afterAdvice(JoinPoint joinPoint) {
        System.out.println("[AOP][After] " + joinPoint.getSignature());
    }

    @AfterThrowing(value = "pointCut()", throwing = "ex")//相当于catch
    public void afterReturningAdvice(JoinPoint joinPoint, Throwable ex) {
        System.out.println("[AOP][AfterThrowing] " + joinPoint.getSignature() + ",异常:" + ex);
    }

    @Around(value = "pointCut()")
    public Object aroundAdvice(ProceedingJoinPoint proceedingJoinPoint) {
        Object obj = null;
        try {
            System.out.println("[AOP][Around][Before] " + proceedingJoinPoint.getSignature() + ",参数:" + Arrays.toString(proceedingJoinPoint.getArgs()));
            obj = proceedingJoinPoint.proceed();
            System.out.println("[AOP][Around][AfterReturning] " + proceedingJoinPoint.getSignature() + ",结果:" + obj);
        } catch (Throwable throwable) {
            System.out.println("[AOP][Around][AfterThrowing] " + proceedingJoinPoint.getSignature() + ",异常:" + throwable);
        } finally {
            System.out.println("[AOP][Around][After] " + proceedingJoinPoint.getSignature());
        }
        return obj;
    }
}

前置通知: 使用@Before注解标识,在被代理的目标方法前执行
返回通知: 使用@AfterReturning注解标识,在被代理的目标方法成功结束后执行(寿终正寝)
异常通知: 使用@AfterThrowing注解标识,在被代理的目标方法异常结束后执行(死于非命)
后置通知: 使用@After注解标识,在被代理的目标方法最终结束后执行(盖棺定论)
环绕通知: 使用@Around注解标识,使用try…catch…finally结构围绕整个被代理的目标方法,包 括上面四种通知对应的所有位置

基于注解的AOP

  1. 编写切面类
          切面类上的注解删掉
  2. spring配置文件
<context:component-scan base-package="com.liliu.spring.aopxml"></context:component-scan>

<!--AOP的注意事项:切面类和目标类都需要交给IOC容器管理切面类必须通过@Aspect注解标识为一个切面
在Spring的配置文件中设置<aop:aspectj-autoproxy />开启基于注解的AOP-->
<!--<aop:aspectj-autoproxy />-->
<aop:config>
    <!--配置切面类-->
    <aop:aspect ref="calcAspect">
        <aop:pointcut id="point" expression="execution(* com.liliu.spring.aopxml.*(..))"/>
        <aop:before method="beforeAdvice" pointcut-ref="point"/>
        <aop:after-returning method="afterReturningAdvice" pointcut-ref="point" returning="result"/>
        <aop:after method="afterAdvice" pointcut-ref="point"/>
        <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="point" throwing="ex"/>
    </aop:aspect>
</aop:config>
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值