上文中描述。代理对象的的创建:
- 完成配置,将Advisor(增强器)填充到Advised中;
- 使用JDK/CGLIB创建代理对象。
而本文重点描述一下代理对象的创建过程。
源码位置:org.springframework.aop.framework.ProxyCreatorSupport#createAopProxy
protected final synchronized AopProxy createAopProxy() {
if (!this.active) {
activate();
}
return getAopProxyFactory().createAopProxy(this);
}
可以看到ProxyCreatorSupport实际上是Advised子类。
创建AopProxy时,会将this(也就是Adviced)对象传入,即传入config(Advised)配置对象。
而后调用DefaultAopProxyFactory
完成代理对象的创建
源码:org.springframework.aop.framework.DefaultAopProxyFactory#createAopProxy
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
//是Advised配置信息。
//是否对代理进行优化 || 直接使用Cglib代理(这两者默认情况下为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.");
}
//目标类本身就是一个接口||目标类已经是JDK代理类
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
1. JDK代理对象
1.1 测试代码
JDK代理前提是:目标类需要存在接口。
//接口类
public interface IAccount {
String say(@NotNull Integer id, @NotNull String desc);
//接口内部定义了hashCode方法
int hashCode();
}
//子类
@Service("accountImpl")
public class AccountImpl implements IAccount {
@Override
public String say(@NotNull Integer id, @NotNull String desc) {
return "my "+id + ":" + desc;
}
@Override
public int hashCode() {
return 123;
}
@Override
public boolean equals(Object obj) {
return super.equals(obj);
}
}
测试方法:
@Slf4j
public class proxyBean {
public static void main(String[] args) {
ProxyFactory proxyFactory = new ProxyFactory(new AccountImpl());
proxyFactory.addAdvice((MethodBeforeAdvice) (method, arg1, target) -> {
log.info("被拦截了:方法名:[{}],参数[{}]", method.getName(), Arrays.asList(arg1));
});
IAccount account = (IAccount) proxyFactory.getProxy();
log.info(account.say(100, "哈哈哈"));
log.info("hashCode方法:"+account.hashCode());
log.info("equals方法:"+account.equals(account));
}
}
测试结果:
12:59:13.242 [main] INFO com.tellme.Impl.proxy.proxyBean - 被拦截了:方法名:[say],参数[[100, 哈哈哈]]
12:59:13.257 [main] INFO com.tellme.Impl.proxy.proxyBean - my 100:哈哈哈
12:59:13.257 [main] INFO com.tellme.Impl.proxy.proxyBean - 被拦截了:方法名:[hashCode],参数[[]]
12:59:13.257 [main] INFO com.tellme.Impl.proxy.proxyBean - hashCode方法:123
12:59:13.258 [main] INFO com.tellme.Impl.proxy.proxyBean - equals方法:true
上述结果中可以看出,hashCode方法被拦截,而equlas方法并没有被拦截。而出现这个问题的原因是:hashCode由接口再次定义,而equals只是子类自己实现的方法。在Proxy中会进行特殊的处理。
1.2源码分析
final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {
private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);
//代理对象使用的配置类
private final AdvisedSupport advised;
private boolean equalsDefined;
private boolean hashCodeDefined;
public JdkDynamicAopProxy(AdvisedSupport config) throws AopConfigException {
Assert.notNull(config, "AdvisedSupport must not be null");
//内部对象再次校验一次,必须至少存在一个增强器+目标实例
if (config.getAdvisors().length == 0 && config.getTargetSource() == AdvisedSupport.EMPTY_TARGET_SOURCE) {
throw new AopConfigException("No advisors and no TargetSource specified");
}
this.advised = config;
}
@Override
public Object getProxy() {
return getProxy(ClassUtils.getDefaultClassLoader());
}
//真正创建Proxy代理的地方
@Override
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);
//第三个参数是this,处理器就是自己,到此一个代理对象就被创建出来
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
//判断接口列表中是否存再自定义的equals方法和hashCode方法,然后标记一下
private void findDefinedEqualsAndHashCodeMethods(Class<?>[] proxiedInterfaces) {
for (Class<?> proxiedInterface : proxiedInterfaces) {
Method[] methods = proxiedInterface.getDeclaredMethods();
for (Method method : methods) {
if (AopUtils.isEqualsMethod(method)) {
this.equalsDefined = true;
}
if (AopUtils.isHashCodeMethod(method)) {
this.hashCodeDefined = true;
}
//若两者均找到后,停止循环。
if (this.equalsDefined && this.hashCodeDefined) {
return;
}
}
}
}
//这部分代码实际上和CGLIB大部分逻辑是一样的,本来是可以抽取出来
//但Spring解释说:由此会带来10%的性能损耗,所以Spring最终采取了粘贴复制的方式各实现了一份。
//Spring为其提供了基础的套件,来保证两个的执行行为是一致的。
@Override
@Nullable
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
MethodInvocation invocation;
Object oldProxy = null;
boolean setProxyContext = false;
//进入invoke方法后,最终操作的是targetSource对象。
//因为InvocationHandler持久化的就是targerSource,最终通过target得到目标对象
TargetSource targetSource = this.advised.targetSource;
Object target = null;
try {
//AOP“通常情况”下不会对equals、hashCode方法进行拦截。
//若equalsDefined为false,即用户未定义equals方法,那么交由代理去比较。
//hashCode同理
//若接口上有equals、hashCode方法,但子类并未实现,那么不会被代理
//若接口没有equals。hashCode方法,子类@Override实现,那么是无效的。
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {
// The target does not implement the equals(Object) method itself.
return equals(args[0]);
}
else if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {
// The target does not implement the hashCode() method itself.
return hashCode();
}
//DecoratingProxy的方法和Advised接口的方法都是调用的是this.advised去执行
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations on ProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//是否暴露代理对象,默认false可配置为true,如果暴露就意味着允许在线程内共享代理对象。
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 通过目标源获取目标对象
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
// 获取作用在这个方法上的所有拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
if (chain.isEmpty()) {
//若拦截器为空,那就直接调用目标方法。
//对参数进行适配:主要处理一些数组类型的参数,看是表示一个参数 还是表示多个参数(可变参数最终到此都是数组类型,所以最好是需要一次适配)
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
//调用目标方法
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 创建一个invocation ,此处为ReflectiveMethodInvocation 最终是通过它,去执行前置加强、后置加强等等逻辑。
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 此处会执行所有的过滤器链+目标方法。
retVal = invocation.proceed();
}
// 获取返回值的类型
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 一些列的判断条件,如果返回值不为空,且为目标对象的话,就直接将目标对象赋值给retVal
retVal = proxy;
}
//返回null,并且还不是void类型。。。抛错
else if (retVal == null && returnType != Void.TYPE && returnType.isPrimitive()) {
throw new AopInvocationException(
"Null return value from advice does not match primitive return type for: " + method);
}
return retVal;
}
finally {
//释放
if (target != null && !targetSource.isStatic()) {
// Must have come from TargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// 把老的代理对象重新set进去
AopContext.setCurrentProxy(oldProxy);
}
}
}
}
比较重要的方法就是AopProxyUtils.completeProxiedInterfaces()
,该方法返回的接口实际上就是JDK代理所需要的接口。
在选择具体代理实现时,若选用JDK代理,要么实现过接口,要么本身就是一个接口,或者已经被JDK代理实现过。那么在completeProxiedInterfaces
方法中。
- 获取到目标类实现的所有接口;
- 为目标类添加一些其他接口:
2.1 SpringProxy:若未实现,则添加;
2.2 Advised:若配置isOpaque
为false,且未实现过,则添加;
2.3 DecoratingProxy:传入的decoratingProxy
为true,且未实现过,则添加;
综上所述,最终返回的接口列表:目标对象所有接口+上面提供的三个接口;
static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised, boolean decoratingProxy) {
//获取所有的接口
Class<?>[] specifiedInterfaces = advised.getProxiedInterfaces();
//若没有实现接口
if (specifiedInterfaces.length == 0) {
// No user-specified interfaces: check whether target class is an interface.
Class<?> targetClass = advised.getTargetClass();
if (targetClass != null) {
if (targetClass.isInterface()) {
advised.setInterfaces(targetClass);
}
else if (Proxy.isProxyClass(targetClass)) {
advised.setInterfaces(targetClass.getInterfaces());
}
specifiedInterfaces = advised.getProxiedInterfaces();
}
}
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
boolean addAdvised = !advised.isOpaque() && !advised.isInterfaceProxied(Advised.class);
boolean addDecoratingProxy = (decoratingProxy && !advised.isInterfaceProxied(DecoratingProxy.class));
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
}
if (addAdvised) {
nonUserIfcCount++;
}
if (addDecoratingProxy) {
nonUserIfcCount++;
}
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length + nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0, proxiedInterfaces, 0, specifiedInterfaces.length);
int index = specifiedInterfaces.length;
if (addSpringProxy) {
proxiedInterfaces[index] = SpringProxy.class;
index++;
}
if (addAdvised) {
proxiedInterfaces[index] = Advised.class;
index++;
}
if (addDecoratingProxy) {
proxiedInterfaces[index] = DecoratingProxy.class;
}
return proxiedInterfaces;
}
2. CGLIB代理
class CglibAopProxy implements AopProxy, Serializable {
//创建代理,就是使用CGLIB的方式,利用Enhancer创建了一个代理类
@Override
public Object getProxy() {
return getProxy(null);
}
//CGLIB重写了这两个方法
@Override
public boolean equals(Object other) {
return (this == other || (other instanceof CglibAopProxy &&
AopProxyUtils.equalsInProxy(this.advised, ((CglibAopProxy) other).advised)));
}
@Override
public int hashCode() {
return CglibAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();
}
//该类相当于JDK的invoke方法,所有被代理的类方法的调用,都会执行intercept方法。
//该类实现了MethodInterceptor接口
private static class DynamicAdvisedInterceptor implements MethodInterceptor, Serializable {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
@Nullable
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
Object oldProxy = null;
boolean setProxyContext = false;
Object target = null;
TargetSource targetSource = this.advised.getTargetSource();
try {
if (this.advised.exposeProxy) {
// Make invocation available if necessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// Get as late as possible to minimize the time we "own" the target, in case it comes from a pool...
target = targetSource.getTarget();
Class<?> targetClass = (target != null ? target.getClass() : null);
//拿到该方法匹配的所有的增强器
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
Object retVal;
//没有增强器,且该方法时public方法,直接调用目标方法
if (chain.isEmpty() && Modifier.isPublic(method.getModifiers())) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = methodProxy.invoke(target, argsToUse);
}
else {
//`CglibMethodInvocation`是`ReflectiveMethodInvocation`的子类 到这里就和JDK Proxy保持一致。即调用过滤器链
retVal = new CglibMethodInvocation(proxy, target, method, args, targetClass, chain, methodProxy).proceed();
}
retVal = processReturnType(proxy, target, method, retVal);
return retVal;
}
finally {
if (target != null && !targetSource.isStatic()) {
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
@Override
public boolean equals(Object other) {
return (this == other ||
(other instanceof DynamicAdvisedInterceptor &&
this.advised.equals(((DynamicAdvisedInterceptor) other).advised)));
}
/**
* CGLIB uses this to drive proxy creation.
*/
@Override
public int hashCode() {
return this.advised.hashCode();
}
}
}
- 和JDK代理一样,Object的方法,只有toString会被代理;
- 生成出来的代理对象,Spring会默认实现
SpringProxy、DecoratingProxy、Advised
接口; - 和JDK代理不同的是,若是equals、hashCode方法不会进入Intercept方法,而是在getCallBack那么就进行了特殊处理。
JdkDynamicAopProxy
入口方法时动态代理的invoke()
方法,而cglib使用的是DynamicAdvisedInterceptor.intercept()
方法。JdkDynamicAopProxy
使用ReflectiveMethodInvocation
执行过滤器链+目标方法。
而CglibAopProxy
使用CglibMethodInvocation
去执行过滤器链+目标方法。
但是它们都是ProxyMethodInvocation
的实现类。关系如下图所示:
即JDK代理和CGLIB代理都是通过ReflectiveMethodInvocation#proceed()
方法去执行目标方法。