一、创建代理准备工作
回顾之前的wrapIfNecessary方法,再获取到匹配的增强器后,Spring就会为拦截的bean创建代理对象:
//获取匹配的增强器
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, null);
//DO_NOT_PROXY = null
if (specificInterceptors != DO_NOT_PROXY) {
this.advisedBeans.put(cacheKey, Boolean.TRUE);
//创建代理
Object proxy = createProxy(
bean.getClass(), beanName, specificInterceptors, new SingletonTargetSource(bean));
this.proxyTypes.put(cacheKey, proxy.getClass());
return proxy;
}
创建代理createProxy:
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
//在bean对应的BeanDefinition中添加原Class对象属性(保存bean原本的Class)
if (this.beanFactory instanceof ConfigurableListableBeanFactory) {
AutoProxyUtils.exposeTargetClass((ConfigurableListableBeanFactory) this.beanFactory, beanName, beanClass);
}
ProxyFactory proxyFactory = new ProxyFactory();
//获取当前类中配置的属性
proxyFactory.copyFrom(this);
//检查proxyTargetClass属性
if (!proxyFactory.isProxyTargetClass()) {
//检查beanDefinitioin中是否包含preserveTargetClass属性,且属性为true
//设置是否使用CGLib进行代理
if (shouldProxyTargetClass(beanClass, beanName)) {
proxyFactory.setProxyTargetClass(true);
}
else {
//筛选代理接口并添加到proxyFactory
evaluateProxyInterfaces(beanClass, proxyFactory);
}
}
//获取增强器(包括前面筛选出来的增强器,以及通过setInterceptorNames中添加的通用增强器,默认为空)
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
//将所有增强器添加到proxyFactory
proxyFactory.addAdvisor(advisor);
}
//设置需要代理的bean对象信息
proxyFactory.setTargetSource(targetSource);
//模版方法,由子类定制化代理
customizeProxyFactory(proxyFactory);
//用来控制代理工程被配置后,是否还允许修改代理的配置,默认为false
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//创建代理对象
return proxyFactory.getProxy(getProxyClassLoader());
}
上面代理流程为:
- 在BeanDefinition中保存bean原Class对象,因为创建代理后,bean的class会被修改(Spring4中新加入的带你,Spring3中不包含)
- 创建ProxyFactory
- 设置属性
- 过滤目标bean的接口,并添加到ProxyFactory
- 获取增强器实例,添加到ProxyFactory中
- 创建代理
过滤接口
过滤接口中主要功能是,帮助判断是否使用JDK的动态代理来创建代理。因为JDK动态代理的条件是bean实现了接口,所以Spring会将目标bean实现的接口过滤后添加到ProxyFactory中,方便判断是否使用JDK动态代理,下面是evaluateProxyInterfaces实现:
protected void evaluateProxyInterfaces(Class<?> beanClass, ProxyFactory proxyFactory) {
//获取所有实现的接口
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, getProxyClassLoader());
boolean hasReasonableProxyInterface = false;
for (Class<?> ifc : targetInterfaces) {
//不是Spring内部回调用的接口 && 不是语言内部接口 && 接口定义了一个以上的方法
if (!isConfigurationCallbackInterface(ifc) && !isInternalLanguageInterface(ifc) &&
ifc.getMethods().length > 0) {
hasReasonableProxyInterface = true;
break;
}
}
//如果满足上面三个条件,才会将接口添加到proxyFactory
if (hasReasonableProxyInterface) {
// Must allow for introductions; can't just set interfaces to the target's interfaces only.
for (Class<?> ifc : targetInterfaces) {
proxyFactory.addInterface(ifc);
}
}
//条件不满足,缺少合适的接口,无法使用JDK动态代理,使用CGLib
else {
proxyFactory.setProxyTargetClass(true);
}
}
下面是过滤条件:
1.Spring内部接口
会排除掉InitializingBean、DisposableBean、Aware接口
protected boolean isConfigurationCallbackInterface(Class<?> ifc) {
return (InitializingBean.class == ifc || DisposableBean.class == ifc ||
ObjectUtils.containsElement(ifc.getInterfaces(), Aware.class));
}
2、是否是语言内部接口 isInternalLanguageInterface
protected boolean isInternalLanguageInterface(Class<?> ifc) {
return (ifc.getName().equals("groovy.lang.GroovyObject") ||
ifc.getName().endsWith(".cglib.proxy.Factory"));
}
其实就是比较类名
3、接口中是否定义了方法
二、创建代理
ProxyFactory.getProxy:
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
createAopProxy:
protected final synchronized AopProxy createAopProxy() {
//active会在在第一次创建代理后,设为true
if (!this.active) {
//设置active为true,并通知监听器(如果没有配置,为空)
activate();
}
//getAopProxyFactory会返回aopProxyFactory变量,默认实现为DefaultAopProxyFactory
return getAopProxyFactory().createAopProxy(this);
}
代码流程:
- 如果是第一次创建代理,会通知ProxyFactory中注册的监听器
- 获取类中定义的aopProxyFactory变量,默认实现为DefaultAopProxyFactory
- 通过DefaultAopProxyFactory创建代理对象(会传入当前对象,用于获取配置信息)
DefaultAopProxyFactory-->createAopProxy:
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config)) {
//代理目标bean的Class不能为空
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.");
}
//如果是接口 或者 Class类型为Proxy
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
Spring生成代理对象的方式有两种,JDK动态代理和CGLib,分别生成JdkDynamicAopProxy和ObjenesisCglibAopProxy,从上面代码可以看出Spring的判断条件:
- optimize:用来控制通过CGLib创建的代理是否使用激进的优化策略(该仅对CGLib有效)
- proxyTargetClass:当属性为true,使用CGLib,设置方式:<aop:aspectj-autoproxy proxy-target-class="true">。
- 是否存在代理接口(也就是前面过滤接口一节中,添加进去的接口)
- 如果目标类是接口的话,还是会使用JDK的方式进行代理
JDK动态代理与CGLib的区别:
- JDK只能针对实现了接口的类生成代理
- CGLib是针对类实现代理,主要通过生成目标类的子类,覆盖其中的方法来达到代理的目的。因此,目标类或方法不能被定义为final
三、获取代理对象
回顾之前getProxy创建代理的代码:
public Object getProxy(ClassLoader classLoader) {
return createAopProxy().getProxy(classLoader);
}
getAopProxy就是上一节中获取到的AopProxy实例:JdkDynamicAopProxy或ObjenesisCglibAopProxy,后面会调用其getProxy获取代理对象:
public Object getProxy(ClassLoader classLoader) {
//log...
//获取代理接口
Class<?>[] proxiedInterfaces = AopProxyUtils.completeProxiedInterfaces(this.advised, true);
//检查是否在接口中定义了equals或hashCode方法
findDefinedEqualsAndHashCodeMethods(proxiedInterfaces);
//创建代理对象
return Proxy.newProxyInstance(classLoader, proxiedInterfaces, this);
}
上面代码流程:
- 获取代理接口
- 检查是否在接口中定义了equals或hashCode方法
- 使用JDK动态代理Proxy.newProxyInstance创建代理对象
四、方法拦截过程
JDK生成代理对象需要调用return Proxy.newProxyInstance,并传入类加载器、代理接口、以及一个InvocationHandler实例。其中InvocationHandler的invoke方法定义了代理的流程。
上面代码中,传入的InvocationHandler是this,即JdkDynamicAopProxy,该类实现了InvocationHandler接口,下面是其invoke方法实现:
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 {
//如果接口中定义了equals或hashCode方法,则进行专门处理
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();
}
else if (method.getDeclaringClass() == DecoratingProxy.class) {
// There is only getDecoratedClass() declared -> dispatch to proxy config.
return AopProxyUtils.ultimateTargetClass(this.advised);
}
//opaque属性,表示是否禁止将代理对象转换为Advised对象,默认是false
//如果调用的方法来自Advised接口
else if (!this.advised.opaque && method.getDeclaringClass().isInterface() &&
method.getDeclaringClass().isAssignableFrom(Advised.class)) {
//通过反射Method.invoke,调用advised(传入的ProxyFactory实例,该类实现了Advised接口)对应的方法
return AopUtils.invokeJoinpointUsingReflection(this.advised, method, args);
}
Object retVal;
//为了解决目标对象内部的自我调用无法实施切面中的增强,需要暴露代理对象
if (this.advised.exposeProxy) {
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
// 获取目标对象信息
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
// 获取当前方法的拦截器链
List<Object> chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method, targetClass);
// 如果没有任何拦截器,则调用直接对原目标对象调用方法
if (chain.isEmpty()) {
Object[] argsToUse = AopProxyUtils.adaptArgumentsIfNecessary(method, args);
retVal = AopUtils.invokeJoinpointUsingReflection(target, method, argsToUse);
}
else {
// 将拦截器链封装到ReflectiveMethodInvocation,方便使用其proceed进行链式调用拦截器
invocation = new ReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
// 执行拦截器链
retVal = invocation.proceed();
}
// Massage return value if necessary.
Class<?> returnType = method.getReturnType();
if (retVal != null && retVal == target &&
returnType != Object.class && returnType.isInstance(proxy) &&
!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// 特殊情况:为了防止方法返回"return this",返回原目标对象,会将返回值替换为代理对象
retVal = proxy;
}
//如果返回类型是基本类型兵器,但是返回结果为null,抛出异常
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);
}
}
}
代码流程:
- 特殊方法的处理,包括equals、hashCode方法以及定义在Advised接口中的方法
- 获取方法匹配的增强器,并生成拦截器链并调用
- 对方法返回结果进行处理:如果返回“this”,即原目标对象,则会替换为返回代理对象;如果返回结果为null,但返回类型为基本数据类型(int、char等)则抛出异常
1、获取匹配的拦截器:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(Method method, Class<?> targetClass) {
//缓存的cacheKey,先尝试从缓存获取,不存在再从ProxyFactory中解析
MethodCacheKey cacheKey = new MethodCacheKey(method);
List<Object> cached = this.methodCache.get(cacheKey);
if (cached == null) {
//通过实例方法和ProxyFactory中保存的信息,解析出匹配的增强
cached = this.advisorChainFactory.getInterceptorsAndDynamicInterceptionAdvice(
this, method, targetClass);
this.methodCache.put(cacheKey, cached);
}
return cached;
}
方法匹配增强器的功能交由advisorChainFactory(DefaultAdvisorChainFactory)完成:
public List<Object> getInterceptorsAndDynamicInterceptionAdvice(
Advised config, Method method, Class<?> targetClass) {
List<Object> interceptorList = new ArrayList<Object>(config.getAdvisors().length);
Class<?> actualClass = (targetClass != null ? targetClass : method.getDeclaringClass());
//方法是否匹配引介增强
boolean hasIntroductions = hasMatchingIntroductions(config, actualClass);
AdvisorAdapterRegistry registry = GlobalAdvisorAdapterRegistry.getInstance();
//遍历增强器
for (Advisor advisor : config.getAdvisors()) {
//PointcutAdvisor类型的增强器
//通过@Aspect加入的增强器类型为InstantiationModelAwarePointcutAdvisorImpl,实现了PointcutAdvisor
if (advisor instanceof PointcutAdvisor) {
// Add it conditionally.
PointcutAdvisor pointcutAdvisor = (PointcutAdvisor) advisor;
if (config.isPreFiltered() || pointcutAdvisor.getPointcut().getClassFilter().matches(actualClass)) {
MethodInterceptor[] interceptors = registry.getInterceptors(advisor);
MethodMatcher mm = pointcutAdvisor.getPointcut().getMethodMatcher();
if (MethodMatchers.matches(mm, method, actualClass, hasIntroductions)) {
if (mm.isRuntime()) {
// Creating a new object instance in the getInterceptors() method
// isn't a problem as we normally cache created chains.
for (MethodInterceptor interceptor : interceptors) {
interceptorList.add(new InterceptorAndDynamicMethodMatcher(interceptor, mm));
}
}
else {
interceptorList.addAll(Arrays.asList(interceptors));
}
}
}
}
//对于引介增强的处理
else if (advisor instanceof IntroductionAdvisor) {
IntroductionAdvisor ia = (IntroductionAdvisor) advisor;
if (config.isPreFiltered() || ia.getClassFilter().matches(actualClass)) {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
else {
Interceptor[] interceptors = registry.getInterceptors(advisor);
interceptorList.addAll(Arrays.asList(interceptors));
}
}
return interceptorList;
}
上面代码首先会遍历拦截增强器,然后根据目标类和目标方法(引介增强外)匹配增强器,如果匹配的话,返回增强器包装的拦截器(Advice)
对于@Aspect注解配置类中,@Before、@After、@AfterThrowing配置的增强会被包装为AspectJMethodBeforeAdvice、AspectJAfterReturningAdvice、AspectJAfterThrowingAdvice等,在这一步骤中,这些Advice会分别被封装为MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor拦截器。
2、创建拦截器链并调用
Spring会在获取到方法匹配的拦截器后,将代理对象、目标对象、调用方法、参数、拦截器等信息封装到ReflectiveMethodInvocation中:
protected ReflectiveMethodInvocation(
Object proxy, Object target, Method method, Object[] arguments,
Class<?> targetClass, List<Object> interceptorsAndDynamicMethodMatchers) {
this.proxy = proxy;
this.target = target;
this.targetClass = targetClass;
this.method = BridgeMethodResolver.findBridgedMethod(method);
this.arguments = AopProxyUtils.adaptArgumentsIfNecessary(method, arguments);
this.interceptorsAndDynamicMethodMatchers = interceptorsAndDynamicMethodMatchers;
}
然后调用ReflectiveMethodInvocation的proceed方法:
public Object proceed() throws Throwable {
// 执行完所有增强后,执行切点方法
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {
return invokeJoinpoint();
}
//获取下一个拦截器
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {
//动态匹配
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;
if (dm.methodMatcher.matches(this.method, this.targetClass, this.arguments)) {
return dm.interceptor.invoke(this);
}
else {
//不匹配则不执行拦截器
return proceed();
}
}
else {
// 普通拦截器。比如:MethodBeforeAdviceInterceptor、AfterReturningAdviceInterceptor、ThrowsAdviceInterceptor
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
通过currentInterceptorIndex记录当前拦截器的索引,每调用一个拦截器就+1,再次调用proceed方法时就会获取下一个拦截器调用。
3、拦截器调用
在获取增强器的过程中,例如@Before注解标注的方法会被封装为AspectJMethodBeforeAdvice,然后会在 1.获取匹配的拦截器 过程中,会被包装为MethodInterceptor(MethodBeforeAdviceInterceptor),下面是Advice转换为MethodInterceptor的过程:
DefaultAdvisorAdapterRegistry.getInterceptors:
public MethodInterceptor[] getInterceptors(Advisor advisor) throws UnknownAdviceTypeException {
List<MethodInterceptor> interceptors = new ArrayList<MethodInterceptor>(3);
//获取Advice
Advice advice = advisor.getAdvice();
//如果Advice实例同时已经实现MethodInterceptor接口,则直接使用
if (advice instanceof MethodInterceptor) {
interceptors.add((MethodInterceptor) advice);
}
//需要使用适配器来转换Advice接口
for (AdvisorAdapter adapter : this.adapters) {
if (adapter.supportsAdvice(advice)) {
interceptors.add(adapter.getInterceptor(advisor));
}
}
if (interceptors.isEmpty()) {
throw new UnknownAdviceTypeException(advisor.getAdvice());
}
return interceptors.toArray(new MethodInterceptor[interceptors.size()]);
}
代码流程:
- 如果Advice增强已经实现了MethodInterceptor,则不需要转换,可以直接使用。例如:@After注解标注的增强方法会被表示为AspectJAfterAdvice,该类同时实现了Advice和MethodInterceptor接口,也就是已经在类中规定好了拦截的逻辑。
- Advice实现了没有同时实现MethodInterceptor,所以需要使用内置的适配器将Advice增强转换为MethodInterceptor拦截器。
a、内置的Advice适配器
在前面的代码中,将Advice转换为MethodInterceptor的工作是交给this.adapters来完成的,该变量定义如下;
private final List<AdvisorAdapter> adapters = new ArrayList<AdvisorAdapter>(3);
并且在DefaultAdvisorAdapterRegistry的构造函数中,对该变量进行了初始化填充:
public DefaultAdvisorAdapterRegistry() {
registerAdvisorAdapter(new MethodBeforeAdviceAdapter());
registerAdvisorAdapter(new AfterReturningAdviceAdapter());
registerAdvisorAdapter(new ThrowsAdviceAdapter());
}
可以看到,Spring实现会加入3个默认的是Advice适配器:MethodBeforeAdviceAdapter、AfterReturningAdviceAdapter、ThrowsAdviceAdapter。
这三个适配器通过support方法,验证是否是否支持传入的Advice对象,如果支持,会将Advice实例封装为对应的MethodInterceptor实例:
MethodBeforeAdviceAdapter:
class MethodBeforeAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof MethodBeforeAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
MethodBeforeAdvice advice = (MethodBeforeAdvice) advisor.getAdvice();
return new MethodBeforeAdviceInterceptor(advice);
}
}
AfterReturningAdviceAdapter:
class AfterReturningAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof AfterReturningAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
AfterReturningAdvice advice = (AfterReturningAdvice) advisor.getAdvice();
return new AfterReturningAdviceInterceptor(advice);
}
}
ThrowsAdviceAdapter:
class ThrowsAdviceAdapter implements AdvisorAdapter, Serializable {
@Override
public boolean supportsAdvice(Advice advice) {
return (advice instanceof ThrowsAdvice);
}
@Override
public MethodInterceptor getInterceptor(Advisor advisor) {
return new ThrowsAdviceInterceptor(advisor.getAdvice());
}
}
下面是对三种适配器的总结:
适配器 | 支持的Advice接口 | Advice实现类 | 对应注解 |
---|---|---|---|
MethodBeforeAdviceAdapter | MethodBeforeAdvice | AspectJMethodBeforeAdvice | @Before |
AfterReturningAdviceAdapter | AfterReturningAdvice | AspectJAfterReturningAdvice | @AfterReturning |
ThrowsAdviceAdapter | ThrowsAdvice | 无 | 无 |
下面再来总结一下通过注解配置的增强对应的拦截器:
注解 | Advice | MethodInterceptor |
---|---|---|
@Before | AspectJMethodBeforeAdvice | MethodBeforeAdviceInterceptor |
@After | AspectJAfterAdvice | AspectJAfterAdvice |
@AfterReturning | AspectJAfterReturningAdvice | AfterReturningAdviceInterceptor |
@AfterThrowing | AspectJAfterThrowingAdvice | AspectJAfterThrowingAdvice |
@Around | AspectJAroundAdvice | AspectJAroundAdvice |
b、拦截器调用
拦截器的类型有多中,下面我们分析由@Before注解添加的拦截器MethodBeforeAdviceInterceptor。
MethodBeforeAdviceInterceptor定义:
public class MethodBeforeAdviceInterceptor implements MethodInterceptor, Serializable {
private MethodBeforeAdvice advice;
/**
* 将传入的MethodBeforeAdvice封装为MethodBeforeAdviceInterceptor
* @param advice the MethodBeforeAdvice to wrap
*/
public MethodBeforeAdviceInterceptor(MethodBeforeAdvice advice) {
Assert.notNull(advice, "Advice must not be null");
this.advice = advice;
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
this.advice.before(mi.getMethod(), mi.getArguments(), mi.getThis() );
return mi.proceed();
}
}
从invoke方法中可以看到,拦截器会在调用真正方法前,调用MethodBeforeAdvice的before方法,在这一步,也就完成了方法的前置增强。
下面看一下AspectJMethodBeforeAdvice的before实现:
public void before(Method method, Object[] args, Object target) throws Throwable {
invokeAdviceMethod(getJoinPointMatch(), null, null);
}
protected Object invokeAdviceMethod(JoinPointMatch jpMatch, Object returnValue, Throwable ex) throws Throwable {
//将参数绑定后,传入invokeAdviceMethodWithGivenArgs方法执行
return invokeAdviceMethodWithGivenArgs(argBinding(getJoinPoint(), jpMatch, returnValue, ex));
}
invokeAdviceMethodWithGivenArgs:
protected Object invokeAdviceMethodWithGivenArgs(Object[] args) throws Throwable {
Object[] actualArgs = args;
//如果advice增强方法参数为空
if (this.aspectJAdviceMethod.getParameterTypes().length == 0) {
actualArgs = null;
}
try {
ReflectionUtils.makeAccessible(this.aspectJAdviceMethod);
// 通过反射,调用增强方法
return this.aspectJAdviceMethod.invoke(this.aspectInstanceFactory.getAspectInstance(), actualArgs);
}
catch (IllegalArgumentException ex) {
throw new AopInvocationException("Mismatch on arguments to advice method [" +
this.aspectJAdviceMethod + "]; pointcut expression [" +
this.pointcut.getPointcutExpression() + "]", ex);
}
catch (InvocationTargetException ex) {
throw ex.getTargetException();
}
}