Spring学习笔记[4]之AOP[面向切面编程

本文介绍了面向切面编程(AOP)的概念及其如何通过代理模式实现业务逻辑的解耦。详细探讨了Spring框架中AOP的两种代理实现:基于JDK的动态代理和基于CGLIB的动态代理。并通过示例代码展示了这两种代理的具体应用。

AOP概述

  • AOP:Aspect Oriented Programming 面向切面编程,是OOP(面向对象编程)的延续,利用AOP可以对业务逻辑的各个部分进行隔离,从而使业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。
  • AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视,事务管理,安全检查,缓存)

AOP 底层实现

代理模式

Spring框架的AOP技术底层是采用的代理模式,代理方式提供了两种

  • 基于JDK的动态代理:必须是面向接口的,只有实现了具体接口的类才能生成代理对象

    JDK的动态代理主要涉及java.lang.reflect中的ProxyInvocationHandler两个类。

    InvocationHandler是个接口,可以通过实现该接口定义横切逻辑,并通过反射机制调用目标类的代码,动态地将横切逻辑和业务逻辑编制在一起。

  • 基于CGLIB动态代理:对于没有实现了接口的类,采用底层的字节码技术,可以为一个类创建子类,在子类中采用方法拦截的技术拦截所有父类方法的调用并顺势织入横切逻辑。

JDK动态代理

//使用Proxy类生成对象
public class MyProxyUtils {
    public static UserDao getProxy(final UserDao dao) {
        // 1:类加载器   2:传入的类实现的接口     3:匿名内部类
        UserDao proxyUser = (UserDao) Proxy.newProxyInstance(dao.getClass().getClassLoader(), dao.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if(method.getName().equals("save"))
                    System.out.println("记录日志...");
                return method.invoke(dao,args);
            }
        });
        //返回代理对象
        return proxyUser;
    }
}
/******************* Test ********************************/
public class test{
    @Test
    public void run(){
        UserDao userDao=new UserDaoIMpl();
        //工具类获取代理对象
        UserDao proxy=MyProxyUtils.getProxy(userDao);
        //调用代理对象方法
        ....
    }
}

CGLib 动态代理

public class MyCgilbUtils {
    public static BookDaoImpl getProxy(){
        Enhancer enhancer=new Enhancer();
        //设置父类
        enhancer.setSuperclass(BookDaoImpl.class);

        //设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            //代理方法对象的执行,回调函数就会执行
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                //正常执行
                if(method.getName().equals("save"))
                    System.out.println("记录日志...");
                return methodProxy.invokeSuper(o,objects);
            }
        });
        //生成代理对象
        BookDaoImpl proxy=(BookDaoImpl) enhancer.create();
        return proxy;
    }
}
/******************* Test ********************************/
public class test{
    @Test
    public void run(){
        //生成代理对象
        BookDaoImpl proxy=MyCgilbUtils.getProxy();
        //调用代理对象方法
        ....
    }
}

用户可以通过getProxy()方法为一个类创建动态代理对象。

public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy)CGLib定义的Intercptor接口方法,它拦截所有目标类方法的调用,其中Object 表示目标实例,Method为目标类方法的反射对象,objects为方法的动态入参,MethodProxy 为代理实例。

总结

CGLib所创建的动态代理对象的性能依旧比JDK所创建的动态代理对象的性能高大约10倍,当时CGLib在创建代理对象的时所花费的时间却比JDK动态代理多大概8倍。对于singleton的代理对象或者具有实例池的代理,因为无须频繁得创建代理对象,所以比较适合采用CGLib动态代理技术,反正则适合采用JDK动态代理技术。

AOP相关术语

public class UserDaoImpl {
    public void save(){}
    public void update(){}
    public void delete(){}
}
  • Joinpoint 连接点:所谓连接点是指那些被拦截到的点

    UserDaoImpl中所有的方法都可以成为连接点 saveupdatedelete

  • Pointcut 切入点:所谓切入点就是我们要对哪些Joinpoint进行拦截的定义

    拦截哪个方法(对哪个方法做增强) saveupdate

  • Advice 通知/增强:所谓通知是指拦截到Joinpoint之后要做的事情

    例如要增加一个记录日志的log()方法

  • Introduction(引介):是一种特殊的通知,在不修改代码的前提下,Introduction可以在运行期为类动态地添加一些方法或者Field

  • Target 目标对象:代理的目标对象,例如,UserDaoImpl

  • Weaving 织入:把通知添加到目标对象,生成代理对象的过程

    Spring采用动态代理织入,AspcetJ采用编译期织入和类装载期织入

  • Proxy 代理:生成的代理对象

  • Aspect 切面:切入点+通知=切面,通知需要自己编写,切入点需要配置

AOP:通知

定义:切面也需要完成工作,在AOP术语中,切面的工作被称为通知

工作内容:通知定义了切面是什么以及何时使用,除了描述切面要完成的工作,通知还解决合适执行这个工作

通知类型

  • 前置通知:在目标方法执行之前执行
  • 后置通知:在目标方法执行之后执行
  • 环绕通知:在目标方法执行前和执行后执行
  • 异常抛出通知:在目标方法执行出现异常的时候执行
  • 最终通知:无论目标方法是否出现异常,最终通知都会执行

AOP:切入点表达式

execution( [方法访问修饰符] 方法返回值 包名.类名.方法名(方法的参数) )

完整写法execution(public void gongfukangee.Demo03.CustomerDaoImpl.save())

省略写法execution(* *..*.*DaoImpl.*save(..))

  • execution() 固定的
  • public 可以省略不写
  • 返回值 可以使用通配符* ,表示任意的返回值,返回值类型不能不写
  • 包名 可以使用 *替代 简写*..*
  • *DaoImpl 所有以DaoImpl结尾的类
  • saev*() 所有以save开头的方法
  • 方法参数:(..)
  • * *..*.*DaoImpl.save*(..)

 

下一篇:Spring学习笔记[5]之AOP入门程序  https://blog.youkuaiyun.com/Rabbit_Judy/article/details/81842600

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值