JdkDynamicAopProxy源码

JdkDynamicAopProxy是通过接口实现动态代理类,主要方法是getProxy(ClassLoader classLoader), 代理类生成之后再调用目标方法时就会调用invoke方法。


package org.springframework.aop.framework;

import java.io.Serializable;

import java.lang.reflect.InvocationHandler;

import java.lang.reflect.Method;

import java.lang.reflect.Proxy;

import java.util.List;

import org.aopalliance.intercept.MethodInvocation;

import org.apache.commons.logging.Log;

import org.apache.commons.logging.LogFactory;

import org.springframework.aop.AopInvocationException;

import org.springframework.aop.RawTargetAccess;

import org.springframework.aop.TargetSource;

import org.springframework.aop.support.AopUtils;

import org.springframework.util.Assert;

import org.springframework.util.ClassUtils;

/**

* JDK-based {@link AopProxy} implementation for the Spring AOP framework,

* based on JDK {@link java.lang.reflect.Proxy dynamic proxies}.

*

* <p>Creates a dynamic proxy, implementing the interfaces exposed by

* the AopProxy. Dynamic proxies <i>cannot</i> be used to proxy methods

* defined in classes, rather than interfaces.

*

* <p>Objects of this type should be obtained through proxy factories,

* configured by an {@link AdvisedSupport} class. This class is internal

* to Spring‘s AOP framework and need not be used directly by client code.

*

* <p>Proxies created using this class will be thread-safe if the

* underlying (target) class is thread-safe.

*

* <p>Proxies are serializable so long as all Advisors (including Advices

* and Pointcuts) and the TargetSource are serializable.

*

* @author Rod Johnson

* @author Juergen Hoeller

* @author Rob Harrop

* @author Dave Syer

* @see java.lang.reflect.Proxy

* @see AdvisedSupport

* @see ProxyFactory

*/

final class JdkDynamicAopProxy implements AopProxy, InvocationHandler, Serializable {

/** use serialVersionUID from Spring 1.2 for interoperability */

private static final long serialVersionUID = 5531744639992436476L;

/*

* NOTE: We could avoid the code duplication between this class and the CGLIB

* proxies by refactoring "invoke" into a template method. However, this approach

* adds at least 10% performance overhead versus a copy-paste solution, so we sacrifice

* elegance for performance. (We have a good test suite to ensure that the different

* proxies behave the same :-)

* This way, we can also more easily take advantage of minor optimizations in each class.

*/

/** We use a static Log to avoid serialization issues */

private static final Log logger = LogFactory.getLog(JdkDynamicAopProxy.class);

/** Config used to configure this proxy */

private final AdvisedSupport advised;

/**

* Is the {@link #equals} method defined on the proxied interfaces?

*/

private boolean equalsDefined;

/**

* Is the {@link #hashCode} method defined on the proxied interfaces?

*/

private boolean hashCodeDefined;

/**

* Construct a new JdkDynamicAopProxy for the given AOP configuration.

* @param config the AOP configuration as AdvisedSupport object

* @throws AopConfigException if the config is invalid. We try to throw an informative

* exception in this case, rather than let a mysterious failure happen later.

*/

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());

}

@Override

public Object getProxy(ClassLoader classLoader) {

if (logger.isDebugEnabled()) {

logger.debug("Creating JDK dynamic proxy: target source is " + this.advised.getTargetSource());

}

Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised);

findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);

return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);

}

/**

* Finds any {@link #equals} or {@link #hashCode} method that may be defined

* on the supplied set of interfaces.

* @param proxiedInterfaces the interfaces to introspect

*/

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;

}

}

}

}

/**

* Implementation of {@code InvocationHandler.invoke}.

* <p>Callers will see exactly the exception thrown by the target,

* unless a hook method throws an exception.

*/

@Override

public Object  invoke(Object proxy, Method method, Object[] args) throws Throwable {

MethodInvocation invocation;

Object oldProxy = null;

boolean setProxyContext = false;

TargetSource targetSource = this.advised.targetSource;

Class<?> targetClass = null;

Object target = null;

try {

if (!this.equalsDefined && AopUtils.isEqualsMethod(method)) {

// The target does not implement the equals(Object) method itself.

return equals(args[0]);

}

if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)) {

// The target does not implement the hashCode() method itself.

return hashCode();

}

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;

if (this.advised.exposeProxy) {

// Make invocation available if necessary.

oldProxy = AopContext.setCurrentProxy(proxy);

setProxyContext = true;

}

// May be null. Get as late as possible to minimize the time we "own" the target,

// in case it comes from a pool.

target = targetSource.getTarget();

if (target != null) {

targetClass = target.getClass();

}

// Get the interception chain for this method.

List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);

// Check whether we have any advice. If we don‘t, we can fallback on direct

// reflective invocation of the target, and avoid creating a MethodInvocation.

if (chain.isEmpty()) {

// We can skip creating a MethodInvocation: just invoke the target directly

// Note that the final invoker must be an InvokerInterceptor so we know it does

// nothing but a reflective operation on the target, and no hot swapping or fancy proxying.

retVal = AopUtils.invokeJoinpointUsingReflection(target, method, args);

}

else {

// We need to create a method invocation...

invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);

// Proceed to the joinpoint through the interceptor chain.

retVal = invocation.proceed();

}

// Massage return value if necessary.

Class<?> returnType = method.getReturnType();

if (retVal != null && retVal == target && returnType.isInstance(proxy) &&

!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {

// Special case: it returned "this" and the return type of the method

// is type-compatible. Note that we can‘t help if the target sets

// a reference to itself in another returned object.

retVal = proxy;

}

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) {

// Restore old proxy.

AopContext.setCurrentProxy(oldProxy);

}

}

}

/**

* Equality means interfaces, advisors and TargetSource are equal.

* <p>The compared object may be a JdkDynamicAopProxy instance itself

* or a dynamic proxy wrapping a JdkDynamicAopProxy instance.

*/

@Override

public boolean equals(Object other) {

if (other == this) {

return true;

}

if (other == null) {

return false;

}

JdkDynamicAopProxy otherProxy;

if (other instanceof JdkDynamicAopProxy) {

otherProxy = (JdkDynamicAopProxy) other;

}

else if (Proxy.isProxyClass(other.getClass())) {

InvocationHandler ih = Proxy.getInvocationHandler(other);

if (!(ih instanceof JdkDynamicAopProxy)) {

return false;

}

otherProxy = (JdkDynamicAopProxy) ih;

}

else {

// Not a valid comparison...

return false;

}

// If we get here, otherProxy is the other AopProxy.

return AopProxyUtils.equalsInProxy(this.advised, otherProxy.advised);

}

/**

* Proxy uses the hash code of the TargetSource.

*/

@Override

public int hashCode() {

return JdkDynamicAopProxy.class.hashCode() * 13 + this.advised.getTargetSource().hashCode();

}

}

时间: 2024-08-14 17:38:58

JdkDynamicAopProxy源码的相关文章

Spring源码学习(二)AOP

----ProxyFactoryBean这个类,这是AOP使用的入口---- AOP有些特有的概念,如:advisor.advice和pointcut等等,使用或配置起来有点绕,让人感觉有些距离感,其实它的实现就是一组标准的设计模式的组合使用:Factory.Proxy.Chain of Responsibility,只要搞清楚这几个设计模式,读AOP的源码是比较容易的. 首先看看ProxyFactoryBean这个类,这是AOP使用的入口,从AOP拿到的bean object就是ProxyFa

Spring核心框架 - AOP的原理及源码解析

一.AOP的体系结构 如下图所示:(引自AOP联盟) 层次3语言和开发环境:基础是指待增加对象或者目标对象:切面通常包括对于基础的增加应用:配置是指AOP体系中提供的配置环境或者编织配置,通过该配置AOP将基础和切面结合起来,从而完成切面对目标对象的编织实现. 层次2面向方面系统:配置模型,逻辑配置和AOP模型是为上策的语言和开发环境提供支持的,主要功能是将需要增强的目标对象.切面和配置使用AOP的API转换.抽象.封装成面向方面中的逻辑模型. 层次1底层编织实现模块:主要是将面向方面系统抽象封

AOP执行增强-Spring 源码系列(5)

AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProcessor-Spring 源码(3) 事件机制-Spring 源码(4) AOP执行增强-Spring 源码系列(5) AOP的核心就是个动态代理,Spring进行了大量抽象和封装形成一个方便上层使用的基础模块. 而动态代理的两种实现都在上一篇中提供了代码 直接ProxyFactoryBean入手来

Spring AOP介绍及源码分析

一.AOP介绍 举个例子来说明一下吧!现在系统中有很多的业务方法,如上传产品信息.修改产品信息.发布公司库等:现在需要对这些方法的执行做性能监控,看每个业务方法的执行时间:在不改变原业务代码的基础上,也许我们会这么做: Offer接口: Offer实现: Offer代理: 我们要通过下面的方式来使用: 上面的例子的输出为: 上面的例子中,OfferProxy实现了IOffer,而所有的业务实现均委托给其成员offer:可以想像,这应该就是最简单的AOP的实现了:但这种方式会存在一个问题:如果有非

spring源码剖析(六)AOP实现原理剖析

Spring的AOP实现原理,酝酿了一些日子,写博客之前信心不是很足,所以重新阅读了一边AOP的实现核心代码,而且又从网上找了一些Spring Aop剖析的例子,但是发现挂羊头买狗肉的太多,标题高大上,内容却大部分都是比较浅显的一些介绍,可能也是由于比较少人阅读这部分的核心代码逻辑把,然后写这部分介绍的人估计也是少之又少,不过说实话,Spring Aop的核心原理实现介绍确实不太好写,里面涉及的类之间的调用还是蛮多的,关系图画的太细的画也很难画,而且最重要的一点就是,如果对AOP的概念以及spr

Spring源码学习笔记(7)

Spring源码学习笔记(七) 前言-- 最近花了些时间看了<Spring源码深度解析>这本书,算是入门了Spring的源码吧.打算写下系列文章,回忆一下书的内容,总结代码的运行流程.推荐那些和我一样没接触过SSH框架源码又想学习的,阅读郝佳编著的<Spring源码深度解析>这本书,会是个很好的入门 写前说句话, 开篇不尴尬 ---- 接下的这一篇当中, 我们将来回顾 Spring 中 AOP 功能的实现流程.  早上精力充沛, 开始新一天的学习 \(^o^)/~ 接触过 Spri

Spring框架AOP源码剖析

今天我要和大家分享的是 AOP(Aspect-Oriented Programming)这个东西的源码剖析,作为多年的开发者,想必大家在面试的时候都被问过,你知道Spring框架AOP的底层实现机制吗,这可是很简单的噢,我们会说,如果某个类有接口就使用JDK动态代理,没有接口就用CGLIB动态代理,并且Spring也提供了可配置开关,不管有无接口都一律使用CGLIB动态代理,例如 <aop:aspectj-autoproxy proxy-target-class="true"/&

spring4.0源码分析━━━(AOP实现)

AOP的概念 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面).这就让一些问题很简单化了,例如:开始我们实现了一些逻辑并上线了,现在客户又来了一个新的需求.要在每次交易之前统计下,或者记录下他们的交易简单资料.而你发现你其他模块可能正好有这部分的功能.那AOP就可以用得上了,使用AOP就可以在不修改源代码的情况下新增这些功能.就是在交易前这个切面,新装你的一些功能.这有点像拦截器和Filter.其实都是一个原理.前面说了解析xml和Bean

异步任务spring @Async注解源码解析

1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就根据spring-context-4.3.14.RELEASE.jar来分析源码. 2.1.@Async org.springframework.scheduling.annotation.Async 源码注释翻译: 1 /** 2 * Annotation that marks a method