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();
}
}
- SpringAop源码情操陶冶-JdkDynamicAopProxy
承接前文SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator,本文在前文的基础上稍微简单的分析默认情况下的AOP代理,即JDK静态代理 JdkDyna ...
- spring源码分析(二)Aop
创建日期:2016.08.19 修改日期:2016.08.20-2016.08.21 交流QQ:992591601 参考资料:<spring源码深度解析>.<spring技术内幕&g ...
- Spring源码学习(二)AOP
----ProxyFactoryBean这个类,这是AOP使用的入口---- AOP有些特有的概念,如:advisor.advice和pointcut等等,使用或配置起来有点绕,让人感觉有些距离感,其 ...
- Spring核心框架 - AOP的原理及源码解析
一.AOP的体系结构 如下图所示:(引自AOP联盟) 层次3语言和开发环境:基础是指待增加对象或者目标对象:切面通常包括对于基础的增加应用:配置是指AOP体系中提供的配置环境或者编织配置,通过该配置A ...
- AOP执行增强-Spring 源码系列(5)
AOP增强实现-Spring 源码系列(5) 目录: Ioc容器beanDefinition-Spring 源码(1) Ioc容器依赖注入-Spring 源码(2) Ioc容器BeanPostProc ...
- SpringAop源码情操陶冶-AspectJAwareAdvisorAutoProxyCreator
本文将对SpringAop中如何为AspectJ切面类创建自动代理的过程作下简单的分析,阅读本文前需要对AOP的Spring相关解析有所了解,具体可见Spring源码情操陶冶-AOP之ConfigBe ...
- Spring AOP高级——源码实现(3)AopProxy代理对象之JDK动态代理的创建过程
spring-aop-4.3.7.RELEASE 在<Spring AOP高级——源码实现(1)动态代理技术>中介绍了两种动态代理技术,当然在Spring AOP中代理对象的生成也是运用 ...
- 异步任务spring @Async注解源码解析
1.引子 开启异步任务使用方法: 1).方法上加@Async注解 2).启动类或者配置类上@EnableAsync 2.源码解析 虽然spring5已经出来了,但是我们还是使用的spring4,本文就 ...
- Spring提取@Transactional事务注解的源码解析
声明:本文是自己在学习spring注解事务处理源代码时所留下的笔记: 难免有错误,敬请读者谅解!!! 1.事务注解标签 <tx:annotation-driven /> 2.tx 命名空间 ...
随机推荐
- Java循环语句之 for
Java 的循环结构中除了 while 和 do...while 外,还有 for 循环,三种循环可以相互替换. 语法: 执行过程: <1>. 执行循环变量初始化部分,设置循环的初始状态, ...
- PHP Header 缓存 --- Header 参数说明
1. Accept:告诉WEB服务器自己接受什么介质类型,*/* 表示任何类型,type/* 表示该类型下的所有子类型,type/sub-type. 2. Accept-Charset: 浏览器申 ...
- hdu 4643(计算几何)
题意:容易理解 分析:切换的地点为两个基站所在直线的中垂线与两座城市所在直线的交点. 代码实现: #include <cstdio> #include <cmath> #inc ...
- angularJS+requireJS并集成karma测试实践
最近在为下一个项目做前端技术选型,Angular是必须要用的(BOSS指定,个人感觉也不错,开发效率会很高).由于需要加载的JS很多,所以打算看看angular和requirejs一起用会怎么样.在g ...
- Linux系统上安装Python
1.下载Python安装包,官网下:http://www.python.org/getit/ http://jingyan.baidu.com/article/eae07827f7f2d01fec54 ...
- 基于opencv的人脸检测的web应用
参考资料 https://github.com/bsdnoobz/web-based-face-detect http://opencv-code.com/projects/web-based-int ...
- eclipse quick diff功能
Eclipse文本编辑器和Java编辑器都提供了quick diff功能.这就使得你可以快速地识别出当前所编辑文件版本和该文件的参考版本之间的不同. 如果编辑器的quick diff功能没有启用,可以 ...
- 【DWT笔记】傅里叶变换与小波变换
[DWT笔记]傅里叶变换与小波变换 一.前言 我们经常接触到的信号,正弦信号,余弦信号,甚至是复杂的心电图.脑电图.地震波信号都是时域上的信号,我们也成为原始信号,但是通常情况下,我们在原始信号中得到 ...
- python中的多线程【转】
转载自: http://c4fun.cn/blog/2014/05/06/python-threading/ python中关于多线程的操作可以使用thread和threading模块来实现,其中th ...
- 机器学习&数据挖掘笔记(常见面试之机器学习算法思想简单梳理)
机器学习&数据挖掘笔记_16(常见面试之机器学习算法思想简单梳理) 作者:tornadomeet 出处:http://www.cnblogs.com/tornadomeet 前言: 找工作时( ...