aop中基于xml和注解的advice

282 阅读2分钟

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

aop基本概念

AOP - Aspect Oriented Programming, 面向切面编程. 通过预编译方式和运行时动态代理的方式实现功能的一种技术.

pointcut - 切入点, 指被增强的方法

advice - 增强或者通知, 给切入点增加功能的方法

aspect - 切面, pointcut + advice, 也就是切点 + 增强称为切面

weaving - 织入, 将切点和增强结合的过程称为织入

常见的增强类型

before - 前置增强, 在指定方法执行之前的增强

after-returning - 后置增强, 在指定方法执行之后的增强

around - 环绕增强, 在指定方法前后都执行的增强

throwing - 异常抛出增强, 在指定方法执行中有异常时的增强

after - 最张执行的方法, 不论指定方法是否有异常抛出

导入aop坐标

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.2.17.RELEASE</version>
</dependency>
<dependency>
    <groupId>org.aspectj</groupId>
    <artifactId>aspectjweaver</artifactId>
    <version>1.9.2</version>
</dependency>

创建接口类

public interface TargetInterface {
    public void save();
}

创建实现类

public class Target implements TargetInterface {
    public void do() {
        System.out.println("do...");
    }
}

基于xml的aop

创建增强类

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

    public void afterReturning() {
        System.out.println("后置增强...");
    }

    public void throwing() {
        System.out.println("异常抛出增强...");
    }

    public void after() {
        System.out.println("最后增强...");
    }
}

配置xml

<!-- 目标对象 -->
<bean id="target" class="com.raylee.aop.Target"></bean>

<!-- 切面对象 -->
<bean id="myAspect" class="com.raylee.aop.MyAspect"></bean>

<!-- 配置织入 -->
<aop:config>
    <aop:aspect ref="myAspect">

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

        <!-- 前置增强 -->
        <aop:before method="before" pointcut="execution(* com.raylee.aop.*.*(..))"/>

        <!-- 后置增强 -->
        <aop:after-returning method="afterReturning" pointcut="execution(* com.raylee.aop.*.*(..))"/>

        <!-- 环绕增强 -->
        <aop:around method="around" pointcut-ref="myPoint"/>

        <!-- 当有异常时进行增强 -->
        <aop:after-throwing method="throwing" pointcut-ref="myPoint"/>

        <!-- 最终增强 -->
        <aop:after method="after" pointcut-ref="myPoint"/>

    </aop:aspect>
</aop:config>

进行测试

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class TestAop {
    @Autowired
    private TargetInterface target;

    @Test
    public void test() {
        target.do();
    }
}

输出结果

前置增强...
do...
后置增强...
最终增强...

基于注解的aop

定义增强类

@Component("myAspect")
@Aspect
public class MyAspect {

    // 定义切点表达式
    @Pointcut("execution(* com.raylee.anno.*.*(..))")
    public void pointcut() {}

    @Before("execution(* com.raylee.anno.*.*(..))")
    public void before() {
        System.out.println("anno-前置增强...");
    }

    @AfterReturning("execution(* com.raylee.anno.*.*(..))")
    public void afterReturning() {
        System.out.println("anno-后置增强...");
    }

//    @Around("execution(* com.raylee.anno.*.*(..))")
//    @Around("pointcut()")
//    @Around("MyAspect.pointcut()")
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("anno-环绕前增强...");
        Object o = pjp.proceed();
        System.out.println("anno-环绕后增强...");
        return 0;
    }

    @AfterThrowing("MyAspect.pointcut()")
    public void throwing() {
        System.out.println("anno-异常抛出增强...");
    }

    @After("MyAspect.pointcut()")
    public void after() {
        System.out.println("anno-最终增强...");
    }
}

配置xml

<!-- 组件扫描 --><context:component-scan base-package="com.raylee.anno"/><!-- aop自动代理 --><aop:aspectj-autoproxy/>

进行测试

@RunWith(SpringJUnit4ClassRunner.class)@ContextConfiguration("classpath:applicationContext-anno.xml")public class TestAop {    @Autowired    private TargetInterface target;    @Test    public void test() {        target.do();    }}

测试结果

anno-前置增强...do...anno-后置增强...anno-最终增强...