JDK、CGLIB、Spring 三种实现代理的区别(三)Spring的ProxyFactory

之前两篇文章中我们说到了JDK proxy和CGLIB实现动态代理的方式,这回说说Spring的方式。Spring中代理对象可通过xml配置方式获得,也可通过ProxyFactory手动编程方式创建对象。我们主要讲手动编程的方式。Spring中的代理对象其实是JDK Proxy和CGLIB Proxy 的结合。
下面我们使用ProxyFactory的方式创建代理对象,顺便看看和JDK的proxy以及CGLIB中的proxy联系。
还是使用前两节中的例子。创建需要代理的类(MyTarget)、接口(PeopleService)及其实现(EnglishService),分别看看对接口和类的代理:

public class MyTarget {
    public void printName() {
        System.err.println("name:Target-");
    }
}
public interface PeopleService {
    public void sayHello();

    public void printName(String name);
}
public class EnglishService implements PeopleService {
    @Override
    public void sayHello() {
        System.err.println("Hi~");
    }

    @Override
    public void printName(String name) {
        System.err.println("Your name:" + name);
    }
}

下面创建一个MethodInterceptor实现方法调用的前后拦截,这里的拦截只是进行简单的打印信息。
这里需要用到额外的包 aopalliance.jar和aspectjweaver。

import org.aopalliance.intercept.MethodInterceptor;

import org.aopalliance.intercept.MethodInvocation;

public class AroundInteceptor implements MethodInterceptor {

    @Override
    public Object invoke(MethodInvocation invocation) throws Throwable {
        System.err.println(invocation.getMethod().getName() + "调用之前");
        Object res = invocation.proceed();
        System.err.println(invocation.getMethod().getName() + "调用之后");
        return res;
    }
}

使用Spring aop包中的ProxyFactory创建代理,并通过addAdvice
增加一个环绕方式的拦截:

package com.spring;

import org.springframework.aop.framework.ProxyFactory;
import org.testng.annotations.Test;

import com.cglib.MyTarget;
import com.proxy.api.PeopleService;
import com.proxy.impl.EnglishService;
import com.spring.aop.AroundInteceptor;

public class ProxyFactoryTest {
    @Test
    public void classProxy() {
        //代理对象未指定接口,使用CGLIB生成代理类
        ProxyFactory factory = new ProxyFactory();
        factory.setTarget(new MyTarget());
        factory.addAdvice(new AroundInteceptor());
        MyTarget targetProxy = (MyTarget) factory.getProxy();
        targetProxy.printName();
        System.err.println(targetProxy.getClass().getName());
    }

    @Test
    public void interfaceProxy() {
        //代理对象指定接口PeopleService,目标类为实现PeopleService的EnglishService,使用JDK proxy生成代理类
        ProxyFactory factory = new ProxyFactory();
        factory.setInterfaces(new Class[] { PeopleService.class });
        factory.addAdvice(new AroundInteceptor());
        factory.setTarget(new EnglishService());
        PeopleService peopleProxy = (PeopleService) factory.getProxy();
        peopleProxy.sayHello();
        System.err.println(peopleProxy.getClass().getName());
    }
}

运行结果分别为:
JDK、CGLIB、Spring 三种实现代理的区别(三)Spring的ProxyFactory_第1张图片

JDK、CGLIB、Spring 三种实现代理的区别(三)Spring的ProxyFactory_第2张图片
成功获得代理类并实现拦截。
从运行结果的代理类的class name ,以及前两节中讲的,很清晰的看到Spring中对于指定接口的代理类,Spring中使用的是JDK的Proxy,对于不指定接口的使用CGLIB的方式。对于上面的测试方法interfaceProxy,我们只注释掉
//factory.setInterfaces(new Class[] { PeopleService.class }) 这行代码,在次运行,结果为:
这里写图片描述
使用的是CGLIB处理,从而验证我们的猜想。
我们从getProxy()方法追踪,看到:

    //根据factory的设置生成一个proxy类。
    public Object getProxy() {
        return createAopProxy().getProxy();
    }

调用的createAopProxy是属于基类ProxyCreatorSupport(ProxyFactory继承ProxyCreatorSupport):的,而getProxy是属于接口AopProxy的。我们查看ProxyCreatorSupport类的相关方法:

   /**
     * Subclasses should call this to get a new AOP proxy. They should not
     * create an AOP proxy with {@code this} as an argument.
     */
    protected final synchronized AopProxy createAopProxy() {
        if (!this.active) {
            activate();
        }
        return getAopProxyFactory().createAopProxy(this);
    }
    /**
     * Return the AopProxyFactory that this ProxyConfig uses.
     */
    public AopProxyFactory getAopProxyFactory() {
        return this.aopProxyFactory;
    }

       /**
     * Create a new ProxyCreatorSupport instance.
     */
    public ProxyCreatorSupport() {
        this.aopProxyFactory = new DefaultAopProxyFactory();
    }

而aopProxyFactory对象在默认构造函数中赋值为DefaultAopProxyFactory的实例。该构造函数在我们使用创建ProxyFactory factory = new ProxyFactory(); 语句创建factory事被调用。接下来我们看DefaultAopProxyFactory的createAopProxy相关代码:

@Override
    public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
    //是否isOptimize默认false;是否直接代理目标类以及任何接口;是否有指定代理接口
        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);
        }
    }

     /**
     * Determine whether the supplied {@link AdvisedSupport} has only the
     * {@link org.springframework.aop.SpringProxy} interface specified
     * (or no proxy interfaces specified at all).
     */
    private boolean hasNoUserSuppliedProxyInterfaces(AdvisedSupport config) {
        Class[] ifcs = config.getProxiedInterfaces();
        return (ifcs.length == 0 || (ifcs.length == 1 && SpringProxy.class.isAssignableFrom(ifcs[0])));
    }

在ProxyCreatorSupport的createAopProxy方法中,调用的就是上面的代码(以当前的ProxyCreatorSupport作为参数)。我们看到代码中默认使用的是JDK的动态代理方式。根据config中参数进行判断使用代理方式。我们再看我们的例子中,对PeopleService接口的代理时,代码中添加了:

factory.setInterfaces(new Class[] { PeopleService.class });

其为AdvisedSupport中的代码(ProxyFactory继承ProxyCreatorSupport,ProxyCreatorSupport继承了AdvisedSupport,而AdvisedSupport继续了ProxyConfig类),我们看看AdvisedSupport中setInterfaces和getProxiedInterfaces方法:

/**
     * Set the interfaces to be proxied.
     */
    public void setInterfaces(Class... interfaces) {
        Assert.notNull(interfaces, "Interfaces must not be null");
        this.interfaces.clear();
        for (Class ifc : interfaces) {
            addInterface(ifc);
        }
    }
      @Override
    public Class[] getProxiedInterfaces() {
        return this.interfaces.toArray(new Class[this.interfaces.size()]);
    }

再看看createAopProxy的真正实现代码中,当我们对PeopleService代理时,添加了interfaces,也就是hasNoUserSuppliedProxyInterfaces为false,而config.isOptimize()和config.isProxyTargetClass()默认false,所有这时候直接走的就是return new JdkDynamicAopProxy(config);
而给MyTarget中进行代理时,hasNoUserSuppliedProxyInterfaces为true,targetClass也就是MyTarget不是接口且Proxy.isProxyClass为false,直接走的就是return new JdkDynamicAopProxy(config); 使用CGLIB进行处理

截止目前为止,三种方式已经分析完毕。Spring中优先使用JDK Proxy,可强制使用CGLIB(通过配置文件)。

你可能感兴趣的:(java,学习记录)