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模块)

  • 相关阅读:
    突然地心血来潮,为 MaixPy( k210 micropython ) 添加看门狗(WDT) C 模块的开发过程记录,给后来的人做开发参考。
    Vular开发手记#1:设计并实现一个拼插式应用程序框架
    VUE实现Studio管理后台(完结):标签式输入、名值对输入、对话框(modal dialog)
    VUE实现Studio管理后台(十三):按钮点选输入控件,input输入框系列
    VUE实现Studio管理后台(十二):添加输入组合,复杂输入,输入框Input系列
    VUE实现Studio管理后台(十一):下拉选择列表(Select)控件,输入框input系列
    VUE实现Studio管理后台(十):OptionBox,一个综合属性输入界面,可以级联重置
    VUE实现Studio管理后台(九):开关(Switch)控件,输入框input系列
    VUE实现Studio管理后台(八):用右键菜单contextmenu,编辑树形结构
    VUE实现Studio管理后台(七):树形结构,文件树,节点树共用一套代码NodeTree
  • 原文地址:https://www.cnblogs.com/cpaulyz/p/12401703.html
Copyright © 2011-2022 走看看