首页 > 代码库 > AOP

AOP

1 . AOP的概念
AOP(Aspect Oriented Programming),即面向切面编程,它是对OOP(Object Oriented Programming)的补充和完善.OOP引入封装、继承和多态等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。

2 . AOP相关的技术术语

  • Join point :连接点,程序执行的某个位置,例如类初始化前,类的方法抛出异常后等。spring仅支持方法的连接点。
  • Pointcut :切点,指定一个通知将被引发的一系列连接点的集合。类比数据库的查询来说,连接点相当与数据库中的记录,切点就相当月查询条件。
  • Advice :通知,也叫增强,切面在某个连接点执行的操作(sprig中提供了五种通知:前置通知,后置通知,环绕通知,异常通知,引入通知 );
  • Aspect :切面,切入系统的一个切面。比如事务管理是一个切面,权限管理也是一个切面;
  • Target : 目标对象,增强逻辑的目标织入类
  • Introduction : 引入,添加方法或字段到被增强的类。 Spring允许引入新的接口到任何被增强的对象。
  • Weaving :织入,将增强添加到目标类具体连接点上。根据不同的实现技术,AOP有三种织入方式:

     (1) 编译期织入,需特别的java编译器
     (2) 类装载期织入,需特别的的ClassLoader
     (3) 动态代理织入,在运行期为目标类添加增加生成子类的方式

3 . Sping AOP的原理:

  • Sping AOP的底层是通过JDK动态代理和CGLib动态代理技术为目标对象织入横切逻辑。
    (1) JDK动态代理:目标类必须实现接口,代理类通过实现InvocationHandler接口完成对目标类的逻辑增强。
    (2)CGLib动态代理:采用底层字节码技术,为目标类创建子类,并在子类中采用方法拦截的技术拦截目标类所有方法的执行,并顺势织入横切逻辑。
  • CGLIib所创建的动态代理对象的性能比JDK创建的代理对象的性能高很多(大概10倍),但CGLib在创建动态代理对象时所花费的时间比JDK动态代理多(大概8倍),所以对于singleton的代理对象或者具有实例池的代理,因为不需要频繁的创建对象,CGLib比较适合,反之JDK动态代理比较适合。需要注意的是由于CGLib采用动态创建子类的方式生成代理对象,所以不能对目标类中的final方法进行代理。

4 . 代码实现

假设现有一段逻辑如下:

1 public class UserServiceImpl {
2     public void getUserInfo() {
3         checkLogin();//权限检验代码,检查用户是否登录,这段代码在每个方法之前都需要执行
4         System.out.println("show user‘s infomation");//真正的业务逻辑代码
5     }
6 }

 

现在分别用两种AOP方式实现以上代码:

(1) 使用JDK 动态代理

首先需要一个UserService的接口

public interface UserService {

    public void getUserInfo();

}

然后一个UserService的实现类UserServiceImpl

public class UserServiceImpl implements UserService{

    @Override
    public void getUserInfo() {
        System.out.println("show user‘s infomation");
    }
}

一个代理类UserServiceProxy

public class UserServiceProxy implements InvocationHandler {

    private Object targetObject;

    public UserServiceProxy(Object targetObject) {
        this.targetObject = targetObject;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

        UserServiceImpl userService = (UserServiceImpl) targetObject;
        Object result = null;
        // 权限判断
        if (checkLogin() == true)) {
            result = method.invoke(targetObject, args);
        }else{
            throw new RuntimeException("you are not login,please login first");
        }
        return result;
    }

}

使用生成的代理类:

public static void main(String[] args) {

        UserServiceImpl targetObject = new UserServiceImpl();
        UserServiceProxy proxy = new UserServiceProxy(targetObject);
        // 生成代理对象
        UserService object = (UserService) Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                targetObject.getClass().getInterfaces(), proxy);
        object.getUserInfo();

    }

(2) 使用CGLib实现

生成代理类

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


public class CGLibProxy implements MethodInteceptor{

    private Enhancer enhancer = new Enhancer();

    public Object getProxy(Class clazz){
        enhancer.setSuperClass(clazz);//根据父类clazz创建代理对象
        enhancer.setCallBack(this);
        return enhancer.create();//动态创建子类实例
    }


    // 拦截父类所有方法的调用
    public Object intercept(Object obj,Method method,Object[] args,MethodProxy proxy) throws Throwable{
        Object result = null;
        if (checkLogin==true)) {
            result = proxy.invokeSuper(obj, args);// 通过代理类调用父类中的方法
        }else{
            throw new RuntimeException("you are not login,please login first");
        }
        return result;
    }

}

 

使用生成的代理类

public static void main(String[] args) {
        CGLibProxy proxy = new CGLibProxy();
        UserServiceImpl userService = (UserServiceImpl)proxy.getProxy(UserServiceImpl.class);
        userService.getUserInfo();
    }

 

AOP