zoukankan      html  css  js  c++  java
  • Spring-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();
        }
  • 相关阅读:
    MATLAB仿真学习笔记(一)
    SolidWorks学习笔记(一)
    机械制造技术学习笔记(七)
    基于MATLAB的多功能语音处理器
    MATLAB图形界面设计(下)
    36、如何避免僵尸进程?
    37、局部性原理你知道吗?主要有哪两大局部性原理?各自是什么?
    35、 守护进程、僵尸进程和孤儿进程
    32、什么是快表,你知道多少关于快表的知识?
    30、终端退出,终端运行的进程会怎样?31、如何让进程后台运行
  • 原文地址:https://www.cnblogs.com/pepper7/p/6895288.html
Copyright © 2011-2022 走看看