SpringAOP原理+使用

什么是SpringAOP?

        软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。

什么叫面向切面?初学者不太懂!下面举个例子就明白了

我们一般登录的时候,一般会记录一下作为登录日志。按照正常的逻辑,我们可以这么做。

SpringAOP原理+使用_第1张图片

 这有个问题就是,有多少接口,就要多少次代码copy。对于一个“懒人”,这是不可容忍的。好,提出一个公共方法,每个接口都来调用这个接口。这里有点切面的味道了。

SpringAOP原理+使用_第2张图片

 同样有个问题,我虽然不用每次都copy代码了,但是,每个接口总得要调用这个方法吧。于是就有了切面的概念,我将方法注入到接口调用的某个地方(切点)。

SpringAOP原理+使用_第3张图片

 这样接口只需要关心具体的业务,而不需要关注其他非该接口关注的逻辑或处理。

以后只要有需要记录日志的地方直接注入就行了,避免了重复造轮子。

红框处,就是面向切面编程。

应用场景

  • 日志记录 & 日志框架
    • 入参打印
      • 用户、时间、那个方法、传了那些参数
    • 出参打印
      • 用户、时间、那个方法、返回那些内容
  • 权限验证、登陆验证
  • 全局异常处理
  • 浏览记录
  • Excel导入

实现原理:动态代理(这里主要将JDK动态代理和cglib动态代理)

JDK动态代理=> 必须实现接口

  • 目标对象实现接口
  • 核心代理类实现InvocationHandler接口,覆写invoke
  • 生成代理对象
IAdvertisement advertisement = (IAdvertisement) Proxy.newProxyInstance(
        jiaLing.getClass().getClassLoader()
        , jiaLing.getClass().getInterfaces()
        ,advertisementHandler
);

代码实现

被代理类

public class Target implements TargetInteface {
    @Override
    public void method1() {
        System.out.println("method1 running ...");
    }

    @Override
    public void method2() {
        System.out.println("method2 running ...");
    }

    @Override
    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

实现接口

public interface TargetInteface {
    void method1();
    void method2();
    int method3(Integer i);
}

增强方法

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

public class TargetProxy {
    public static   Object getTarget(T t) {
        //新构建了新的代理类对象
        return Proxy.newProxyInstance(t.getClass().getClassLoader(), t.getClass().getInterfaces(), new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // proxy就是目标对象t,method就是调用目标对象中方法,args就是调用目标对象中方法的参数。
                        //比如说:代理对象.method1(),这时proxy就是目标类,method1就是method,args就是method1方法参数。
                        System.out.println("执行方法前...");
                        Object invoke = method.invoke(t, args);
                        System.out.println("执行方法后...");
                        return invoke;
            }
        });
    }
}

测试类

public class TargetUser {

    public static void main(String[] args) {
        TargetInteface target = (TargetInteface) TargetProxy.getTarget(new Target());
        target.method1();
        System.out.println("-----------------------------");
        target.method2();
        System.out.println("-----------------------------");
        System.out.println(target.method3(3));
    }

}

cglib动态代理=> 不用实现接口

  • cglib动态代理会自己创建

被代理类

public class Target {
    public void method1() {
        System.out.println("method1 running ...");
}

    public void method2() {
        System.out.println("method2 running ...");
    }

    public int method3(Integer i) {
        System.out.println("method3 running ...");
        return i;
    }
}

增强方法

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;

public class TargetProxy {

    public static  Object getProxy(T t) {
        Enhancer en = new Enhancer(); //帮我们生成代理对象
        en.setSuperclass(t.getClass());//设置要代理的目标类
        en.setCallback(new MethodInterceptor() {//代理要做什么
            @Override
            public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
                System.out.println("执行方法前。。。");
                //调用原有方法  
                Object invoke = methodProxy.invokeSuper(object, args);
                // Object invoke = method.invoke(t, args);// 作用等同与上面。
                System.out.println("执行方法后。。。");
                return invoke;
            }
        });
        return en.create();
    }
}

测试类

public class TargetUser {

    public static void main(String[] args) {
        Target target = (Target) TargetProxy.getProxy(new Target());
        System.out.println(target.getClass().getName());
        target.method1();
    }

}

你可能感兴趣的:(SpringAop,面向切面编程,java,后端)