AOP简介与代理方式
标签:Spring

AOP简介与代理方式

AOP Aspect Oriented Programing 面向切面编程 , AOP采取横向抽取机制,取代了传统纵向继承体系重复性代码(性能监视、事务管理、安全检查、缓存);

Spring AOP使用纯Java实现,不需要专门的编译过程和类加载器,在运行期通过代理方式向目标类织入增强代码 ;

AspecJ是一个基于Java语言的AOP框架,Spring2.0开始,Spring AOP引入对Aspect的支持,AspectJ扩展了Java语言,提供了一个专门的编译器,在编译时提供横向代码的织入 。

1. AOP相关术语

2. AOP底层实现

AOP 底层使用的代理技术 : JDK动态代理(JDK1.3 引入) 和 CGlib的动态代理

2.1 JDK动态代理

原理: 针对内存中Class对象,使用类加载器 动态为目标对象实现接口的创建代理类

UserDAO:

public interface UserDAO {
    void add();

    void search();
}

MyJDKProxy:

package com.liuyao.proxy;

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

/**
 * Created By liuyao on 2018/5/10 15:19.
 */
public class MyJDKProxy implements InvocationHandler {
    private UserDAO userDAO; //被代理对象

    // 通过被代理对象构造代理类对象
    public MyJDKProxy(UserDAO userDAO) {
        this.userDAO = userDAO;
    }

    /**
     * 使用JDK进行 动态代理
     *
     * @return
     */
    public UserDAO createJDKProxy() {
        return (UserDAO) Proxy.newProxyInstance(this.userDAO.getClass().getClassLoader(), this.userDAO.getClass().getInterfaces(), this);
    }

    @Override
//    访问被代理对象 任何方法,都和执行 invoke
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//        针对add方法进行增强
        if (method.getName().equals("add")) {
            System.out.println("记录日志...");
//            调用目标方法
            return method.invoke(this.userDAO, args);
        } else {
//            其他方法直接继续执行
            return method.invoke(this.userDAO, args);
        }
    }
}

Test:

@Test
public void testJDKProxy() {
    UserDAO userDAO = new UserDAOImpl();
    MyJDKProxy myJDKProxy = new MyJDKProxy(userDAO);
    UserDAO userDAOProxy = myJDKProxy.createJDKProxy();
    userDAOProxy.add();
    userDAOProxy.search();
}

运行结果:

2.2 CGLib动态代理

原理 : CGlib采用非常底层字节码技术,可以为一个类创建子类,解决无接口代理问题

ProductDAO:

public class ProductDAO {
    public void addProduct() {
        System.out.println("addProduct");
    }

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

MyCGLibProxy:

package com.liuyao.proxy.cglibproxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Created By liuyao on 2018/5/10 16:05.
 */
public class MyCGLibProxy implements MethodInterceptor {
    private ProductDAO productDAO; //目标对象

    //    通过构造器传入被代理对象
    public MyCGLibProxy(ProductDAO productDAO) {
        this.productDAO = productDAO;
    }

    //    创建代理
    public ProductDAO createCGLibProxy() {
//        创建代理核心对象
        Enhancer enhancer = new Enhancer();
//        设置被代理类(为类创建子类)
        enhancer.setSuperclass(this.productDAO.getClass());

//        设置回调函数
        enhancer.setCallback(this);
//        返回代理(返回代理子类对象)
        return (ProductDAO) enhancer.create();
    }

    @Override
//    被代理对象所有方法执行,都会调用intercept方法
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        if (method.getName().equals("addProduct")) {
            long start = System.currentTimeMillis();
            Object res = methodProxy.invokeSuper(o, objects);
            long end = System.currentTimeMillis();
            System.out.println("addProduct 运行 " + (end - start));
            return res;
        } else {
            return methodProxy.invokeSuper(o, objects);
        }
    }
}

Test:

  @Test
    public void test() {
        ProductDAO productDAO = new ProductDAO();
        MyCGLibProxy myCGLibProxy = new MyCGLibProxy(productDAO);

        ProductDAO productDAOProxy = myCGLibProxy.createCGLibProxy();
        productDAOProxy.addProduct();
        productDAOProxy.deleteProduct();
    }

运行结果:

2.3 JDK与CGLib使用总结

  • 6 min read

CONTRIBUTORS


  • 6 min read