Spring AOP实现原理

Spring AOP实现原理

这里整理了一下AOP实现的几种方式,同时将代理模式也整理了一下。

代理模式

代理模式模型如下:
在这里插入图片描述
代理类实现了被代理类的接口,同时与被代理类是组合关系。下来看一下代理模式的实现。

静态代理

接口类:

public interface Person {
    void speak();
}

真实实体类:

public class Actor implements Person{
    
    @Override
    public void speak() {
        System.out.println("show your performance");
    }
}

代理类:

public class Agent implements Person{

   private Actor actor;

    public Agent(Actor actor) {
        this.actor = actor;
    }

    @Override
    public void speak() {
        System.out.println("before execute...");
        actor.speak();
        System.out.println("after execute...");
    }
}

测试方法:

public class StaticProxyTest {

    public static void main(String[] args) {
        Actor actor = new Actor();
        Agent agent = new Agent(actor);
        agent.speak();
    }
}

结果:
在这里插入图片描述

动态代理

JDK自带方法

先看下最核心的一个接口和一个方法
这个是java.lang.reflect包里的InvocationHandler接口:

public interface InvocationHandler {

    public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable;
}

我们对于被代理的类的操作都会由改接口中的invoke方法实现,其中的参数的含义分别是:

  • proxy:被代理的类的实例
  • method:调用被代理的类的方法
  • args:该方法需要的参数

使用方法首先是需要实现该接口,并且我们可以在invoke方法中调用被代理类的方法并获得返回值,自然也可以在调用该方法的前后去做一些额外的事情,从而实现动态代理。

另外一个很重要的静态方法就是java.lang.reflect包中的Proxy类的newProxyInstance方法:

 public static Object newProxyInstance(ClassLoader loader,
                                          Class<?>[] interfaces,
                                          InvocationHandler h)
        throws IllegalArgumentException

其中的参数含义如下:

  • loader:被代理的类的类加载器
  • interfaces:被代理类的接口数组
  • invocationHandler:就是刚刚介绍的调用处理器类的对象实例

该方法会返回一个被修改过的类的实例,从而可以自由的调用该实例的方法。下面是一个实际例子。

代理类Agent.java:

public class DynamicAgent {


    // 实现InvocationHandler接口,并且可以初始化被代理类的对象
    static class MyHandler implements InvocationHandler {
        private Object proxy;

        public MyHandler(Object proxy) {
            this.proxy = proxy;
        }

        // 自定义invoke方法
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            System.out.println("before invoke...");
            // 真正调用方法的地方
            Object ret = method.invoke(this.proxy, args);
            System.out.println("after invoke...");
            return ret;
        }
    }

    // 返回一个被修改过的对象
    public static Object agent(Class interfaceClazz, Object proxy) {
        return Proxy.newProxyInstance(interfaceClazz.getClassLoader(), new Class[]{interfaceClazz},
                new MyHandler(proxy));
    }
}

测试类:

public class ReflectTest {

    public static void main(String[] args) {
        // 注意一定要返回接口,不能返回实现类否则会报错
        Person person = (Person) DynamicAgent.agent(Person.class, new Actor());
        person.speak();
    }
}

结果:
在这里插入图片描述
可以看到对于不同的实现类来说,可以用同一个动态代理类来进行处理,实现了“一次编写到处代理”的效果。但是这种方法有个缺点,就是被代理的类一定要是实现了某个接口的,这很大程度限制了本方法的使用场景。下面还有另外一个使用了CGlib增强库的方法。

CGLIB库的方法

CGlib是一个字节码增强库,为AOP等提供了底层支持。
被代理类:

public class Actress {

    public void speak() {
        System.out.println("start your performance");
    }
}

使用CGlib代理过程:

public class CGlibAgent implements MethodInterceptor {

    private Object proxy;

    public Object getInstance(Object proxy) {
        this.proxy = proxy;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.proxy.getClass());
        // 回调方法
        enhancer.setCallback(this);
        // 创建代理对象
        return enhancer.create();
    }

    // 回调方法
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before invoke...");
        // 真正调用
        Object ret = methodProxy.invokeSuper(o, objects);
        System.out.println("after invoke...");
        return ret;
    }

    public static void main(String[] args) {
        CGlibAgent cGlibAgent = new CGlibAgent();
        Actress actress = (Actress)cGlibAgent.getInstance(new Actress());
        actress.speak();
    }
}

结果:
在这里插入图片描述
可以看到结果和JDK动态代理是一样的,但是可以直接对实现类进行操作而非接口,这样会有很大的便利。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值