美文网首页
Spring AOP基础

Spring AOP基础

作者: luoxn28 | 来源:发表于2017-06-22 22:57 被阅读0次

    IOC和AOP是Spring的两大基石,AOP(面向切面编程),是一种编程范式,提供从另一个角度来考虑程序结构从而完善面向对象编程(OOP)。

    在进行 OOP 开发时,都是基于对组件(比如类)进行开发,然后对组件进行组合,OOP 最大问题就是无法解耦组件进行开发。AOP 为开发者提供一种进行横切关注点(比如日志关注点)分离并织入的机制,把横切关注点分离,然后通过某种技术织入到系统中,从而无耦合的完成了我们的功能。

    AOP世界中的居民

    • Joinpoint(连接点):指那些被拦截到的点。在Spring中只支持方法级别的连接点。
    • Pointcut(切入点):指需要配置的Joinpoint。
    • Advice(通知):指拦截到Joinpoint后要做的操作,通知分为前置通知/后置通知/异常通知/后置通知/环绕通知。
    • Aspect(切面):切入点和通知的结合。
    • Target(目标对象):需要被代理的对象。
    • Proxy(代理对象):目标对象被AOP 织入通知产生的对象。
    • Weaving(织入):指把通知应用到目标对象来创建代理对象的过程(Spring采用动态代理织入,AspectJ采用编译期织入和类装载期织入)。

    AOP中的通知类型

    • 前置通知:在切入点选择的连接点处的方法之前执行的通知,该通知不影响正常程序执行流程,除非发生了异常。
    • 后置通知:在切入点选择的连接点处的方法正常执行完毕时执行的通知。
    • 返回通知:在切入点选择的连接点处的方法返回时执行的通知,不管抛没抛出异常都执行,类似于 Java 中的 finally 块。
    • 异常通知:在切入点选择的连接点处的方法抛出异常返回时执行的通知。
    • 环绕通知:环绕着在切入点选择的连接点处的方法所执行的通知,环绕通知可以在方法调用之前和之后自定义任何行为,并且可以决定是否执行连接点处的方法、替换返回值、抛出异常等等。

    AOP程序示例

    @Component
    public interface HelloAop {
        void hello();
    }
    
    @Component
    public class HelloAopImpl implements HelloAop{
        @Override
        public void hello() {
            System.out.println("---hello HelloAopImpl---");
        }
    }
    
    @Aspect
    @Component
    public class HelloAopAspect {
        @Before("execution(public void com.luo.aop.HelloAopImpl.hello())")
        public void beforeAdvice(JoinPoint point) {
            String methodName = point.getSignature().getName();
            System.out.println("beforeAdvice: " + methodName);
        }
    
        @After("execution(public void com.luo.aop.HelloAopImpl.hello())")
        public void afterAdvice(JoinPoint point) {
            String methodName = point.getSignature().getName();
            System.out.println("afterAdvice: " + methodName);
        }
    
        @AfterThrowing("execution(public void com.luo.aop.HelloAopImpl.hello())")
        public void afterThrowingAdvice(JoinPoint point) {
            String methodName = point.getSignature().getName();
            System.out.println("afterThrowingAdvice: " + methodName);
        }
    
        @AfterReturning("execution(public void com.luo.aop.HelloAopImpl.hello())")
        public void afterReturningAdvice(JoinPoint point) {
            String methodName = point.getSignature().getName();
            System.out.println("afterReturningAdvice: " + methodName);
        }
    
        @Around("execution(public void com.luo.aop.HelloAopImpl.hello())")
        public Object aroundAdvice(ProceedingJoinPoint point) {
            Object result = null;
    
            // 环绕通知(前通知)
            System.out.println("aroundAdvice start...");
            try {
                // 前置通知
                result = point.proceed(); // 目标方法执行
            } catch (Throwable throwable) {
                // 异常通知
                throwable.printStackTrace();
            }
            // 环绕通知(后通知)
            System.out.println("aroundAdvice end...");
            // 后置通知
            // 返回通知
    
            return result;
        }
    }
    
    public static void main(String[] args) {
        ApplicationContext ctx = new ClassPathXmlApplicationContext("springConfig.xml");
    
        HelloAop helloAop = ctx.getBean(HelloAop.class);
    
        helloAop.hello();
    }
    

    spring配置文件:

    <!-- 自动扫描 -->
    <context:component-scan base-package="com.luo.aop"/>
    
    <!-- 使用AspjectJ自动生成代理对象 -->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
    
    AOP通知输出结果

    指定切面优先级

    在同一个连接点上应用不止一个切面时, 除非明确指定, 否则它们的优先级是不确定的。切面的优先级可以通过实现 Ordered 接口或利用 @Order 注解指定。实现 Ordered 接口, getOrder() 方法的返回值越小, 优先级越高.若使用 @Order 注解, 序号出现在注解中。

    @Aspect
    @Order(0)
    @Component
    public class HelloAspect2 { }
    
    @Aspect
    @Order(1)
    @Component
    public class HelloAspect { }
    

    参考资料:

    1. 《Spring揭秘》AOP章节
    2. Spring学习之AOP总结帖

    相关文章

      网友评论

          本文标题:Spring AOP基础

          本文链接:https://www.haomeiwen.com/subject/nigfcxtx.html