Aop 的基础内容

72 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第17天,点击查看活动详情 Aop

(1).简介

image.png

(2).Aop的作用及其优势

​ 作用:在程序运行期间,在不修改源码的情况下对方法进行功能增强(动态代理)

​ 优势:减少代码重复,提高开发效率,并且便于维护

(3).Aop的底层实现

Aop的动态代理技术

image.png

(4).基于jdk的动态代理

public class ProxyTest {
    public static void main(String[] args) {
        // 目标对象
        final Target target = new Target();
        // 增强对象
        final Advice advice = new Advice();
        // 返回值就是动态生成的代理对象
        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(
                // 目标对象类加载器
                target.getClass().getClassLoader(),
                // 目标对象类实现的接口的字节码对象数组
                target.getClass().getInterfaces(),
                // InvocationHandler接口: 内部实现功能增强
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 前置增强
                        advice.before();
                        Object res = method.invoke(target, args);
                        // 后置增强
                        advice.afterReturning();
                        return res;
                    }
                });
        proxy.save();
    }
}

(5).Aop相关概念

​ 1.Target(目标对象):代理的目标对象

​ 2.Proxy(代理对象):一个类被Aop增强后,就会产生一个代理类

​ 3.JoinPoint(连接点):可以被增强的方法

​ 4.PointCut(切入点):已经被增强的方法

​ 5.Advice(通知/增强):拦截到JoinPoint要做的事情

​ 6.Aspect(切面):是切入点(已经被增强的方法)和通知的结合

​ 7.Weaving(织入):将切点和通知结合的过程

(6).Aop入门

1.导入Aop相关坐标

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

2.创建目标接口和目标类(内部有切点)

3.创建切面类(内部有增强方法)

public class MyAspect {
    public void before(){
        System.out.println("前置增强......");
    }
}

4.将目标类和切面类的对象创建权交给Spring

<!--    配置目标对象-->
<bean id="target" class="com.aop.Target"/>
<!--    配置切面对象-->
<bean id="myAspect" class="com.aop.MyAspect"/>

5.在配置文件中配置织入关系

<!--    配置织入(哪些方法需要被增强)-->
<aop:config>
    <!--        声明切面-->
    <aop:aspect ref="myAspect">
        <aop:before method="before" pointcut="execution(public void com.aop.Target.save())"/>
    </aop:aspect>

</aop:config>

6.测试

(7).切点表达式

image.png

(8).通知的种类

image.png

环绕通知:

//     ProceedingJoinPoint: 正在执行的连接点 : 切点
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前增强");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("环绕后增强");
        return proceed;
    }

如果同时配置了环绕增强和后置增强,会先执行环绕后增强然后再执行后置增强

如果同时配置了环绕增强和前置增强,会先执行环绕前增强然后再执行前置增强

(9).抽取切点表达式

<!--            抽取切点表达式-->
<aop:pointcut id="myPointcut" expression="execution(* com.aop.*.*(..))"/>

<aop:around method="around" pointcut-ref="myPointcut"/>

(10).注解实现Aop

@Component("myAspect")
@Aspect  // 表明这是一个切面类
public class MyAspect {
    @Before("execution(* com.anno.*.*(..))")
    public void before(){
        System.out.println("前置增强......");
    }

    public void afterReturning(){
        System.out.println("后置增强");
    }
//     ProceedingJoinPoint: 正在执行的连接点 : 切点
    @Around("execution(* com.anno.*.*(..))")
    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前增强");
        Object proceed = proceedingJoinPoint.proceed();
        System.out.println("环绕后增强");
        return proceed;
    }
}
<!--    开启组件扫描-->
    <context:component-scan base-package="com.anno"/>
<!--    Aop自动代理-->
    <aop:aspectj-autoproxy/>