AOP 概述

什么是 AOP

AOP: 全称是 Aspect Oriented Programming 即: 面向切面编程。


简单的说它就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。

AOP 的作用及优势

作用:在程序运行期间,不修改源码对已有方法进行增强。

优势:

  • 减少重复代码
  • 提高开发效率
  • 维护方便

动态代理回顾

动态代理的特点

  • 字节码随用随创建,随用随加载。
  • 它与静态代理的区别也在于此。因为静态代理是字节码一上来就创建好,并完成加载。
  • 装饰者模式就是静态代理的一种体现。

动态代理常用的有两种方式

基于接口的动态代理
提供者: JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。

基于子类的动态代理
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。

使用 JDK 官方的 Proxy 类创建代理对象

此处我们使用的是一个演员的例子:
在很久以前,演员和剧组都是直接见面联系的。没有中间人环节。
而随着时间的推移,产生了一个新兴职业:经纪人(中间人),这个时候剧组再想找演员就需要通过经纪人来找了。下面我们就用代码演示出来。

/** * 一个经纪公司的要求: * 能做基本的表演和危险的表演 */
    public interface IActor {
        /** * 基本演出 * @param money */
        public void basicAct(float money);
        /** * 危险演出 * @param money */
        public void dangerAct(float money);
    }
    /** * 一个演员 */
    //实现了接口,就表示具有接口中的方法实现。即:符合经纪公司的要求
    public class Actor implements IActor{
        public void basicAct(float money){
            System.out.println("拿到钱,开始基本的表演: "+money);
        }
        public void dangerAct(float money){
            System.out.println("拿到钱,开始危险的表演: "+money);
        }
    }
    public class Client {
        public static void main(String[] args) {
            //一个剧组找演员: 
            final Actor actor = new Actor();//直接
            /** * 代理: * 间接。 * 获取代理对象: * 要求: * 被代理类最少实现一个接口 * 创建的方式 * Proxy.newProxyInstance(三个参数) * 参数含义: * ClassLoader:和被代理对象使用相同的类加载器。 * Interfaces:和被代理对象具有相同的行为。实现相同的接口。 * InvocationHandler:如何代理。 * 策略模式:使用场景是: * 数据有了,目的明确。 * 如何达成目标,就是策略。 * */
            IActor proxyActor = (IActor) Proxy.newProxyInstance(
                    actor.getClass().getClassLoader(),
                    actor.getClass().getInterfaces(),
                    new InvocationHandler() {
                        /** * 执行被代理对象的任何方法,都会经过该方法。 * 此方法有拦截的功能。 * * 参数: * proxy:代理对象的引用。不一定每次都用得到 * method:当前执行的方法对象 * args:执行方法所需的参数 * 返回值: * 当前执行方法的返回值 */
                        @Override
                        public Object invoke(Object proxy, Method method, Object[] args)
                                throws Throwable {
                            String name = method.getName();
                            Float money = (Float) args[0];
                            Object rtValue = null;
                                //每个经纪公司对不同演出收费不一样,此处开始判断
                                if("basicAct".equals(name)){
                                  //基本演出,没有 2000 不演
                                if(money > 2000){
                                    //看上去剧组是给了 8000,实际到演员手里只有 4000
                                    //这就是我们没有修改原来 basicAct 方法源码,对方法进行了增强
                                    rtValue = method.invoke(actor, money/2);
                                }
                            }
                            if("dangerAct".equals(name)){
                                //危险演出,没有 5000 不演 
                                if(money > 5000){
                                    //看上去剧组是给了 50000,实际到演员手里只有 25000
                                    //这就是我们没有修改原来 dangerAct 方法源码,对方法进行了增强
                                    rtValue = method.invoke(actor, money/2);
                                }
                            }
                            return rtValue;
                        }
                    });
            //没有经纪公司的时候,直接找演员。
            // actor.basicAct(1000f);
            // actor.dangerAct(5000f);
            //剧组无法直接联系演员,而是由经纪公司找的演员
            proxyActor.basicAct(8000f);
            proxyActor.dangerAct(50000f);
        }
    }