对Spring AOP的理解

AOP

  • AOP是什么?
  • AOP的相关名词
    • 切面
    • 切入点
    • 通知
    • 切面
    • 目标
    • 代理
  • StringAOP的实现
  • 代理
    • jdk代理
      • JDK代理的优缺点
    • cglib代理

AOP是什么?

    AOP是Spring两大特性之一,他的意思为面向切面编程。使用AOP可以抽取一些公共模块出来,减少公共模块和业务代码的耦合。利用 AOP 可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各 部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 AOP、OOP 在字面上虽然非常类似,但却是面向不同领域的两种设计思想。OOP (面向对象编程)针对业务处理过程的实体及其属性和行为进行抽象封装,以获 得更加清晰高效的逻辑单元划分。
对Spring AOP的理解_第1张图片

AOP的相关名词

切面

类中可以被增强的方法,这个方法就被称为连接点

切入点

类中有很多方法可以被增强,但实际中只有 add 和 update被增了,那么 add 和 update 方法就被称为切入点(实际实现的连接点)

通知

通知是指一个切面在特定的连接点要做的事情(增强的功能)。通知分为方法执行前通知,方法执行后通知,环绕通知、异常通知和返回通知等.

切面

把通知添加到切入点的过程叫切面.

目标

代理的目标对象(要增强的类)

代理

向目标对象应用通知之后创建的代理对象

StringAOP的实现

具体实现方式翻阅之前写的博客
AOP和事务管理

代理

    SpringAOP是通过代理来实现面向切面编程的,它使用的代理有两种,JDK代理和CGlib代理。当我们的bean对象实现了某一接口后,Spring默认将采用Jdk动态代理,当我们的bean对象没有实现接口时,默认将采用CGLIB代理,Spring也支持我们在bean对象实现了接口时也强制的使用CGLIB代理。

jdk代理

    JDK动态代理基于拦截器和反射来实现。代理类必须要实现InvocationHandler接口,重写invoke()方法。

代码实现:

接口类:UserDao

//抽象用户操作定义
public interface UserDao {
    void saveUser();
}

两个实现类,普通用户实现UserDaoImpl和VIP用户实现VipUserDaoImpl

public class UserDaoImpl implements UserDao{

    @Override
    public void saveUser() {
        System.out.println("普通用户实现");
        //增加新功能要在每个实现类里面写
        //saveLog()
    }
}

public class VipUserDaoImpl implements UserDao{
    @Override
    public void saveUser() {
        System.out.println("VIP用户实现");
        //增加新功能要在每个实现类里面写
        //saveLog()
    }
}

动态代理类Dtproxy

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

//实现java.lang包下的reflect类的InvocationHandler接口
public class Dtproxy implements InvocationHandler {

    Object object;//真实对象
    public Dtproxy(Object object){
        this.object = object;
    }

    /*
      invoke() 反射
      Method method 动态获取的真正的要执行的saveUser()方法,用反射的机制获取到
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("之前开始事务");
        method.invoke(object);
        System.out.println("之后提交事务");
        return proxy;
    }
    /**
     * 动态代理类
     *    代理类不需要实现与目标类相同的接口,这样就可以代理任意的目标类
     *    但是有要求,目标类必须实现接口,此种方式是动态代理的实现方式之一,成为JDK代理。
     *    jdk代理:是一种纯反射机制实现的(动态获取目标接口的方法)
     */
}

测试类Test

public class Test {
    public static void main(String[] args) {
        VipUserDaoImpl vipUserDao = new VipUserDaoImpl();
        InvocationHandler dtproxy = new Dtproxy(vipUserDao);

        //创建代理对象
        UserDao userDao = (UserDao)Proxy.newProxyInstance(Dtproxy.class.getClassLoader(),VipUserDaoImpl.class.getInterfaces(),dtproxy);
        userDao.saveUser();
    }
}

JDK代理的优缺点

    JDK代理是通过反射来实现,JDK通过反射,生成一个代理类,这个代理类实现了原来那个类的所有接口,并对接口定义的方法进行代理。当我们通过代理对象执行原来那个类的方法时,代理类底层会通过反射机制,回调我们实现的InvocationHandler接口的invoke方法。
优点:

  1. JDK动态代理是JDK原生的,不需要任何依赖即可使用;
  2. 通过反射机制生成代理类的速度要比CGLib操作字节码生成代理类的速度更快;

缺点:

  1. 如果要使用JDK动态代理,被代理的类必须实现了接口,否则无法代理;
  2. JDK代理必须要有实现类实现目标接口。
  3. JDK动态代理执行代理方法时,需要通过反射机制进行回调,此时方法执行的效率比较低;

cglib代理

CGLIB实现动态代理的原理是:底层采用ASM字节码生成框架,直接对需要代理的类的字节码进行操作,生成这个类的一个子类,并且重写类的所有方法。
优点:

  1. 使用CGLib代理的类,不需要实现接口,因为CGLib生成的代理类是直接继承自需要被代理的类;
  2. CGLib生成的代理类是原来那个类的子类,这就意味着这个代理类可以为原来那个类中,所有能够被子类重写的方法进行代理;
  3. CGLib生成的代理类,和我们自己编写并编译的类没有太大区别,对方法的调用和直接调用普通类的方式一致,所以CGLib执行代理方法的效率要高于JDK的动态代理;

缺点

  1. 由于CGLib的代理类使用的是继承,这也就意味着如果需要被代理的类是一个final类,则无法使用CGLib代理
  2. 由于CGLib实现代理方法的方式是重写父类的方法,所以无法对final方法,或者private方法进行代理,因为子类无法重写这些方法;
  3. CGLib生成代理类的方式是通过操作字节码,这种方式生成代理类的速度要比JDK通过反射生成代理类的速度更慢;

你可能感兴趣的:(Spring框架,JavaSE基础,spring,代理模式,java,AOP)