zoukankan      html  css  js  c++  java
  • Spring AOP面向切面编程

    AOPAspect Oriented Program 面向切面编程

    首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能。

    所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务

    所谓的周边功能,比如性能统计,日志,事务管理等等

    周边功能在Spring的面向切面编程AOP思想里,即被定义为切面

    在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发
    然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP

    Spring AOP原理和用法

    常用术语

    join point

    连接点(join point)中文翻译大致意思是join point在spring aop中作为一种方法或者是对报错的处理。比如说刚举的例子,切面log是基于f方法的,而这个f方法就是连接点,我个人理解就是切面和主逻辑的连接处。

    Advice

    1581753129397
    也就是增强,为了实现log日志,得编写一些逻辑代码Logic,但此时,我们需要在不同的连接点编写代码,可以说advice决定了在原有方法功能中出现的位置和时机。可分为around before after

    Pointcut

    可以与任何join point点进行匹配,匹配后的位置就是切面的位置。

    target object

    顾名思义,目标对象
    1581753136685
    如上图,f方法里实现的m功能再进行一些修改后(或者说增强)实现了n功能,而target object,也就是基础对象,增强后的方法f,则是被存在代理对象proxy object中。

    AOP Proxy

    aop代理,也就是为了实现方法增强而编写的对象,编写方式有jdk动态代理等,在我的另一篇文章也有写到。

    Weaving

    编织,也就是把切面应用到目标对象来创建新的代理对象的过程。也就是把上图的target object通过切面穿件proxy object的过程。

    实现方式

    先把测试用的类创好

    package service;
    
    public class ProductService {
        public void doSomeService(){
            System.out.println("doSomeService");
        }
    }
    
    public class TestAOP {
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext(new String("applicationContext.xml"));
            ProductService s = (ProductService) context.getBean("s");
            s.doSomeService();
        }
    }
    
    

    通过Spring API实现1

    创建一个LoggerAspect类

    package aspect;
    
    import org.aspectj.lang.ProceedingJoinPoint;
    
    public class LoggerAspect {
        public Object log(ProceedingJoinPoint joinPoint) throws Throwable{
            System.out.println("start log: "+joinPoint.getSignature().getName());
            Object object = joinPoint.proceed();
            System.out.println("end log: "+joinPoint.getSignature().getName());
            return object;
        }
    }
    
    

    在xml文件中添加以下

        <bean name="s" class="service.ProductService"></bean>
        <bean id="loggerAspect" class="aspect.LoggerAspect"/>
    	<aop:config>
            <aop:pointcut id="loggerCutPoint" expression="execution(* service.ProductService.*(..)) "/>
            <aop:aspect id="logAspect" ref="loggerAspect">
                <aop:around pointcut-ref="loggerCutPoint" method="log"/>
            </aop:aspect>
        </aop:config>
    

    解释一下

    config中,pointcut是切点,id是标识符(用于下面的pointcut-ref),expression是执行表达式,也就是触发的条件

    执行表达式的格式如下:

    execution(modifiers-pattern? ret-type-pattern declaring-type-pattern? name-pattern(param-pattern) throws-pattern?) 
    

    除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外,所有的部分都是可选的。 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是 * ,它代表了匹配任意的返回类型。 一个全称限定的类型名将只会匹配返回给定类型的方法。名字模式匹配的是方法名。 你可以使用 * 通配符作为所有或者部分命名模式。 参数模式稍微有点复杂:() 匹配了一个不接受任何参数的方法, 而 (..) 匹配了一个接受任意数量参数的方法(零或者更多)。 模式 () 匹配了一个接受一个任何类型的参数的方法。 模式 (,String) 匹配了一个接受两个参数的方法,第一个可以是任意类型,第二个则必须是String类型。
    一些常见切入点表达式的例子。

    execution(public * (..))  任意公共方法的执行;
    execution(
    set(..))  任何一个以“set”开始的方法的执行;
    execution(
    com.xyz.service.AccountService.(..))   AccountService接口的任意方法的执行;
    execution(
    com.xyz.service..(..))  定义在service包里的任意方法的执行;
    execution(* com.xyz.service...(..))  定义在service包或者子包里的任意方法的执行;

    aop:aspect标签中注册了相应的切面,子标签around说明了是包围式的

    可以看到LoggerAspetc类中

            System.out.println("start log: "+joinPoint.getSignature().getName());
            Object object = joinPoint.proceed();
            System.out.println("end log: "+joinPoint.getSignature().getName());
    

    中间的那句就是将来与某个核心功能编织之后,用于执行核心功能的代码

    结果:1581753538769

    通过Spring API实现2

    创建Log类和LogAfter类,实现相应的接口

    package aspect;
    
    import org.springframework.aop.MethodBeforeAdvice;
    import java.lang.reflect.Method;
    
    public class Log implements MethodBeforeAdvice {
        @Override
        public void before(Method method, Object[] objects, Object o) throws Throwable {
            System.out.println(o.getClass().getName()+"的"+method.getName()+"执行了");
        }
    }
    
    package aspect;
    
    import org.springframework.aop.AfterReturningAdvice;
    import java.lang.reflect.Method;
    
    public class LogAfter implements AfterReturningAdvice {
        @Override
        public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
            System.out.println("执行了"+o1.getClass().getName()+"的"+method.getName()+"结束了");
        }
    }
    

    修改xml

        <bean name="s" class="service.ProductService"></bean>
        <bean id="logBefore" class="aspect.Log"/>
        <bean id="logAfter" class="aspect.LogAfter"/>
        <aop:config>
            <aop:pointcut id="loggerCutPoint" expression="execution(* service.ProductService.*(..)) "/>
            <aop:advisor advice-ref="logBefore" pointcut-ref="loggerCutPoint"/>
            <aop:advisor advice-ref="logAfter" pointcut-ref="loggerCutPoint"/>
        </aop:config>
    
    

    解释一下

    和第一个方式不同的是,这里用了aop:advisor,这是通过Spring提供的API实现的。

    因为Log类和LogAfter类实现了MethodBeforeAdvice和AfterReturningAdvice方法,所以可以在核心代码执行前后进行输出。

    1581753813192

    自己实现Aspect

    上面这种方法,可能程序复杂以后就会出现记不住接口的情况
    记录下第三种方法

    做一个MyLog.java

    package aspect;
    
    public class MyLog {
        public void before(){
            System.out.println("-----before-----");
        }
        public void after(){
            System.out.println("-----after------");
        }
    }
    
    

    修改xml

        <bean name="s" class="service.ProductService"></bean>
        <bean id="myLogger" class="aspect.MyLog"/>
        <aop:config>
            <aop:pointcut id="loggerCutPoint" expression="execution(* service.ProductService.*(..)) "/>
            <aop:aspect id="logAspect" ref="myLogger">
                <aop:before method="before" pointcut-ref="loggerCutPoint"/>
                <aop:after method="after" pointcut-ref="loggerCutPoint"/>
            </aop:aspect>
        </aop:config>
    

    这里通过aop:before和aop:after分别置顶method来包围核心代码

    1581753956610

    推荐连接

    Spring AOP 教程

    浅析Spring AOP(一)——基本概念

    Spring(4)——面向切面编程(AOP模块)

  • 相关阅读:
    Atitit sql计划任务与查询优化器统计信息模块
    Atitit  数据库的事件机制触发器与定时任务attilax总结
    Atitit 图像处理知识点体系知识图谱 路线图attilax总结 v4 qcb.xlsx
    Atitit 图像处理 深刻理解梯度原理计算.v1 qc8
    Atiti 数据库系统原理 与数据库方面的书籍 attilax总结 v3 .docx
    Atitit Mysql查询优化器 存取类型 范围存取类型 索引存取类型 AND or的分析
    Atitit View事件分发机制
    Atitit 基于sql编程语言的oo面向对象大规模应用解决方案attilax总结
    Atitti 存储引擎支持的国内点与特性attilax总结
    Atitit 深入理解软件的本质 attilax总结 软件三原则"三次原则"是DRY原则和YAGNI原则的折
  • 原文地址:https://www.cnblogs.com/cpaulyz/p/12401703.html
Copyright © 2011-2022 走看看