Spring Aop原理之Advised接口
通过之前我们介绍的ProxyFactory
我们知道,Spring Aop是通过ProxyFactory
来创建代理对象的。ProxyFactory
在创建代理对象时会委托给DefaultAopProxyFactory.createAopProxy(AdvisedSupport config)
,DefaultAopProxyFactory
内部会分情况返回基于JDK的JdkDynamicAopProxy
或基于CGLIB的ObjenesisCglibAopProxy
,它俩都实现了Spring的AopProxy
接口。AopProxy
接口中只定义了一个方法,getProxy()
方法,Spring Aop创建的代理对象也就是该接口方法的返回结果。
我们先来看一下基于JDK代理的JdkDynamicAopProxy
的getProxy()的逻辑。
@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);
}
我们可以看到它最终是通过JDK的Proxy
来创建的代理,使用的InvocationHandler
实现类是它本身,而使用的接口是AopProxyUtils.completeProxiedInterfaces(this.advised)
的返回结果。而这个this.advised
对象是AdvisedSupport
类型,它是ProxyFactory
的父类(间接通过ProxyCreatorSupport
继承,ProxyFactory
的直接父类是ProxyCreatorSupport
,ProxyCreatorSupport
的父类是AdvisedSupport
),AdvisedSupport
的父类是ProxyConfig
,ProxyConfig
中包含创建代理对象时的一些配置项信息。以下是AopProxyUtils.completeProxiedInterfaces(this.advised)
的内部逻辑。
public static Class<?>[] completeProxiedInterfaces(AdvisedSupport advised) {
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 && targetClass.isInterface()) {
specifiedInterfaces = new Class<?>[] {targetClass};
}
}
boolean addSpringProxy = !advised.isInterfaceProxied(SpringProxy.class);
boolean addAdvised = !advised.isOpaque()
&& !advised.isInterfaceProxied(Advised.class);
int nonUserIfcCount = 0;
if (addSpringProxy) {
nonUserIfcCount++;
}
if (addAdvised) {
nonUserIfcCount++;
}
Class<?>[] proxiedInterfaces = new Class<?>[specifiedInterfaces.length
+ nonUserIfcCount];
System.arraycopy(specifiedInterfaces, 0,
proxiedInterfaces, 0, specifiedInterfaces.length);
if (addSpringProxy) {
proxiedInterfaces[specifiedInterfaces.length]
= SpringProxy.class;
}
if (addAdvised) {
proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class;
}
return proxiedInterfaces;
}
我们可以看到其会在!advised.isOpaque() && !advised.isInterfaceProxied(Advised.class)
返回true
的情况下加上本文的主角Advised
接口。isOpaque()
是ProxyConfig
中的一个方法,对应的是opaque
属性,表示是否禁止将代理对象转换为Advised
对象,默认是false
。!advised.isInterfaceProxied(Advised.class)
表示将要代理的目标对象类没有实现Advised
接口,对于我们自己应用的Class
来说,一般都不会自己去实现Advised
接口的,所以这个通常也是返回true
,所以通常创建Aop代理对象时是会创建包含Advised
接口的代理对象的,即上述的proxiedInterfaces[proxiedInterfaces.length - 1] = Advised.class
会被执行。
前面我们已经提到,JdkDynamicAopProxy
创建代理对象应用的InvocationHandler
是其自身,所以我们在调用JdkDynamicAopProxy
创建的代理对象的任何方法时都将调用JdkDynamicAopProxy
实现的InvocationHandler
接口的invoke(Object proxy, Method method, Object[] args)
方法。该方法实现如下:
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);
}
}
}
其中关于Advised
接口方法调用最核心的一句是如下这句。我们可以看到,当我们调用的目标方法是定义自Advised
接口时,对应方法的调用将委托给AopUtils.invokeJoinpointUsingReflection(this.advised, method, args)
,invokeJoinpointUsingReflection
方法的逻辑比较简单,是通过Java反射来调用目标方法。在这里invokeJoinpointUsingReflection
传递的目标对象正是AdvisedSupport
类型的this.advised
对象。
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);
}
AdvisedSupport
类是实现了Advised
接口的,所以Spring Aop创建了基于Advised
接口的代理对象后在调用Advised
接口方法时可以把它委托给AdvisedSupport
。而我们知道Spring Aop代理对象的创建正是基于AdvisedSupport
的配置进行的(配置项主要都定义在AdvisedSupport
的父类ProxyConfig
类中)。创建代理对象时应用AdvisedSupport
,调用Advised
接口方法也用同一个实现了Advised
接口的AdvisedSupport
对象,所以这个过程在Spring Aop内部就可以很好的衔接。接着我们来看一下Advised
接口的定义。
public interface Advised extends TargetClassAware {
boolean isFrozen();
boolean isProxyTargetClass();
Class<?>[] getProxiedInterfaces();
boolean isInterfaceProxied(Class<?> intf);
void setTargetSource(TargetSource targetSource);
TargetSource getTargetSource();
void setExposeProxy(boolean exposeProxy);
boolean isExposeProxy();
void setPreFiltered(boolean preFiltered);
boolean isPreFiltered();
Advisor[] getAdvisors();
void addAdvisor(Advisor advisor) throws AopConfigException;
void addAdvisor(int pos, Advisor advisor) throws AopConfigException;
boolean removeAdvisor(Advisor advisor);
void removeAdvisor(int index) throws AopConfigException;
int indexOf(Advisor advisor);
boolean replaceAdvisor(Advisor a, Advisor b) throws AopConfigException;
void addAdvice(Advice advice) throws AopConfigException;
void addAdvice(int pos, Advice advice) throws AopConfigException;
boolean removeAdvice(Advice advice);
int indexOf(Advice advice);
String toProxyConfigString();
}
Advised
接口中定义的方法还是非常多的,通过它我们可以在运行时了解我们的代理对象是基于CGLIB的还是基于JDK代理的;可以了解我们的代理对应应用了哪些Advisor
;也可以在运行时给我们的代理对象添加和删除Advisor/Advise
。本文旨在描述Spring Aop在创建代理对象时是如何基于Advised
接口创建代理的,以及我们能够应用Advised
接口做哪些事。文中应用的是Spring创建基于JDK代理对象的过程为示例讲解的,其实基于CGLIB的代理也是一样的。关于CGLIB的代理过程、本文中描述的一些核心类以及本文的核心——Advised
接口的接口方法说明等请有兴趣的朋友参考Spring的API文档和相关的源代码。
(注:本文是基于Spring4.1.0所写,Elim写于2017年5月15日)
相关推荐
最后,本文的目标是从实现的角度来认识 SpringAOP 框架,观察的角度是从外部接口、内部实现、组成部分、执行过程四个方面来认识 SpringAOP 框架。本文的风格是首先列出 AOP 的基本概念,然后介绍框架所涉及到的核心...
标签“源码”意味着这篇博客可能深入解析了Spring AOP的内部工作机制,包括如何通过代理机制实现切面的织入,以及Spring AOP的相关核心类如`Advised`、`ProxyFactoryBean`、`DefaultAdvisorAdapterRegistry`等。...
首先,我们需要知道Spring AOP的核心概念——切面(Aspect)、通知(Advice)、连接点(Join Point)、切入点(Pointcut)和代理(Proxy)。切面是封装了特定关注点的模块,如日志或事务管理。通知是在特定连接点...
Spring 4 框架是Java开发中广泛使用的轻量级框架,它的核心特性包括依赖注入(DI)、面向切面编程(AOP)以及一系列的其他功能,如数据访问、Web MVC、测试等。AOP作为Spring的重要组成部分,允许开发者在不修改原有...
在阅读源码时,我们可以深入了解Spring AOP的代理实现,例如`Advised`接口和`AopProxy`接口,以及`DefaultAdvisorAdapterRegistry`、`ProxyFactoryBean`等类的作用。理解这些内部机制有助于我们更好地利用Spring AOP...
**Spring AOP 源码解析** Spring AOP(Aspect Oriented Programming,面向切面编程)是...通过阅读和理解Spring AOP的源码,我们可以更深入地了解其工作原理,从而更好地利用这一强大功能来设计和实现解耦的系统。
- **JDK动态代理**:如果目标对象实现了接口,那么Spring AOP会使用JDK动态代理来创建一个实现了相同接口的新对象。这个代理对象能够在方法调用前后执行额外的操作。 - **CGLIB代理**:如果目标对象没有实现接口,...
在Spring框架中,动态代理是实现AOP(面向切面编程)的核心技术之一。它允许我们在不修改原有代码的情况下,为方法添加额外的功能,如事务管理、日志记录等。本篇文章将深入探讨Spring中的动态代理机制,以及它是...
在Spring AOP中,拦截器调用的实现是通过动态代理机制来完成的,主要涉及到JDK的Proxy类和InvocationHandler接口。本文将详细解析Spring AOP如何利用这两个组件来实现拦截器链的调用。 首先,Spring在生成代理对象...
Spring AOP,全称Aspect-Oriented Programming(面向切面编程),是Spring框架的重要组成部分,它为Java应用程序提供了声明式的企业级服务,如事务管理、性能监控等。本篇文章将深入探讨Spring AOP的应用实例以及...
本压缩包“Spring源码解析”提供了对Spring框架核心组件——IOC(Inversion of Control,控制反转)、AOP(Aspect Oriented Programming,面向切面编程)以及Transaction(事务管理)的源码分析,帮助开发者更全面地...
- `getTargetSource(Advised advised)`:此方法接收一个`Advised`对象,`Advised`接口是所有可以提供配置信息的代理对象的超接口。通过这个方法,我们可以获取到代理对象的目标源(`TargetSource`),它封装了目标...
- `org.springframework.aop.framework.Advised`:这个接口定义了对代理对象进行配置的方法,如设置通知(advisors)和代理类型等。 - `org.aopalliance.intercept.MethodInterceptor`:这是AOP联盟定义的拦截器接口...
在这个包中,我们能找到`spring-context`, `spring-core`, `spring-web`, `spring-aop`等模块,每个模块都对应着Spring框架的一个特定部分,例如`spring-context`是Spring应用上下文,负责环境配置和bean的生命周期...
源码学习是提升编程技能的重要途径,尤其是在理解复杂框架如Spring的工作原理时。本笔记旨在深入解析Spring的高级源码,帮助程序员从应用层面过渡到源码级的理解。 Spring的核心组件包括Bean容器、AOP代理、数据...
`org.springframework.aop`包下包含了AOP的核心实现,如`Advised`接口和`ProxyFactoryBean`类。 二、数据访问支持 1. **JDBC抽象层**:Spring提供了对JDBC的简化封装,通过`JdbcTemplate`和`SimpleJdbcTemplate`,...
`Advised`接口和`ProxyFactoryBean`等类是理解AOP实现的关键。 Spring MVC是Spring框架中用于构建Web应用程序的部分。它遵循MVC(Model-View-Controller)架构模式,解耦了业务逻辑、数据和用户界面。在`org.spring...
`AspectJAutoProxyCreator`和`Advised`接口是实现AOP的关键。 3. MVC框架:Spring MVC为构建Web应用提供了模型-视图-控制器架构。`DispatcherServlet`是入口点,`HandlerMapping`和`HandlerAdapter`负责映射请求到...
`org.springframework.aop`包下的类和接口,如`Advised`、`Advisor`和`Pointcut`,是理解AOP的关键。`ProxyFactoryBean`和`AspectJAutoProxyCreator`等类用于生成和管理代理对象。 5. 事务管理实现 Spring提供了...