如果需要在Spring中使用AOP是非常簡單的,只需要在Bean上加上@AspectJ,在方法上加@PointCut、@Before等註解就可以實現你想要的邏輯,最後在XML配置文件中加入<aop:aspectj-autoproxy>
即可。
那麼Spring是如何實現的呢?
動態AOP標籤
我們從AopNamespaceHandler中的init()方法開始分析:
1.配置文件中在遇到aspectj-autoproxy標籤的時候我們會採用AspectJAutoProxyBeanDefinitionParser解析器
2.進入AspectJAutoProxyBeanDefinitionParser的parse方法,它將請求給了AopNamespaceUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary去處理
3.registerAspectJAnnotationAutoProxyCreatorIfNecessary方法中,先調用AopConfigUtils的registerAspectJAnnotationAutoProxyCreatorIfNecessary方法完成註冊或者升級AnnotationAwareAspectJAutoProxyCreator類。對於AOP的實現,基本是靠AnnotationAwareAspectJAutoProxyCreator去完成的,它可以根據@point註解定義的切點來代理相匹配的bean。
4.接下來會調用useClassProxyingIfNecessary() 處理proxy-target-class以及expose-proxy屬性
5.最後的調用registerComponentIfNecessary 方法,註冊組建並且通知便於監聽器做進一步處理。
2.創建AOP代理
AOP主要是依靠AnnotationAwareAspectJAutoProxyCreator的實現的。那麼AnnotationAwareAspectJAutoProxyCreator是如何完成的?
AnnotationAwareAspectJAutoProxyCreator的層次結構:
AnnotationAwareAspectJAutoProxyCreator實現了BeanPostProcessor接口,那就意味着這個類在spring加載實例化前會調用postProcessAfterInitialization方法。
public Object <strong>postProcessAfterInitialization</strong>(Object bean, String beanName) throws BeansException {
if (bean != null) {
Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.containsKey(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
邏輯:
1.根據bean的class和name生成一個key。
2.如果適合代理就執行wrapIfNecessary(bean, beanName, cacheKey)。
protected Object wrapIfNecessary(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.containsKey(beanName)) {
return bean;
}
if (Boolean.FALSE.equals(this.advisedBeans.get(cacheKey))) {
return bean;
}
if (isInfrastructureClass(bean.getClass()) || shouldSkip(bean.getClass(), beanName)) {
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
Object[] specificInterceptors = getAdvicesAndAdvisorsForBean(bean.getClass(), beanName, 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;
}
this.advisedBeans.put(cacheKey, Boolean.FALSE);
return bean;
}
邏輯:
1.如果以及處理過直接返回bean
2.不需要advisor返回bean
3.如果是基類或者說不需要自動代理返回bean。
4.獲得此類的advisor
5.創建代理
2.1 getAdvicesAndAdvisorsForBean
getAdvicesAndAdvisorsForBean主要邏輯由findEligibleAdvisors實現
protected List<Advisor> findEligibleAdvisors(Class beanClass, String beanName) {
2 List<Advisor> candidateAdvisors = findCandidateAdvisors();
3 List<Advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
4 extendAdvisors(eligibleAdvisors);
5 if (!eligibleAdvisors.isEmpty()) {
6 eligibleAdvisors = sortAdvisors(eligibleAdvisors);
7 }
8 return eligibleAdvisors;
9 }
findEligibleAdvisors實現邏輯:
1.findCandidateAdvisors找到所有的Advisors
2.findAdvisorsThatCanApply找到匹配當前bean的Advisors。
findCandidateAdvisors源碼邏輯:
1.獲得beanFactory中註冊所有的BeanName
2.遍歷所有BeanName,找出有@AspectJ的類
3.對有@AspectJ的類提取advisor
4.將提取出的結果放入緩存。
findAdvisorsThatCanApply源碼邏輯:
從findCandidateAdvisors獲得的advisor中尋找適合當前class的advisor。
2.2 createProxy
protected Object createProxy(
Class<?> beanClass, String beanName, Object[] specificInterceptors, TargetSource targetSource) {
ProxyFactory proxyFactory = new ProxyFactory();
// Copy our properties (proxyTargetClass etc) inherited from ProxyConfig.
proxyFactory.copyFrom(this);
if (!shouldProxyTargetClass(beanClass, beanName)) {
// Must allow for introductions; can't just set interfaces to
// the target's interfaces only.
Class<?>[] targetInterfaces = ClassUtils.getAllInterfacesForClass(beanClass, this.proxyClassLoader);
for (Class<?> targetInterface : targetInterfaces) {
proxyFactory.addInterface(targetInterface);
}
}
Advisor[] advisors = buildAdvisors(beanName, specificInterceptors);
for (Advisor advisor : advisors) {
proxyFactory.addAdvisor(advisor);
}
proxyFactory.<strong>setTargetSource</strong>(targetSource);
customizeProxyFactory(proxyFactory);
proxyFactory.setFrozen(this.freezeProxy);
if (advisorsPreFiltered()) {
proxyFactory.setPreFiltered(true);
}
//實現核心方法
return proxyFactory.getProxy(this.proxyClassLoader);
}
通過上面的源碼我們可以知道,對於代理的創建,Springle交給了proxyFactory的getProxy方法去完成,而之前的所有主要是爲proxyFactory做了初始準備而已。
2.2.1 ProxyFactory.getProxy(classLoader)
public object getProxy(ClassLoader classLoader){
return createAopProxy().getProxy(classLoader);
}
createAopProxy創建代理:
protected final synchronized AopProxy createAopProxy(){
if(!this.active){activate();}
return getAopProxyFactory().createAopProxy(this);
}
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
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.");
}
if (targetClass.isInterface()) {
return new JdkDynamicAopProxy(config);
}
return CglibProxyFactory.createCglibProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
上述代碼中的if判斷主要是對代理的選擇,使用JDK或者CGLIB實現代理,選擇完以後就創建了代理。
- **optimize:**CGLIB創建的代理是否使用激進策略。
- proxyTargetClass:當XML配置文件設置了
<aop:aspectj-autoproxy proxy-target-class="true"/>
時爲true,表示使用CGLIB - hasNoUserSuppliedProxyInterfaces:是否存在代理接口。
獲得代理
我們以使用JDK獲得代理做一下分析:
使用JDK方式最關鍵兩個方法:invoke和getProxy。
getProxy:獲得代理對象。
invoke:執行被代理對象的方法。
我們看一下JdkDynamicAopProxy的核心代碼invoke方法:
public Object invoke(Object proxy, Method method, Object[] args) throwsThrowable {
MethodInvocation invocation = null;
Object oldProxy = null;
boolean setProxyContext = false;
TargetSource targetSource = this.advised.targetSource;
Class targetClass = null;
Object target = null;
try {
//eqauls()方法,具目標對象未實現此方法
if (!this.equalsDefined && AopUtils.isEqualsMethod(method)){
return (equals(args[0])? Boolean.TRUE : Boolean.FALSE);
}
//hashCode()方法,具目標對象未實現此方法
if (!this.hashCodeDefined && AopUtils.isHashCodeMethod(method)){
return newInteger(hashCode());
}
//Advised接口或者其父接口中定義的方法,直接反射調用,不應用通知
if (!this.advised.opaque &&method.getDeclaringClass().isInterface()
&&method.getDeclaringClass().isAssignableFrom(Advised.class)) {
// Service invocations onProxyConfig with the proxy config...
return AopUtils.invokeJoinpointUsingReflection(this.advised,method, args);
}
Object retVal = null;
if (this.advised.exposeProxy) {
// Make invocation available ifnecessary.
oldProxy = AopContext.setCurrentProxy(proxy);
setProxyContext = true;
}
//獲得目標對象的類
target = targetSource.getTarget();
if (target != null) {
targetClass = target.getClass();
}
//獲取當前方法的攔截鏈
List chain = this.advised.getInterceptorsAndDynamicInterceptionAdvice(method,targetClass);
//如果沒有可以應用到此方法的通知(Interceptor),此直接反射調用 method.invoke(target, args)
if (chain.isEmpty()) {
retVal = AopUtils.invokeJoinpointUsingReflection(target,method, args);
} else {
//創建MethodInvocation,封裝攔截器鏈
invocation = newReflectiveMethodInvocation(proxy, target, method, args, targetClass, chain);
retVal = invocation.proceed();
}
// Massage return value if necessary.
if (retVal != null && retVal == target &&method.getReturnType().isInstance(proxy)
&&!RawTargetAccess.class.isAssignableFrom(method.getDeclaringClass())) {
// Special case: it returned"this" and the return type of the method
// is type-compatible. Notethat we can't help if the target sets
// a reference to itself inanother returned object.
retVal = proxy;
}
return retVal;
} finally {
if (target != null && !targetSource.isStatic()) {
// Must have come fromTargetSource.
targetSource.releaseTarget(target);
}
if (setProxyContext) {
// Restore old proxy.
AopContext.setCurrentProxy(oldProxy);
}
}
}
1)獲取攔截器:getInterceptorsAndDynamicInterceptionAdvice
2)判斷攔截器鏈是否爲空,如果是空的話直接調用切點方法
3)如果攔截器不爲空的話那麼便創建ReflectiveMethodInvocation類,把攔截器方法都封裝在裏面
4)對攔截器鏈中的攔截器逐一調用:invocation.proceed()
看一下proceed方法:
public Object proceed() throws Throwable {
// We start with an index of -1and increment early.
if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size()- 1) {
//如果Interceptor執行完了,則執行joinPoint
return invokeJoinpoint();
}
//獲得下一個攔截器interceptor
Object interceptorOrInterceptionAdvice =
this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);
//如果要動態匹配joinPoint
if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher){
InterceptorAndDynamicMethodMatcher dm =
(InterceptorAndDynamicMethodMatcher)interceptorOrInterceptionAdvice;
//動態匹配:運行時參數是否滿足匹配條件
if (dm.methodMatcher.matches(this.method, this.targetClass,this.arguments)) {
//執行當前Intercetpor
returndm.interceptor.invoke(this);
}
else {
//動態匹配失敗時,略過當前Intercetpor,調用下一個Interceptor
return proceed();
}
}
else {
//對於普通攔截器
//執行當前Intercetpor
return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);
}
}
ReflectiveMethodInvocation中維護了攔截器調用的計數器,用來記錄當前調用鏈接的位置,使得可以有序的對攔截器逐一調用。
實現Aop自動代理總結:
1.<aop:aspectj-autoproxy/>
解析註冊AnnotationAwareAspectJAutoProxyCreator類
2.AnnotationAwareAspectJAutoProxyCreator完成動態代理
AnnotationAwareAspectJAutoProxyCreator完成動態代理實現邏輯:
2.1.執行postProcessAfterInitialization()
———–如果適合代理就執行wrapIfNecessary()方法。
2.1.1wrapIfNecessary()實現邏輯:
1.判斷是否需要生成代理
2.如果需要則調用getAdvicesAndAdvisorsForBean()方法獲得當前類的advisor
3調用createProxy()創建代理。
2.1.1.2getAdvicesAndAdvisorsForBean()邏輯:
主要交給findEligibleAdvisors,實現邏輯:
—-1.findCandidateAdvisors找到所有的Advisors
—-2.findAdvisorsThatCanApply找到匹配當前bean的Advisors。
findCandidateAdvisors源碼邏輯:
—-1.獲得beanFactory中註冊所有的BeanName
—-2.遍歷所有BeanName,找出有@AspectJ的類
—-3.對有@AspectJ的類提取advisor
—-4.將提取出的結果放入緩存。
findAdvisorsThatCanApply源碼邏輯:
—-從findCandidateAdvisors獲得的advisor中尋找適合當前class的advisor。
2.1.1.3.調用createProxy()創建代理實現邏輯:
—-1.對ProxyFactory進行初始化
—-2.調用ProxyFactory.getProxy()創建代理
2.1.1.3.2.ProxyFactory.getProxy()實現邏輯:
調用 createAopProxy.getProxy(classLoader),邏輯如下
—-1.創建AopProxy:
——-對實現代理方式進行選擇:JDK?CGLIB?
——-調用JdkDynamicAopProxy的構造方法獲得代理。
JdkDynamicAopProxy的invoke方法:
1)獲取攔截器:getInterceptorsAndDynamicInterceptionAdvice
2)判斷攔截器鏈是否爲空,如果是空的話直接調用切點方法
3)如果攔截器不爲空的話那麼便創建ReflectiveMethodInvocation類,把攔截器方法都封裝在裏面
4)對攔截器鏈中的攔截器逐一調用:invocation.proceed()
proceed()方法:ReflectiveMethodInvocation中維護了攔截器調用的計數器,用來記錄當前調用鏈接的位置,使得可以有序的對攔截器逐一調用。