Spring-AOP

SpringAOP简介

在这里插入图片描述

优势及其作用

在这里插入图片描述

Aop的底层实现

在这里插入图片描述

Aop的动态代理技术

在这里插入图片描述

基于jdk的动态代理

package cn.zhw.proxy.jdk;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {
        Target target = new Target();

        Advice advice = new Advice();


        //返回动态代理的代理对象,必须用接口接受
        TargetInter o = (TargetInter) Proxy.newProxyInstance(
                target.getClass().getClassLoader(), //目标对象的加载器
                target.getClass().getInterfaces(),//目标对象的接口字节码对象数组
                new InvocationHandler() {
                    //调用代理对象的任何方法,实质执行的都是invoke方法
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                        //前置增强方法
                        advice.before();

                        //获取方法名字
                        String name = method.getName();
                        System.out.println(name);

                        //method为代理对象调用的方法
                        Object invoke = method.invoke(target, args);

                        //打印方法的参数
                        for (Object arg : args) {
                            System.out.println(arg);
                        }

                        //后置增强方法
                        advice.after();
                        
                        return null;
                    }
                }
        );
        //执行代理对象的方法
        o.save(56);

        System.out.println("=====");

        o.update("zhw","henan");
    }
}

结果

前置增强
save  方法名
56 参数
后置增强
=====
前置增强
update 方法名
zhw  参数
henan 参数
后置增强

当执行代理对象的中的方法,会接受其中的参数给invoke方法的args数组里面,把方法给invoke的method参数,每一次执行代理对象那个的方法,其实就是执行的invoke方法

package cn.zhw.proxy.jdk;

import org.junit.Test;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyTest {

    @Test
    public void test1(){
        Target target = new Target();
        Advice advice = new Advice();
        TargetInter proxy = (TargetInter) Proxy.newProxyInstance(
                target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        advice.before();
                        String name = method.getName();
                        if("save".equals(name)){
                            method.invoke(target,args);
                        }else {
                            System.out.println("不是save方法");
                        }
                        advice.after();
                        return null;
                    }
                }
        );
        proxy.update("zhw","kaifeng");
    }
}
前置增强
不是save方法
后置增强

基于cglib的动态代理

在这里插入图片描述

package cn.zhw.proxy.cglib;

import org.junit.Test;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @author 小七
 * 测试cglib动态代理
 */
public class ProxyTest {

    @Test
    public void test(){
        Target target = new Target(); //创建目标对象

        Advice advice = new Advice(); //创建切面类

        Enhancer enhancer = new Enhancer();   //创建增强器

        enhancer.setSuperclass(Target.class); //设置父类

        enhancer.setCallback(new MethodInterceptor() { //设置回调
        
            /**
             * @param method 目标方法
             * @param objects 方法的参数
             */
        @Override
         public Object intercept(Object o, Method method, Object[] objects,
                                 MethodProxy methodProxy) throws Throwable {
            //前置增强
            advice.before();
            
            Object invoke = method.invoke(target, objects);
            
			//后置增强
            advice.after();
            
            return invoke;
        }});

        Target proxy = (Target) enhancer.create(); //创建代理对象

        proxy.update("zhw","henan"); //执行代理对象的方法

}
}
前置增强
zhw:henan
后置增强

AOP相关概念

在这里插入图片描述

AOP开发明确的事项

在这里插入图片描述

快速入门

在这里插入图片描述
1.引入坐标

<dependency>
           <groupId>org.springframework</groupId>
           <artifactId>spring-context</artifactId>
           <version>5.2.9.RELEASE</version>
       </dependency>
       <dependency>
           <groupId>junit</groupId>
           <artifactId>junit</artifactId>
           <version>4.12</version>
           <scope>test</scope>
       </dependency>

       <!-- aspectj的织入比spring原生的aop实现效率高 -->
       <dependency>
           <groupId>org.aspectj</groupId>
           <artifactId>aspectjweaver</artifactId>
           <version>1.8.13</version>
       </dependency>

2.创建目标接口和目标类
目标类接口

package cn.zhw.aop.service;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 7:27
 */
public interface LogService {

    public void pringDate(String name);
}

目标类

package cn.zhw.aop.service.impl;

import cn.zhw.aop.service.LogService;
import org.springframework.stereotype.Service;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 7:27
 */
@Service
public class LogServiceImpl implements LogService {
    @Override
    public void pringDate(String name) {
        System.out.println(name);
//        throw new IndexOutOfBoundsException("我故意抛出的异常");
    }
}

3.创建切面类

package cn.zhw.aop.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 7:26
 */
public class LogAspect {
//    前置通知
    public void before(JoinPoint joinPoint) throws Throwable {
        System.out.println("LogAspect的前置通知");
        Object[] args = joinPoint.getArgs();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < args.length; i++) {
            stringBuilder.append(args[i]);
        }
//        System.out.println("获取的参数为:"+args[0]);
        System.out.println("LogAspect的前置通知执行完成");
    }

//    最终通知:无论是否出现异常都会执行
    public void after(JoinPoint joinPoint) throws Throwable {
        System.out.println("LogAspect的最终通知");
        System.out.println("LogAspect的最终通知执行完成");

    }

//    环绕通知:需要在方法中拦截使用joinPoint.proceed()方法进行调用
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知前");
        joinPoint.proceed(joinPoint.getArgs());
        System.out.println("环绕通知后");
    }

//    后置通知:指定的增强的方法执行后才执行
    public void returning(JoinPoint joinPoint) throws Throwable {
        System.out.println("后置通知");
        System.out.println("后置通知完成");
    }

    public void throwing(JoinPoint joinPoint,Exception e) throws Throwable {
        System.out.println("出现异常");
        System.out.println("异常信息为:"+e.getMessage());
    }
}


4.将目标类和切面类交给spring容器管理

<!--    配置目标类-->
    <bean id="target" class="cn.zhw.proxy.cglib.Target"/>

<!--    配置切面类-->
    <bean  id="myAspect" class="cn.zhw.proxy.cglib.MyAspect"/>

5.引入Aop命名空间,配置织入关系

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

">


<!--        aop配置,xml配置-->
    <bean id="myAdvice" class="cn.zhw.aop.aspect.LogAspect"/>
    
    <bean id="logService" class="cn.zhw.aop.service.impl.LogServiceImpl"/>
    
    <aop:config>
        <!--        全局接入点-->
        <aop:pointcut id="pointcut" expression="execution(*  cn.zhw.aop.service.impl.LogServiceImpl.*(..))"/>
        <!--        配置aop-->
        <aop:aspect ref="myAdvice">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
            <aop:around method="around" pointcut-ref="pointcut"/>
            <aop:after-returning method="returning" pointcut-ref="pointcut"/>
<!--            将抛出的错误给参数e-->
            <aop:after-throwing method="throwing" pointcut-ref="pointcut" throwing="e"/>
        </aop:aspect>
    </aop:config>
</beans>

6.测试

package cn.zhw.aop;

import cn.zhw.aop.service.LogService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.PriorityQueue;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 14:08
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private ApplicationContext app;

    @Autowired
    private LogService logService;

    @Test
    public void test1(){
        this.logService.pringDate("LogService的方法执行了");
    }
}

7.结果

LogAspect的前置通知
LogAspect的前置通知执行完成
环绕通知前
LogService的方法执行了
后置通知
后置通知完成
环绕通知后
LogAspect的最终通知
LogAspect的最终通知执行完成

切点表达式写法

在这里插入图片描述

execution(* *..*.*(..))
表示 任意返回类型 所有包 所有类 所有方法 所有的参数

通知的类型

在这里插入图片描述
1.通知的类型以及使用

package cn.zhw.aop.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 7:26
 */
public class LogAspect {
//    前置通知
    public void before(JoinPoint joinPoint) throws Throwable {
        System.out.println("LogAspect的前置通知");
        Object[] args = joinPoint.getArgs();
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < args.length; i++) {
            stringBuilder.append(args[i]);
        }
//        System.out.println("获取的参数为:"+args[0]);
        System.out.println("LogAspect的前置通知执行完成");
    }

//    最终通知:无论是否出现异常都会执行
    public void after(JoinPoint joinPoint) throws Throwable {
        System.out.println("LogAspect的最终通知");
        System.out.println("LogAspect的最终通知执行完成");

    }

//    环绕通知:需要在方法中拦截使用joinPoint.proceed()方法进行调用
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("环绕通知前");
        joinPoint.proceed(joinPoint.getArgs());
        System.out.println("环绕通知后");
    }

//    后置通知:指定的增强的方法执行后才执行
    public void returning(JoinPoint joinPoint) throws Throwable {
        System.out.println("后置通知");
        System.out.println("后置通知完成");
    }
//     异常通知:目标方法执行的时间出现异常,才会执行本方法,并将exception给参数e
    public void throwing(JoinPoint joinPoint,Exception e) throws Throwable {
        System.out.println("出现异常");
        System.out.println("异常信息为:"+e.getMessage());
    }
}

2.配置增强


<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"

       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd

">

<!--        aop配置,xml配置-->
    <bean id="myAdvice" class="cn.zhw.aop.aspect.LogAspect"/>
    <bean id="logService" class="cn.zhw.aop.service.impl.LogServiceImpl"/>
    <aop:config>
        <!--        全局接入点-->
        <aop:pointcut id="pointcut" expression="execution(*  cn.zhw.aop.service.impl.LogServiceImpl.*(..))"/>
        <!--        配置aop-->
        <aop:aspect ref="myAdvice">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
            <aop:around method="around" pointcut-ref="pointcut"/>
            <aop:after-returning method="returning" pointcut-ref="pointcut"/>
<!--            将抛出的错误给参数e-->
            <aop:after-throwing method="throwing" pointcut-ref="pointcut" throwing="e"/>
        </aop:aspect>
    </aop:config>
</beans>

AOP注解开发

1.目标类

package cn.zhw.aop.service.impl;

import cn.zhw.aop.service.LogService;
import org.springframework.stereotype.Service;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 7:27
 */
@Service
public class LogServiceImpl implements LogService {
    @Override
    public void pringDate(String name) {
        System.out.println(name);
//        throw new IndexOutOfBoundsException("我故意抛出的异常");
    }
}

2.切面类

package cn.zhw.aop.aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import org.springframework.test.annotation.Commit;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 7:26
 */
@Component
@Aspect
public class AnnotationAspect {

    @Pointcut("execution(*  cn.zhw.aop.service.impl.LogServiceImpl.*(..))")
    public void pointcut(){};

    @Before("pointcut()")
//    前置通知
    public void before(JoinPoint joinPoint) throws Throwable {
        System.out.println("AnnotationAspect的前置通知");
        System.out.println("AnnotationAspect的前置通知执行完成");
    }

//    最终通知:无论是否出现异常都会执行
    @After("pointcut()")
    public void after(JoinPoint joinPoint) throws Throwable {
        System.out.println("AnnotationAspect的最终通知");
        System.out.println("AnnotationAspect的最终通知执行完成");

    }

//    环绕通知:需要在方法中拦截使用joinPoint.proceed()方法进行调用
    @Around("pointcut()")
    public void around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("AnnotationAspect环绕通知前");
        joinPoint.proceed(joinPoint.getArgs());
        System.out.println("AnnotationAspect环绕通知后");
    }

//    后置通知:指定的增强的方法执行后才执行
    @AfterReturning("pointcut()")
    public void returning(JoinPoint joinPoint) throws Throwable {
        System.out.println("AnnotationAspect后置通知");
        System.out.println("AnnotationAspect后置通知完成");
    }

    @AfterThrowing(value = "pointcut()",throwing = "e")
    public void throwing(JoinPoint joinPoint,Exception e) throws Throwable {
        System.out.println("AnnotationAspect出现异常");
        System.out.println("异常信息为:"+e.getMessage());
    }
}

3.配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
    <!-- 注解版配置
        1.使用包扫描把bean注册进来
        2.开启aop自动代理
        3.编写切面类
    -->
    <aop:aspectj-autoproxy/>-->
    <context:component-scan base-package="cn.zhw.aop">
    </context:component-scan>
</beans>

4.测试

package cn.zhw.aop;

import cn.zhw.aop.service.LogService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.PriorityQueue;

/**
 * @author 小七
 * @date 2022/7/4
 * @time 14:08
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class AopTest {
    @Autowired
    private ApplicationContext app;

    @Autowired
    private LogService logService;

    @Test
    public void test1(){
        this.logService.pringDate("LogService的方法执行了");
    }
}

知识小结

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值