Spring如何實現AOP,你瞭解多少?

Spring如何實現AOP,你瞭解多少?

引言

1. 從註解入手找到對應核心類

最近工作中我都是基於註解實現AOP功能,常用的開啟AOP的註解是@EnableAspectJAutoProxy,我們就從它入手。

Spring如何實現AOP,你瞭解多少?

上面的動圖的流程的步驟就是:

@EnableAspectJAutoProxy

--> AspectJAutoProxyRegistrar

-->AopConfigUtils .registerAspectJAnnotationAutoProxyCreatorIfNecessary

-->AnnotationAwareAspectJAutoProxyCreator.classAnnotationAwareAspectJAutoProxyCreator查看其中文註釋(如下),確定它就是AOP的核心類!--溫安適 20191020

/**
1.AspectJAwareAdvisorAutoProxyCreator的子類
,用於處理當前應用上下文中的註解切面
2.任何被AspectJ註解的類將自動被識別。
3.若SpringAOP代理模式可以識別,優先使用Spring代理模式。
4.它覆蓋了方法執行連接點
5.如果使用<include>元素,
則只有名稱與include模式匹配的@aspectj bean才被視為切面
,並由spring自動代理。
6. Spring Advisors的處理請查閱,
org.springframework.aop
.framework.autoproxy.AbstractAdvisorAutoProxyCreator
*/
@SuppressWarnings("serial")
public class AnnotationAwareAspectJAutoProxyCreator
extends AspectJAwareAdvisorAutoProxyCreator {
//...省略實現
}註解切面
複製代碼
/<include>

雖然找到了核心類,但是並沒有找到核心方法!下面我們嘗試畫類圖確定核心方法。

2.畫核心類類圖,猜測核心方法

AnnotationAwareAspectJAutoProxyCreator的部分類圖。

Spring如何實現AOP,你瞭解多少?

AnnotationAwareAspectJAutoProxyCreator

 從類圖看到了AnnotationAwareAspectJAutoProxyCreator實現了BeanPostProcessor,而AOP功能應該在創建完Bean之後執行,猜測AnnotationAwareAspectJAutoProxyCreator實現BeanPostProcessor的postProcessAfterInitialization(實例化bean後處理)是核心方法。 查看AnnotationAwareAspectJAutoProxyCreator實現的postProcessAfterInitialization方法,實際該方法在其父類AbstractAutoProxyCreator中。//AbstractAutoProxyCreator中的postProcessAfterInitialization實現
@Override
public Object postProcessAfterInitialization(Object bean, String beanName)
throws BeansException {
if (bean != null) {

Object cacheKey = getCacheKey(bean.getClass(), beanName);
if (!this.earlyProxyReferences.contains(cacheKey)) {
return wrapIfNecessary(bean, beanName, cacheKey);
}
}
return bean;
}
複製代碼

發現發現疑似方法wrapIfNecessary,查看其源碼如下,發現createProxy方法。確定找對了地方。

protected Object wrapIfNecessary
(Object bean, String beanName, Object cacheKey) {
if (beanName != null && this.targetSourcedBeans.contains(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;
}
複製代碼

即AnnotationAwareAspectJAutoProxyCreator實現BeanPostProcessor的postProcessAfterInitialization方法,在該方法中由wrapIfNecessary實現了AOP的功能。 wrapIfNecessary中有2個和核心方法

  • getAdvicesAndAdvisorsForBean獲取當前bean匹配的增強器
  • createProxy為當前bean創建代理
  • 要想明白核心流程還需要分析這2個方法。

3.讀重點方法,理核心流程

3.1 getAdvicesAndAdvisorsForBean獲取當前bean匹配的增強器

查看源碼如下,默認實現在AbstractAdvisorAutoProxyCreator中。

@Override
@Nullable
protected Object[] getAdvicesAndAdvisorsForBean(
Class> beanClass, String beanName,
@Nullable TargetSource targetSource) {
List<advisor> advisors = findEligibleAdvisors(beanClass, beanName);
if (advisors.isEmpty()) {
return DO_NOT_PROXY;
}
return advisors.toArray();
}
複製代碼
/<advisor>

查閱findEligibleAdvisors方法,就幹了3件事

  • 找所有增強器,也就是所有@Aspect註解的Bean
  • 找匹配的增強器,也就是根據@Before,@After等註解上的表達式,與當前bean進行匹配,暴露匹配上的。
  • 對匹配的增強器進行擴展和排序,就是按照@Order或者PriorityOrdered的getOrder的數據值進行排序,越小的越靠前。
protected List<advisor> findEligibleAdvisors(Class> beanClass, String beanName) {
//找所有增強器
List<advisor> candidateAdvisors = findCandidateAdvisors();
//找所有匹配的增強器
List<advisor> eligibleAdvisors = findAdvisorsThatCanApply(candidateAdvisors, beanClass, beanName);
extendAdvisors(eligibleAdvisors);
if (!eligibleAdvisors.isEmpty()) {
//排序
eligibleAdvisors = sortAdvisors(eligibleAdvisors);
}
return eligibleAdvisors;
}
複製代碼
/<advisor>/<advisor>/<advisor>

AnnotationAwareAspectJAutoProxyCreator 重寫了findCandidateAdvisors,下面我們看看具體實現了什麼

3.1.1findCandidateAdvisors找所有增強器,也就是所有@Aspect註解的Bean

@Override
protected List<advisor> findCandidateAdvisors() {
// Add all the Spring advisors found according to superclass rules.
List<advisor> advisors = super.findCandidateAdvisors();
// Build Advisors for all AspectJ aspects in the bean factory.
if (this.aspectJAdvisorsBuilder != null) {
//@Aspect註解的類在這裡除了
advisors.addAll(this.aspectJAdvisorsBuilder.buildAspectJAdvisors());
}
return advisors;
}
複製代碼
/<advisor>/<advisor>

從該方法我們可以看到處理@Aspect註解的bean的方法是:this.aspectJAdvisorsBuilder.buildAspectJAdvisors()。 這個方法如下:

public List<advisor> buildAspectJAdvisors() {
List<string> aspectNames = this.aspectBeanNames;

if (aspectNames == null) {
synchronized (this) {
aspectNames = this.aspectBeanNames;
if (aspectNames == null) {
List<advisor> advisors = new ArrayList<>();
aspectNames = new ArrayList<>();
//找到所有BeanName
String[] beanNames = BeanFactoryUtils.beanNamesForTypeIncludingAncestors(
this.beanFactory, Object.class, true, false);
for (String beanName : beanNames) {
if (!isEligibleBean(beanName)) {
continue;
}
// 必須注意,bean會提前暴露,並被Spring容器緩存,但是這時還不能織入。
Class> beanType = this.beanFactory.getType(beanName);
if (beanType == null) {
continue;
}
if (this.advisorFactory.isAspect(beanType)) {
//找到所有被@Aspect註解的類
aspectNames.add(beanName);
AspectMetadata amd = new AspectMetadata(beanType, beanName);
if (amd.getAjType().getPerClause().getKind() == PerClauseKind.SINGLETON) {
MetadataAwareAspectInstanceFactory factory =
new BeanFactoryAspectInstanceFactory(this.beanFactory, beanName);
//解析封裝為Advisor返回
List<advisor> classAdvisors = this.advisorFactory.getAdvisors(factory);
if (this.beanFactory.isSingleton(beanName)) {
this.advisorsCache.put(beanName, classAdvisors);
}
else {
this.aspectFactoryCache.put(beanName, factory);
}
advisors.addAll(classAdvisors);
}
else {
// Per target or per this.
if (this.beanFactory.isSingleton(beanName)) {
throw new IllegalArgumentException("Bean with name '" + beanName +
"' is a singleton, but aspect instantiation model is not singleton");
}
MetadataAwareAspectInstanceFactory factory =
new PrototypeAspectInstanceFactory(this.beanFactory, beanName);
this.aspectFactoryCache.put(beanName, factory);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}

}
}
this.aspectBeanNames = aspectNames;
return advisors;
}
}
}
if (aspectNames.isEmpty()) {
return Collections.emptyList();
}
List<advisor> advisors = new ArrayList<>();
for (String aspectName : aspectNames) {
List<advisor> cachedAdvisors = this.advisorsCache.get(aspectName);
if (cachedAdvisors != null) {
advisors.addAll(cachedAdvisors);
}
else {
MetadataAwareAspectInstanceFactory factory = this.aspectFactoryCache.get(aspectName);
advisors.addAll(this.advisorFactory.getAdvisors(factory));
}
}
return advisors;
}
複製代碼
/<advisor>/<advisor>/<advisor>/<advisor>/<string>/<advisor>

這個方法可以概括為:

  • 找到所有BeanName
  • 根據BeanName篩選出被@Aspect註解的類
  • 針對類中被Around.class, Before.class, After.class, AfterReturning.class, AfterThrowing.class註解的方法,先按上邊的註解順序排序後按方法名稱排序,每一個方法對應一個Advisor。

3.2 createProxy為當前bean創建代理。

3.2.1 創建代理的2種方式

眾所周知,創建代理的常用的2種方式是:JDK創建和CGLIB,下面我們就看看這2中創建代理的例子。

3.2.1 .1 jdk創建代理的例子

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKProxyMain {
public static void main(String[] args) {
JDKProxyTestInterface target = new JDKProxyTestInterfaceImpl();
// 根據目標對象創建代理對象
JDKProxyTestInterface proxy =
(JDKProxyTestInterface) Proxy
.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new JDKProxyTestInvocationHandler(target));
// 調用代理對象方法
proxy.testProxy();
}
interface JDKProxyTestInterface {
void testProxy();
}
static class JDKProxyTestInterfaceImpl
implements JDKProxyTestInterface {
@Override
public void testProxy() {
System.out.println("testProxy");
}
}
static class JDKProxyTestInvocationHandler
implements InvocationHandler {
private Object target;
public JDKProxyTestInvocationHandler(Object target){
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
System.out.println("執行前");
Object result= method.invoke(this.target,args);
System.out.println("執行後");
return result;
}
}
複製代碼

3.2.1 .2 cglib創建代理的例子

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxyTest {
static class CglibProxyService {
public CglibProxyService(){
}
void sayHello(){
System.out.println(" hello !");
}
}
static class CglibProxyInterceptor implements MethodInterceptor{
@Override
public Object intercept(Object sub, Method method,
Object[] objects, MethodProxy methodProxy)
throws Throwable {
System.out.println("before hello");
Object object = methodProxy.invokeSuper(sub, objects);
System.out.println("after hello");
return object;
}
}
public static void main(String[] args) {
// 通過CGLIB動態代理獲取代理對象的過程
Enhancer enhancer = new Enhancer();
// 設置enhancer對象的父類
enhancer.setSuperclass(CglibProxyService.class);
// 設置enhancer的回調對象
enhancer.setCallback(new CglibProxyInterceptor());
// 創建代理對象
CglibProxyService proxy= (CglibProxyService)enhancer.create();
System.out.println(CglibProxyService.class);
System.out.println(proxy.getClass());
// 通過代理對象調用目標方法
proxy.sayHello();
}
}
複製代碼

3.2.1 .3 jdk創建代理與cglib創建代理的區別

類型 jdk創建動態代理 cglib創建動態代理 原理 java動態代理是利用反射機制生成一個實現代理接口的匿名類,在調用具體方法前調用InvokeHandler來處理 cglib動態代理是利用asm開源包,對代理對象類的class文件加載進來,通過修改其字節碼生成子類來處理 核心類 Proxy 創建代理利用反射機制生成一個實現代理接口的匿名類InvocationHandler 方法攔截器接口,需要實現invoke方法 net.sf.cglib.proxy.Enhancer:主要增強類,通過字節碼技術動態創建委託類的子類實例net.sf.cglib.proxy.MethodInterceptor:方法攔截器接口,需要實現intercept方法 侷限性 只能代理實現了接口的類 不能對final修飾的類進行代理,也不能處理final修飾的方法 3.2.2 Spring如何選擇的使用哪種方式

Spring的選擇選擇如何代理時在DefaultAopProxyFactory 中。

public class DefaultAopProxyFactory implements AopProxyFactory, 
Serializable {
@Override
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()
|| Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);

}
}
//...
}
複製代碼
  • config.isOptimize() 查看源碼註釋時發現,這個是配置使用cglib代理時,是否使用積極策略。這個值一般不建議使用!
  • config.isProxyTargetClass() 就是@EnableAspectJAutoProxy中的proxyTargetClass屬性。

//exposeProxy=true AopContext 可以訪問,proxyTargetClass=true CGLIB生成代理 @EnableAspectJAutoProxy(exposeProxy=true,proxyTargetClass=true)

  • hasNoUserSuppliedProxyInterfaces 是否存在可代理的接口

總結下Spring如何選擇創建代理的方式:

  1. 如果設置了proxyTargetClass=true,一定是CGLIB代理
  2. 如果proxyTargetClass=false,目標對象實現了接口,走JDK代理
  3. 如果沒有實現接口,走CGLIB代理

4.總結

Spring如何實現AOP?,您可以這樣說:

  1. AnnotationAwareAspectJAutoProxyCreator是AOP核心處理類
  2. AnnotationAwareAspectJAutoProxyCreator實現了BeanProcessor,其中postProcessAfterInitialization是核心方法。
  3. 核心實現分為2步
  4. getAdvicesAndAdvisorsForBean獲取當前bean匹配的增強器 createProxy為當前bean創建代理
  5. getAdvicesAndAdvisorsForBean核心邏輯如下
  6. a. 找所有增強器,也就是所有@Aspect註解的Bean
  7. b. 找匹配的增強器,也就是根據@Before,@After等註解上的表達式,與當前bean進行匹配,暴露匹配上的。
  8. c. 對匹配的增強器進行擴展和排序,就是按照@Order或者PriorityOrdered的getOrder的數據值進行排序,越小的越靠前。
  9. createProxy有2種創建方法,JDK代理或CGLIB
  10. a. 如果設置了proxyTargetClass=true,一定是CGLIB代理
  11. b. 如果proxyTargetClass=false,目標對象實現了接口,走JDK代理
  12. c. 如果沒有實現接口,走CGLIB代理

小結

私信小編髮送“架構”(免費獲取JAVA相關的面試架構資料喲)

最後,每一位讀到這裡的Java程序猿朋友們,感謝你們能耐心地看完。希望在成為一名更優秀的Java程序猿的道路上,我們可以一起學習、一起進步!都能贏取白富美,走向架構師的人生巔峰!


分享到:


相關文章: