JDK/CGLIB/Spring三种方式实现动态代理

基于 JDK 实现动态代理

JDK 动态代理的原理是利用反射机制,在运行时创建代理类,必要条件是代理对象基于接口实现。

创建一个接口及其实现类。

public interface IService {

    void sayHello();

}
public class JdkServiceImpl implements IService {

    @Override
    public void sayHello() {
        System.out.println("Hello JAVA Proxy");
    }

}

创建代理处理类,必须实现 InvocationHandler 接口。

@AllArgsConstructor
public class ServiceInvocationHandler implements InvocationHandler {

    private final Object target;

    @Override
    public Object invoke(Object obj, Method method, Object[] args) throws Throwable {
        System.out.println("-------- begin ----------");
        Object result = method.invoke(target, args);
        System.out.println("-------- end ----------");
        return result;
    }

}

执行动态代理

public class JdkProxyTest {

    public static void main(String[] args) {
        IService service = new JdkServiceImpl();
        ServiceInvocationHandler handler = new ServiceInvocationHandler(service);
        IService proxy = (IService) Proxy.newProxyInstance(JdkProxyTest.class.getClassLoader(), new Class[]{IService.class}, handler);
        proxy.sayHello();

        System.out.println();
        System.out.println(proxy.getClass().getSimpleName() +
                " extend " + proxy.getClass().getSuperclass().getSimpleName() +
                " implements " + Arrays.stream(proxy.getClass().getInterfaces())
                .map(Class::getSimpleName)
                .collect(Collectors.joining(",")));
    }

}

输出结果如下,可以看出在 sayHello 方法前后,执行了代理处理类中的代码输出,说明通过 JDK 动态代理实现了代理增强。

-------- begin ----------
Hello JAVA Proxy
-------- end ----------

$Proxy0 extend Proxy implements IService

最后一行的输出显示了动态生成的代理类的继承关系,该类实现代理对象的接口,JDK 动态代理的继承机制决定了只能对接口进行代理。

基于 Cglib 实现动态代理

Cglib 动态代理的原理是利用字节码技术,在运行时创建一个继承代理类的 class,所以代理对象不需要实现接口,但要求被代理类及方法必须不是 final 的

创建一个需要被代理的类

public class CglibServiceImpl {

    public void sayHello() {
        System.out.println("Hello Cglib Proxy");
    }

}

创建方法拦截器,必须实现 MethodInterceptor 接口,实现代理增强

public class ServiceInterceptor implements MethodInterceptor {

    @Override
    public Object intercept(Object obj, Method method, Object[] params, MethodProxy methodProxy) throws Throwable {
        System.out.println("-------- begin ----------");
        Object result = methodProxy.invokeSuper(obj, params);
        System.out.println("-------- end ----------");
        return result;
    }

}

执行代理操作

public class CglibProxyTest {

    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(CglibServiceImpl.class);
        enhancer.setCallback(new ServiceInterceptor());
        CglibServiceImpl proxy = (CglibServiceImpl) enhancer.create();
        proxy.sayHello();

        System.out.println();
        System.out.println(proxy.getClass().getSimpleName() +
                " extend " + proxy.getClass().getSuperclass().getSimpleName() +
                " implements " + Arrays.stream(proxy.getClass().getInterfaces())
                .map(Class::getSimpleName)
                .collect(Collectors.joining(",")));
    }

}

输出结果如下

-------- begin ----------
Hello Cglib Proxy
-------- end ----------

ServiceImpl$$EnhancerByCGLIB$$ef25c05 extend ServiceImpl implements Factory

基于 Spring 的 ProxyFactory 实现动态代理

Spring 也提供了自己动态代理实现,但其实做的还是整合的工作,底层依然是基于上文中的两种技术。

创建方法拦截器,需要实现 MethodInterceptor 接口(这个接口在 org.aopalliance.intercept 包中,与 cglib 中的不是同一个)。

public class AopInterceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.out.println("-------- begin ----------");
        Object result = invocation.proceed();
        System.out.println("-------- end ----------");
        return result;
    }

}

执行代理操作

public class SpringProxyTest {

    public static void main(String[] args) {
        executeJdkProxy();
//        executeCglibProxy();
    }

    public static void executeJdkProxy() {
        ProxyFactory factory = new ProxyFactory();
        factory.setInterfaces(IService.class);
        factory.setTarget(new JdkServiceImpl());
        factory.addAdvice(new AopInteceptor());
        IService proxy = (IService) factory.getProxy();
        proxy.sayHello();
        printClassName(proxy);
    }

    public static void executeCglibProxy() {
        ProxyFactory factory1 = new ProxyFactory();
        factory1.setTarget(new CglibServiceImpl());
        factory1.addAdvice(new AopInteceptor());
        CglibServiceImpl proxy1 = (CglibServiceImpl) factory1.getProxy();
        proxy1.sayHello();
        printClassName(proxy1);
    }

    public static void printClassName(Object proxy) {
        System.out.println();
        System.out.println(proxy.getClass().getSimpleName() +
                " extend " + proxy.getClass().getSuperclass().getSimpleName() +
                " implements " + Arrays.stream(proxy.getClass().getInterfaces())
                .map(Class::getSimpleName)
                .collect(Collectors.joining(",")));
    }

}

执行 executeJdkProxy 方法输出

-------- begin ----------
Hello World
-------- end ----------

$Proxy18 extend Proxy implements IService,SpringProxy,Advised,DecoratingProxy

执行 executeCglibProxy 方法输出

-------- begin ----------
Hello Cglib Proxy
-------- end ----------

CglibServiceImpl$$EnhancerBySpringCGLIB$$57b39275 extend CglibServiceImpl implements SpringProxy,Advised,Factory

通过最后输出的类继承结构可以看出在 ProxyFactory 之下的实现原理,executeJdkProxyexecuteCglibProxy 方法不同的一点是调用 factory.setInterfaces 设置了接口,如果不设置接口,那么底层还是使用 cglib 实现,虽然最终呈现出来的效果是一样的。所以具体使用哪种方案实现,并不处决了代理对象是不是接口,而是有没有向 ProxyFactory 设置接口(当然设置接口的前提首先得实现接口)。

ProxyFactory 的实现源码分析

根据方法 getProxy 进行源码跟踪

public class ProxyFactory extends ProxyCreatorSupport {
    
    public Object getProxy() {
		return createAopProxy().getProxy();
	}

}

createAopProxy 方法在其父类中实现,调用 AopProxyFactory.createAopProxy 方法创建一个 AopProxy 对象,AopProxyFactory 默认使用 DefaultAopProxyFactory

public class ProxyCreatorSupport extends AdvisedSupport {

    private AopProxyFactory aopProxyFactory;

    public ProxyCreatorSupport() {
        this.aopProxyFactory = new DefaultAopProxyFactory();
    }
    
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }

}

DefaultAopProxyFactorycreateAopProxy 方法,可以看到根据不同的条件会选择创建不同的 AopProxy

public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {

    @Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
        if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
            Class<?> targetClass = config.getTargetClass();
            if (targetClass == null) {
                throw new AopConfigException("TargetSource cannot determine target class: " +
                        "Either an interface or a target is required for proxy creation.");
            }
            if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
                return new JdkDynamicAopProxy(config);
            }
            return new ObjenesisCglibAopProxy(config);
        } else {
            return new JdkDynamicAopProxy(config);
        }
    }
    
}

AopProxy 的实现类分别代表不同的实现策略

在这里插入图片描述

JdkDynamicAopProxy 的实现为例,可以看到最终调用的还是 JDK 提供的 Proxy.newProxyInstance() 方法创建代理对象。

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
    
    public Object getProxy() {
        return getProxy(ClassUtils.getDefaultClassLoader());
    }

    public Object getProxy(@Nullable ClassLoader classLoader) {
        if (logger.isTraceEnabled()) {
            logger.trace("Creating JDK dynamic proxy: " + this.advised.getTargetSource());
        }
        Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
        findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
        return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
    }

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值