Spring AOP底层原理

633 阅读3分钟

时间不够就看这两句话

有接口jdk动态代理,没接口cglib动态代理。

aop时加载所有切面类,拿到切点和本类的方法一一比较,匹配到了执行动态代理。

一、动态代理

AOP中最最核心的一点就是动态代理,动态代理就是帮助我们扩展现有功能的,那么动态代理怎么实现呢?

1、jdk动态代理

jdk动态代理是代理实现的一种方式,这种方式适用于使用接口的形式。

主要是这几步:创建接口、生成接口实现类、创建代理逻辑的类、测试。

(1)创建接口

public interface HelloWorld {
    public void sayHello();
}

(2)创建接口实现类

public class HelloWorldImpl implements HelloWorld{
    public void sayHello() {
        System.out.println("Hello World");
    }
}

(3)创建代理逻辑的类,实现invoke方法,这里面写代理逻辑,也就是扩展原来的方法。

public class JdkProxyExample implements InvocationHandler {
    //创建真实对象
    private Object target = null;

    //建立代理对象和真实对象的联系
    public Object bind(Object target){
        this.target = target;
        return Proxy.newProxyInstance
                (target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
    }

    //代理方法逻辑
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("进入代理逻辑");
        System.out.println("调度真实对象之前的服务");
        Object obj = method.invoke(target, args);
        System.out.println("调度真实对象之后的服务");
        return obj;
    }
}

测试。

public class testJdkProxy {
    public static void main(String[] args) {
        JdkProxyExample jdk = new JdkProxyExample();
        HelloWorld proxy = (HelloWorld) jdk.bind(new HelloWorldImpl());
        proxy.sayHello();
    }
}

2、cglib动态代理

实际上也有不含接口的类,这些怎么实现动态代理呢?这就需要使用cglib动态代理了。

这里使用增强类来实现动态代理,生成代理对象,然后操作代理逻辑。

public class CglibProxyExample implements MethodInterceptor {
    //生成代理对象
    public Object getProxy(Class cls){
        //增强类对象
        Enhancer enhancer = new Enhancer();
        //设置增强类型
        enhancer.setSuperclass(cls);
        //定义代理逻辑对象为当前对象
        enhancer.setCallback(this);
        //生成并返回代理对象
        return enhancer.create();
    }

    //代理逻辑方法
    public Object intercept(Object o, Method method,
                            Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("调用真实对象前");
        Object result = methodProxy.invokeSuper(o,objects);
        System.out.println("调用真实对象后");
        return result;
    }
}

测试。

public class testCglibProxy {
    public static void main(String[] args) {
        CglibProxyExample cpe = new CglibProxyExample();
        HelloWorldImpl obj = (HelloWorldImpl) cpe.getProxy(HelloWorldImpl.class);
        obj.sayHello();
    }
}

二、AOP

aop操作实际上就是使用动态代理来扩展现有的类和方法。

首先我们会在某个类上加上切面@Aspect来定义一个切面,当然这里类上也需要加上@Component注解把这个类加入到容器中。

当某个类A需要使用AOP横向切入了,Spring会看到这个类的上级是否有接口,也就是它是不是某个接口的实现类,如果是的话,Spring会选择jdk动态代理,如果不是则会选择cglib动态代理。

A要创建对象,创建对象的流程如下:

class——>实例化对象——>DI注入——>初始化——>aop(代理对象)——>bean

创建对象走到aop这一步,Spring会拿到所有加上@Aspect的类,找到它们的切点和当前类中的方法进行一一比较,切点因为有表达式,这样很容易定位,如果定位到了,那么就会执行下去。

因为要创建代理对象,代理对象不管是哪种方式,都会先拿到原对象target,然后在代理类中调用target需代理的方法,并在它的前后左右加上代理逻辑。