15Spring AOP基础

为什么需要AOP?

先来看一段代码:

package com.cn.spring.aop.helloworld;
//加减乘除的接口类
public interface ArithmeticCalculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}
package com.cn.spring.aop.helloworld;

//实现类
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }
}

现在问题来了:

现在需要在程序执行期间追踪正在发生的活动?

代码如下:

package com.cn.spring.aop.helloworld;

//实现类
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        System.out.println("The method add begins with[" + i + "," + j + "]");
        int result = i + j;
        System.out.println("The method add ends with[" + i + "," + j + "]");
        return result;
    }

    @Override
    public int sub(int i, int j) {
        System.out.println("The method sub begins with[" + i + "," + j + "]");
        int result = i - j;
        System.out.println("The method sub ends with[" + i + "," + j + "]");
        return result;
    }

    @Override
    public int mul(int i, int j) {
        System.out.println("The method mul begins with[" + i + "," + j + "]");
        int result = i * j;
        System.out.println("The method mul ends with[" + i + "," + j + "]");
        return result;
    }

    @Override
    public int div(int i, int j) {
        System.out.println("The method div begins with[" + i + "," + j + "]");
        int result = i / j;
        System.out.println("The method div ends with[" + i + "," + j + "]");
        return result;
    }
}

如果还希望计算器的加减乘除只能处理整数的运算呢,又需要在ArithmeticCalculatorImpl 实现类中添加代码进行验证,每添加一个需求,都要去添加类似的代码。

使得代码冗余且维护性低。

那如何用AOP来解决呢?

AOP是使用代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理对象取代原始对象。任何对原始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原始对象上。

 

 先来看下代理是如何来实现的:

package com.cn.spring.aop.helloworld;
//加减乘除的接口类
public interface ArithmeticCalculator {
    int add(int i, int j);
    int sub(int i, int j);
    int mul(int i, int j);
    int div(int i, int j);
}
package com.cn.spring.aop.helloworld;

//实现类
public class ArithmeticCalculatorImpl implements ArithmeticCalculator {
    @Override
    public int add(int i, int j) {
        int result = i + j;
        return result;
    }

    @Override
    public int sub(int i, int j) {
        int result = i - j;
        return result;
    }

    @Override
    public int mul(int i, int j) {
        int result = i * j;
        return result;
    }

    @Override
    public int div(int i, int j) {
        int result = i / j;
        return result;
    }
}
package com.cn.spring.aop.helloworld;

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

public class ArithmeticCalculatorLoggingProxy {
    //要代理的对象
    private ArithmeticCalculator target;

    public ArithmeticCalculatorLoggingProxy(ArithmeticCalculator target) {
        this.target = target;
    }

    public ArithmeticCalculator getLoggingProxy() {
        ArithmeticCalculator proxy = null;

        //代理对象由哪一个类加载器负责加载
        ClassLoader loader = target.getClass().getClassLoader();
        //代理对象的类型,即其中有哪些方法
        Class[] interfaces = new Class[]{ArithmeticCalculator.class};

        InvocationHandler handler = new InvocationHandler() {
            /**
             *
             * @param proxy 正在返回的那个代理对象,一般情况下,在invoke方法中都不使用该对象
             * @param method 正在被调用的方法
             * @param args 调用方法时,传入的参数
             * @return
             * @throws Throwable
             */
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                String methodName = method.getName();
                System.out.println("The methed " + methodName + "begins with " + Arrays.asList(args));
                Object result = method.invoke(target, args);
                System.out.println("The methed " + methodName + "end with " + Arrays.asList(args));
                return result;
            }
        };
        proxy = (ArithmeticCalculator) Proxy.newProxyInstance(loader, interfaces, handler);
        return proxy;
    }
}
package com.cn.spring.aop.helloworld;

/**
 * Created by jecyhw on 2015/6/20.
 */
public class Main {
    public static void main(String[] args)  {
        ArithmeticCalculator target = new ArithmeticCalculatorImpl();
        ArithmeticCalculator proxy = new ArithmeticCalculatorLoggingProxy(target).getLoggingProxy();

        int result = proxy.add(1, 2);
        System.out.println("-->" + result);

        result = proxy.sub(1, 2);
        System.out.println("-->" + result);

        result = proxy.mul(1, 2);
        System.out.println("-->" + result);

        result = proxy.div(1, 2);
        System.out.println("-->" + result);
    }
}

Spring AOP基础:

  • AOP(Aspect-Oriented Programming 面向切面编程)是一种新的方法论,是对传统OOP(Object-Oriented Programming 面向对象编程)的补充
  • AOP的主要编程对象是切面(aspect),而切面模块化横切关注点
  • 在应用AOP编程时,仍然需要定义公共功能,但可以明确的定义这个功能在哪里,以什么方式应用,并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里。
  • AOP的好处:每个事物逻辑位于一个位置,代码不分散,便于维护和升级;业务模块更简洁,只包含核心业务代码。

  • 切面(Aspect):横切关注点(跨越应用程序多个模块的功能)被模块化的特殊对象
  • 通知(Advice):切面必须要完成的工作
  • 目标(Target):被通知的对象
  • 代理(Proxy):向目标对象应用通知之后创建的对象
  • 连接点(Joinpoint):程序执行的某个特定位置:如类某个方法调用前、调用后、方法抛出异常后等,连接点由两个信息确定:方法表示的程序执行点;相对点表示的方位,例如ArithmeticCalculator#add()方法执行前的连接点,执行点为 ArithmeticCalculator#add();方法为该方法执行前的位置
  • 切点(pointcut):每个类都拥有多个连接点:例如ArithmeticCalculator的所有方法实际上都是连接点,即连接点是程序类中客观存在的事物。AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。

posted on 2015-06-20 12:53  jec  阅读(162)  评论(0编辑  收藏  举报

导航