AOP(Aspect Oriented Programing)就是预编译方式或者是软件运行期期间通过动态代理实现功能扩展而不修改源代码的的技术。实现一种通用的逻辑解耦,解决一些系统层面的问题,如日志,事务,权限等,从而实现高可用的可重用性和可维护性AOP的设计原理和思想。

面向切面编程,就是将交叉业务逻辑封装成切面,利用 AOP 容器的功能将切面植入到主业务逻辑中。所谓的“交叉业务”,就是指通用的、与主业务逻辑无关的代码。例如:日志信息、安全检查、事务、缓存、设置字符编码、发短信 等。

若不使用 AOP 。则会出现代码纠缠不清。不重要的业务功能和重要的业务功能代码混杂在一起,使得整个程序的结构混乱不清。

例如,转账功能。在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑。而这些业务逻辑和主要的业务逻辑之间并没有直接的关系。但是他们的代码量能达到总代码量的一半甚至更多! 他们的存在,不仅产生了大量“冗余”的代码,还大大干扰了主业务逻辑的结构——转账。

(来源于掘金用户励志买套华侨城苏荷湾大平层)

简单描述下就是 不修改源代码,在主干功能里添加新的功能。

AOP 术语

连接点(JoinPoint):所谓连接点是指那些被拦截到的点。在Spring中,这些点指的是方法,因为spring只支持方法类型的连接点。(通俗理解:业务层接口的所有方法都叫连接点)

切入点(Pointcut):所谓切入点是指我们要对哪些连接点进行拦截的定义。 (通俗理解:被增强的业务层接口的方法叫切入点)连接点不一定是切入点,但切入点一定是连接点。
在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法。
注意: 被标记为 final 的方法是不能作为连接点与切入点的,因为 final 是不能被修改、不能被增强的。

通知(Advice):所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。
通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
(通知的查找方法:找到invoke方法中明确调用业务层那行代码,在其之前执行的就是前置通知,在其之后执行的就是后置通知,在catch中的就是异常通知,在finally中的就是最终通知。整个的invoke方法执行就是环绕通知。)

通知类:通知方法所在的类叫做通知类。

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

目标对象(Target):代理的目标对象。(被代理的对象)

切面(Aspect):切面是切入点和通知(引介)的结合。 (通俗理解:建立切入点方法和通知方法在执行调用的对应关系就是切面)

AOP(底层原理)

实际上就是代理机制。

  • JDK动态代理机制:有接口情况 ,使用JDK动态代理创建接口实现类代理对象,增强类的方法。
  • 在没有接口情况,使用CGLIB动态代理创建子类的代理对象,增强类的方法。

JDK动态代理:

使用JDK动态代理,使用Proxy类里面的方法创建代理对象。

调用newProxyInstance方法

   public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler a)
        throws IllegalArgumentException


newProxyInstance,方法有三个参数:

loader: 用哪个类加载器去加载代理对象

interfaces:动态代理类需要实现的接口

a:动态代理方法在执行时,会调用a里面的invoke方法去执行

编写JDK动态代理代码

//创建接口,定义方法
public interface UserDao {
    public int add(int a,int b);
    public String update(String id);
}

创建接口实现类,实现方法

public class UserDaoImpl implements UserDao{
    @Override
    public int add(int a, int b) {
        return a+b;
    }

    @Override
    public String update(String id) {
return id;
    }
}

使用Proxy类创建接口代理对象

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;

public class JDKProxy {
    public static void main(String[] args) {
        //创建接口实现类代理方法
        Class[] interfaces={UserDao.class};
        UserDaoImpl userDao=new UserDaoImpl();
        UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
        int result= dao.add(1,2);
        System.out.println(result);
    }
}
//创建代理对象代码
class  UserDaoProxy implements InvocationHandler{
    //1 把创建的是谁的代理对象,把谁传递进来
    //有参构造传递
    private Object obj;
    public UserDaoProxy(Object obj){
        this.obj=obj;
    }
    //增强的逻辑
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
       //方法之前
        System.out.println("方法之前执行..."+method.getName()+":传递的参数..."+ Arrays.toString(args));
        //被增强的方法执行
        Object res = method.invoke(obj, args);
        //方法之后
        System.out.println("方法之后执行.."+obj);
        return res;
    }
}

发表回复

您的电子邮箱地址不会被公开。