框架之Spring的AOP

作者: vaneL | 来源:发表于2017-08-01 10:18 被阅读0次

首先在学习AOP之前,先了解一下动态代理。

动态代理指的是通过一个代理对象来创建需要的业务对象,然后在这个代理对象中统一进行各种需求的处理

1.写一个类实现相应的InvocationHandler接口,以后创建对象就完全通过这个代理类来进行创建
2.创建要代理的对象
代理模式的详解

public class LogProxy implements InvocationHandler {
       //2、创建一个代理对象
       private Object target;
       private LogProxy( ){   }
       //3、创建一个方法来生成对象
       //创建一个静态的newInstance方法来创建代理对象
    public static Object getInstance(Object o) {
        //3.1、创建LogProxy对象
        LogProxy proxy = new LogProxy();
        //3.2、设置这个代理对象
        proxy.target = o;
        //3.3、通过Proxy的方法创建代理对象
        //第一个参数是要代理对象的classLoader
        //第二个参数是要代理对象实现的所有接口
        //第三个参数是实现类InvocationHandler的对象
        //此时的result就是一个代理对象,代理的是o    【result代理o】
        Object result = Proxy.newProxyInstance(o.getClass().getClassLoader(), 
                                               o.getClass().getInterfaces(), 
                                               proxy);
        return result;
    }

     /**
     * 当有了代理对象之后,不管这个代理对象执行什么方法,都会调用以下的invoke方法
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//      if(method.getName().equals("add")||method.getName().equals("delete")) {
//          Logger.info("进行了相应的操作");
//      }
        Object obj = method.invoke(target, args);
        if(method.isAnnotationPresent(LogInfo.class)) {
            LogInfo li = method.getAnnotation(LogInfo.class);
            Logger.info(li.value());
        }
        return obj;
    }
AOP.jpg
基于XML配置的Spring AOP:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
        
        <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
        <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
        <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
        <bean id="logHandler" class="com.xrq.aop.LogHandler" />
        
        <aop:config>
            <aop:aspect id="time" ref="timeHandler" order="1">
                <aop:pointcut id="addTime" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addTime" />
                <aop:after method="printTime" pointcut-ref="addTime" />
            </aop:aspect>
            <aop:aspect id="log" ref="logHandler" order="2">
                <aop:pointcut id="printLog" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="LogBefore" pointcut-ref="printLog" />
                <aop:after method="LogAfter" pointcut-ref="printLog" />
            </aop:aspect>
        </aop:config>
</beans>
使用注解配置AOP:
@Service("math")
public class Math{
    //加
    public int add(int n1,int n2){
        int result=n1+n2;
        System.out.println(n1+"+"+n2+"="+result);
        return result;
    }
    
    //减
    public int sub(int n1,int n2){
        int result=n1-n2;
        System.out.println(n1+"-"+n2+"="+result);
        return result;
    }
}
/**
 * @Component表示该类的实例会被Spring IOC容器管理;
 * @Aspect表示声明一个切面;
 * @Before表示before为前置通知,通过参数execution声明一个切点
**/

@Component
@Aspect
public class Advices {
    @Before("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
    public void before(JoinPoint jp){
        System.out.println("----------前置通知----------");
        System.out.println(jp.getSignature().getName());
    }
    
    @After("execution(* com.zhangguo.Spring052.aop02.Math.*(..))")
    public void after(JoinPoint jp){
        System.out.println("----------最终通知----------");
    }
}  // 在xml中配置为<aop:aspectj-autoproxy proxy-target-class="true">
AspectJ切点函数:

@AspectJ使用AspectJ专门的切点表达式描述切面。

AspectJ表达式可分为四类:

  • 方法切点函数:通过描述目标类方法信息定义连接点。
  • 方法参数切点函数:通过描述目标类方法入参信息定义连接点。
  • 目标类切点函数:通过描述目标类类型信息定义连接点。
  • 代理类切点函数:通过描述代理类信息定义连接点。

常见的AspectJ表达式函数:
execution():满足匹配模式字符串的所有目标类方法的连接点
@annotation():任何标注了指定注解的目标方法链接点
args():目标类方法运行时参数的类型指定连接点
@args():目标类方法参数中是否有指定特定注解的连接点
within():匹配指定的包的所有连接点
target():匹配指定目标类的所有方法
@within():匹配目标对象拥有指定注解的类的所有方法
@target():匹配当前目标对象类型的执行方法,其中目标对象持有指定的注解
this():匹配当前AOP代理对象类型的所有执行方法
最常用的是:execution(<修饰符模式>?<返回类型模式><方法名模式>(<参数模式>)<异常模式>?)切点函数,可以满足多数需求。

AspectJ通知注解:
/**
 * 通知类,横切逻辑
 */
@Component
@Aspect
public class Advices {
    //切点
    @Pointcut("execution(* com.zhangguo.Spring052.aop04.Math.a*(..))")
    public void pointcut(){
    }
    
    //前置通知
    @Before("pointcut()")
    public void before(JoinPoint jp){
        System.out.println(jp.getSignature().getName());
        System.out.println("----------前置通知----------");
    }
    
    //最终通知
    @After("pointcut()")
    public void after(JoinPoint jp){
        System.out.println("----------最终通知----------");
    }
    
    //环绕通知
    @Around("execution(* com.zhangguo.Spring052.aop04.Math.s*(..))")
    public Object around(ProceedingJoinPoint pjp) throws Throwable{
        System.out.println(pjp.getSignature().getName());
        System.out.println("----------环绕前置----------");
        Object result=pjp.proceed();
        System.out.println("----------环绕后置----------");
        return result;
    }
    
    //返回结果通知
    @AfterReturning(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.m*(..))",returning="result")
    public void afterReturning(JoinPoint jp,Object result){
        System.out.println(jp.getSignature().getName());
        System.out.println("结果是:"+result);
        System.out.println("----------返回结果----------");
    }
    
    //异常后通知
    @AfterThrowing(pointcut="execution(* com.zhangguo.Spring052.aop04.Math.d*(..))",throwing="exp")
    public void afterThrowing(JoinPoint jp,Exception exp){
        System.out.println(jp.getSignature().getName());
        System.out.println("异常消息:"+exp.getMessage());
        System.out.println("----------异常通知----------");
    }
}

结果
add
----------前置通知----------
100+0=100
----------最终通知----------
sub
----------环绕前置----------
100-0=100
----------环绕后置----------
100*0=0
mut
结果是:0
----------返回结果----------
div
异常消息:/by zero
----------异常通知----------

相关文章

  • Spring学习(二)

    spring框架核心技术的两大概念之AOP: AOP(Aspect Oriented Programming)...

  • 6.Spring 框架的 AOP

    1.Spring 框架的 AOP Spring 框架的 AOP Spring 框架的一个关键组件是面向方面的编程(...

  • 面试:spring

    Spring 的核心 Spring 框架主要负责技术整合,该框架提供 IOC 和 AOP 机制,可以降低系统组件之...

  • Spring_13_Spring框架的AOP

    Spring 框架的 AOP Spring框架的一个关键组件是面向切面编程(AOP)框架,面向切面的编程需要把程序...

  • Spring AOP介绍(一)之 Spring AOP 基础介绍

    Spring AOP介绍(一)之 Spring AOP 基础介绍 AOP是什么? AOP(Aspect Orien...

  • 2019-06-11

    四、Spring的AOP AOP实现可分为两类(按AOP框架修改源代码的时机): 静态AOP实现:AOP框架在编译...

  • Spring的AOP

    、Spring的AOP AOP实现可分为两类(按AOP框架修改源代码的时机): 静态AOP实现:AOP框架在编译阶...

  • Spring AOP 机制解读

    Spring AOP 机制源码解读 导读 AOP是Spring框架面向切面的编程思想,AOP采用一种称为“横切”的...

  • springAOP的使用方法

    Aspect Oriented programming with spring 在spring框架中实现AOP常用...

  • Spring AOP实战和源码解析

    Spring AOP简介 说起Spring框架,我们最先想到的就是IOC和AOP了,如果说IOC是Spring的核...

网友评论

    本文标题:框架之Spring的AOP

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