Spring AOP 实现

常用AOP代理形式

AOP常见有静态代理和动态代理
静态代理代表为AspectJ;
动态代理有jdk动态代理, cglib动态代理。

静态代理

AspectJ是静态代理的增强, 即编译时生成代理类, 也成为编译时增强。性能较好。 不过由于需要特定的编译器进行处理。

动态代理

动态代理是每次运行的时候生成代理AOP代理类,不会修改字节码文件。代理对象创建在内存中。
由于是在运行的时候生成代理,故性能稍差一点。

JDK动态代理实例

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

/**
 * @author imyzt
 * @date 2019/1/17 9:51
 * @description JDK动态代理演示
 */
public class JdkDynamicProxyDemo {

    public static void main(String[] args) {

        // 创建需要被代理的实例对象
        JdkDynamicProxyClass jdkDynamicProxyClass = new JdkDynamicProxyClass();

        JdkDynamicProxyInvocationHandler invocationHandler =
                new JdkDynamicProxyInvocationHandler(jdkDynamicProxyClass);

        // 增强代理类
        // Proxy.newProxyInstance();
        JdkDynamicProxyInterface proxyInstance = (JdkDynamicProxyInterface) Proxy.newProxyInstance(
                jdkDynamicProxyClass.getClass().getClassLoader(),
                jdkDynamicProxyClass.getClass().getInterfaces(),
                invocationHandler);

        // 执行被增强的方法
        proxyInstance.proxyMethod();
    }

}

interface JdkDynamicProxyInterface {
    void proxyMethod();
}

class JdkDynamicProxyClass implements JdkDynamicProxyInterface {

    @Override
    public void proxyMethod() {
        System.out.println("JDK Dynamic Proxy Method is running");
    }
}

class JdkDynamicProxyInvocationHandler implements InvocationHandler {

    private Object target;

    public JdkDynamicProxyInvocationHandler(Object target) {
        this.target = target;
    }

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

        String name = method.getName();

        System.out.println("execute before JDK Dynamic Method = " + name);
        Object invoke = method.invoke(target, args);
        System.out.println("execute after JDK Dynamic Method = " + name);

        return invoke;
    }
}

运行结果展示
JDK动态代理

CGLIB 动态代理

/**
 * @author imyzt
 * @date 2019/1/17 10:05
 * @description CGLIB 动态代理演示
 */
public class CglibDynamicProxyDemo {

    public static void main(String[] args) {

        CglibDynamicProxy cglibDynamicProxy = new CglibDynamicProxy();

        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibDynamicClass.class);
        enhancer.setCallback(cglibDynamicProxy);

        CglibDynamicClass cglibDynamicClass = (CglibDynamicClass) enhancer.create();

        String yyy = cglibDynamicClass.proxyMethod("yyy");

        System.out.println(yyy);


    }
}
class CglibDynamicClass {
    public String proxyMethod(String message){
        System.out.println("hello! you say " + message);
        return message;
    }
}
class CglibDynamicProxy implements MethodInterceptor {

    @Override
    public Object intercept(Object proxyClass, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

        String name = method.getName();

        System.out.println("execute before CGLIB Dynamic Method = " + name);
        Object invoke = **methodProxy.invokeSuper**(proxyClass, args);
        System.out.println("execute after CGLIB Dynamic Method = " + name);

        return invoke;
    }
}

运行结果展示
请输入图片描述

Spring AOP

Spring AOP在使用的时候会判断,如果需要代理的类实现了接口, 则会使用JDK代理,如果没有实现接口, 则使用CGLIB代理。

JDK动态代理通过反射来接收被代理的类,并且要求被代理的类必须实现一个接口。JDK动态代理的核心是InvocationHandler接口和Proxy类。
如果目标类没有实现接口,那么Spring AOP会选择使用CGLIB来动态代理目标类。CGLIB(Code Generation Library),是一个代码生成的类库,可以在运行时动态的生成某个类的子类(通过修改字节码来实现代理)。
注意,CGLIB是通过继承的方式做的动态代理,因此如果某个类被标记为final,那么它是无法使用CGLIB做动态代理的。

文章中部分内容转载自掘金-年糕妈妈技术团队