spring中的动态代理

动态代理

Spring容器在启动时,会检测到 dishFlavorMapper 需要被AOP增强(假设它已经被标记为需要增强,比如通过注解或配置)。然后,Spring容器不会直接注入原始的 dishFlavorMapper 实例,而是注入一个代理对象。
这个代理对象实现了与 原对象相同的接口,因此可以在不改变代码的情况下替换原始对象。当你通过代理对象调用方法时,比如 dishFlavorMapper.getByDishId(d.getId()),以下步骤会发生:
拦截调用:代理对象会拦截这个方法调用。
查找切面:代理对象会检查是否有配置的切面(比如 AutoFillAspect)与当前方法调用匹配。
执行通知:如果找到匹配的切面和通知,代理对象会先执行对应的通知逻辑。例如,如果有一个 @Before 通知,它会在目标方法执行之前执行。

Spring更常用的是动态代理,主要有两种实现方式:JDK动态代理和CGLIB。

JDK动态代理
JDK动态代理是基于Java反射机制实现的,只能为实现了接口的类创建代理。

实现:通过实现java.lang.reflect.InvocationHandler接口和java.lang.reflect.Proxy类来创建代理对象。
限制:被代理的类必须实现至少一个接口。
CGLIB
CGLIB(Code Generation Library)通过底层的字节码技术创建代理类的子类,因此它不需要接口。

代码举例

实现:通过扩展目标类并覆盖其非final方法来创建代理。
特点:可以代理没有实现接口的类,但无法代理final类和方法。
下面是一个使用JDK动态代理的简单例子。这个例子中,我们将创建一个简单的Hello接口,一个实现了这个接口的类HelloImpl,以及一个代理类HelloProxyHandler,它将作为我们的代理处理器。

首先,定义一个简单的接口:

public interface Hello {
    void sayHello(String name);
}

然后,实现这个接口:

public class HelloImpl implements Hello {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello, " + name + "!");
    }
}

接下来,创建代理处理器,它实现了InvocationHandler接口:

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

public class HelloProxyHandler implements InvocationHandler {
    private final Object target; // 被代理的对象

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

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        // 在调用目标方法之前,可以添加一些预处理逻辑
        System.out.println("Before method call: " + method.getName());
        
        // 调用目标对象的方法
        Object result = method.invoke(target, args);
        
        // 在调用目标方法之后,可以添加一些后处理逻辑
        System.out.println("After method call: " + method.getName());
        
        return result;
    }
}

最后,创建代理对象并使用它:

import java.lang.reflect.Proxy;

public class ProxyTest {
    public static void main(String[] args) {
        // 创建被代理的对象
        Hello hello = new HelloImpl();
        
        // 创建代理处理器
        InvocationHandler handler = new HelloProxyHandler(hello);
        
        // 使用Proxy类创建代理对象
        Hello proxyHello = (Hello) Proxy.newProxyInstance(
                Hello.class.getClassLoader(), // 类加载器
                new Class<?>[]{Hello.class}, // 代理需要实现的接口
                handler // 代理处理器
        );
        
        // 使用代理对象调用方法
        proxyHello.sayHello("World");
    }
}

在这个例子中,当proxyHello.sayHello(“World”)被调用时,实际上会调用HelloProxyHandler的invoke方法。invoke方法内部会执行以下步骤:

输出调用方法之前的信息。
调用实际对象hello的sayHello方法。
输出调用方法之后的信息。
运行ProxyTest类的main方法,你会看到以下输出:

Before method call: sayHello
Hello, World!
After method call: sayHello
下面是一个使用CGLIB动态代理的简单例子。在这个例子中,我们将创建一个简单的Hello类,一个实现了Hello接口的HelloImpl类,以及一个代理类HelloProxy,它将作为我们的代理处理器。

首先,定义一个简单的接口:

public interface Hello {
    void sayHello(String name);
}

然后,实现这个接口:

public class HelloImpl implements Hello {
    @Override
    public void sayHello(String name) {
        System.out.println("Hello, " + name + "!");
    }
}

接下来,创建代理处理器,它实现了MethodInterceptor接口:

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

public class HelloProxy implements MethodInterceptor {
    private final Object target; // 被代理的对象

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

    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        // 在调用目标方法之前,可以添加一些预处理逻辑
        System.out.println("Before method call: " + method.getName());
        
        // 调用目标对象的方法
        Object result = proxy.invokeSuper(obj, args);
        
        // 在调用目标方法之后,可以添加一些后处理逻辑
        System.out.println("After method call: " + method.getName());
        
        return result;
    }
}

最后,创建代理对象并使用它:

import net.sf.cglib.proxy.Enhancer;

public class CGLIBProxyTest {
    public static void main(String[] args) {
        // 创建被代理的对象
        Hello hello = new HelloImpl();
        
        // 创建代理处理器
        HelloProxy handler = new HelloProxy(hello);
        
        // 使用CGLIB创建代理对象
        Hello proxyHello = (Hello) Enhancer.create(hello.getClass(), handler);
        
        // 使用代理对象调用方法
        proxyHello.sayHello("World");
    }
}

在这个例子中,当proxyHello.sayHello(“World”)被调用时,实际上会调用HelloProxy的intercept方法。intercept方法内部会执行以下步骤:

输出调用方法之前的信息。
调用目标对象的方法。
输出调用方法之后的信息。
运行CGLIBProxyTest类的main方法,你会看到以下输出:

Before method call: sayHello
Hello, World!
After method call: sayHello

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值