Spring AOP的实现原理

一、介绍

AOP(Aspect Orient Programming),我们一般称为面向方面(切面)编程,作为面向对象的一种补充,用于处理系统中分布于各个模块的横切关注点,比如事务管理、日志、缓存等等。

AOP代理主要分为静态代理和动态代理:

  • 静态代理:以AspectJ为代表,在编译阶段生成AOP代理类---修改字节码
  • 动态代理:以Spring AOP为代表。不会去修改字节码,而是在内存中临时为方法生成一个AOP对象,这个AOP对象包含了目标对象的全部方法,并且在特定的切点做了增强处理,并回调原对象的方法。

二、Spring AOP的原理

Spring AOP中的动态代理主要有两种方式,JDK动态代理和CGLIB动态代理。

1. JDK动态代理

  • 通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。
  • JDK动态代理的核心是InvocationHandler接口和Proxy类。

2. CGLIB动态代理

  • CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类,
  • CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

3. Spring AOP的实现

  • 如果目标对象是接口类,就使用JDK动态代理;
  • 否则,Spring会使用CGLIB动态代理。

三、JDK动态代理的使用

1. 创建目标对象的接口及实现类

/**
 * 目标对象实现的接口,用JDK来生成代理对象一定要实现一个接口
 */
public interface UserService {

    /**
     * 目标方法 
     */
    public void add();

}

2. 创建目标对象

/**
 * 目标对象
 */
public class UserServiceImpl implements UserService {

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

3. 实现自己的InvocationHandler

/**
 * 实现自己的InvocationHandler
 */
public class MyInvocationHandler implements InvocationHandler {
    
    // 目标对象 
    private Object target;
    
    /**
     * 构造方法
     * @param target 目标对象 
     */
    public MyInvocationHandler(Object target) {
        super();
        this.target = target;
    }


    /**
     * 执行目标对象的方法
     */
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        
        // 在目标对象的方法执行之前简单的打印一下
        System.out.println("------------------before------------------");
        
        // 执行目标对象的方法
        Object result = method.invoke(target, args);
        
        // 在目标对象的方法执行之后简单的打印一下
        System.out.println("-------------------after------------------");
        
        return result;
    }

    /**
     * 获取目标对象的代理对象
     * @return 代理对象
     */
    public Object getProxy() {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), 
                target.getClass().getInterfaces(), this);
    }
}

4. 测试

/**
 * 动态代理测试类
 */
public class ProxyTest {

    public static void main(String[] args) {
        // 实例化目标对象
        UserService userService = new UserServiceImpl();

        // 实例化InvocationHandler
        MyInvocationHandler invocationHandler = new MyInvocationHandler(userService);

        // 根据目标对象生成代理对象
        UserService proxy = (UserService) invocationHandler.getProxy();

        // 调用代理对象的方法
        proxy.add();
    }

}

结果:

------------------before------------------
--------------------add---------------
-------------------after------------------

四、Cglib动态代理的使用

 1. 创建目标对象

//被代理类
public class InfoDemo {
    public void welcome (String person){
        System.out.println("welcome :" + person);
    }
}

2. 实现自己的MethodInterceptor

public class MyCglibInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        System.out.println("before...");
        Object result = methodProxy.invokeSuper(obj, args);
        System.out.println("after...");
        return result;
    }

    public static Object getProxy(Class cls, MethodInterceptor interceptor){
        Enhancer enhancer = new Enhancer();
        //生成指定类的子类,也就是重写类中的业务方法
        enhancer.setSuperclass(cls);
        //设置回调函数,加入intercept()方法
        enhancer.setCallback(interceptor);
        return enhancer.create();
    }

    public static void main(String[] args) {
        InfoDemo infoDemo = (InfoDemo)getProxy(InfoDemo.class, new MyCglibInterceptor());
        infoDemo.welcome("ketty");
    }
}

 3. 测试结果

before...
welcome :ketty
after...
原文地址:https://www.cnblogs.com/wslook/p/9163858.html