之前两篇文章中我们说到了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());
}
}
成功获得代理类并实现拦截。
从运行结果的代理类的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(通过配置文件)。