中文亚洲精品无码_熟女乱子伦免费_人人超碰人人爱国产_亚洲熟妇女综合网

當(dāng)前位置: 首頁(yè) > news >正文

電子商務(wù)網(wǎng)站建設(shè)的成本分析如何做營(yíng)銷活動(dòng)

電子商務(wù)網(wǎng)站建設(shè)的成本分析,如何做營(yíng)銷活動(dòng),什么樣的企業(yè)要做網(wǎng)站,個(gè)人免費(fèi)注冊(cè)公司Spring之AOP底層源碼解析 1、動(dòng)態(tài)代理 代理模式的解釋:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn),增強(qiáng)一個(gè)類中的某個(gè)方法,對(duì)程序進(jìn)行擴(kuò)展。 舉個(gè)例子 public class UserService {public void test() {System.out.println("test.…

Spring之AOP底層源碼解析

1、動(dòng)態(tài)代理

代理模式的解釋:為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問(wèn),增強(qiáng)一個(gè)類中的某個(gè)方法,對(duì)程序進(jìn)行擴(kuò)展。

舉個(gè)例子

public class UserService {public void test() {System.out.println("test...");}
}

此時(shí),我們 new 一個(gè) UserService 對(duì)象,然后執(zhí)行 test() 方法,結(jié)果是顯而易見(jiàn)的。

Untitled

那如果我們現(xiàn)在想在不修改 UserService 類的源碼前提下,給 test() 方法增加額外的邏輯,那么就可以使用動(dòng)態(tài)代理機(jī)制來(lái)創(chuàng)建 UserService 對(duì)象了,比如:

		public static void main(String[] args) {// 被代理對(duì)象UserService target = new UserService();// 通過(guò)cglib技術(shù)Enhancer enhancer = new Enhancer();// 設(shè)置要代理的類enhancer.setSuperclass(UserService.class);// 定義額外的邏輯,也就是代理邏輯enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {/**** @param o 代理對(duì)象* @param method 當(dāng)前正在執(zhí)行的方法* @param objects 方法所需要的參數(shù)* @param methodProxy* @return* @throws Throwable*/@Overridepublic Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {System.out.println("before...");// 執(zhí)行被代理對(duì)象的原始方法Object result = methodProxy.invoke(target, objects);// Object result = methodProxy.invokeSuper(o, objects); 這種方式也可以System.out.println("after...");return result;}}});// 動(dòng)態(tài)代理所創(chuàng)建出來(lái)的UserService代理對(duì)象UserService userService = (UserService) enhancer.create();// 執(zhí)行這個(gè)userService的test方法時(shí),就會(huì)額外執(zhí)行一些其他邏輯userService.test();}

Untitled

得到的都是 UserService 對(duì)象,但是執(zhí)行 test() 方法時(shí)的效果卻不一樣了,這就是代理所帶來(lái)的效果。

上面是通過(guò) cglib 來(lái)實(shí)現(xiàn)的動(dòng)態(tài)代理對(duì)象的創(chuàng)建,是基于子父類的,被代理類(UserService)是父類,代理類是子類,代理對(duì)象就是代理類的實(shí)例對(duì)象,代理類是由 cglib 創(chuàng)建的,對(duì)于程序員來(lái)說(shuō)不用關(guān)心。

除了 cglib 技術(shù),JDK 本身也提供了一種創(chuàng)建代理對(duì)象的動(dòng)態(tài)代理機(jī)制,但是它只能代理接口,也就是 UserService 得先有一個(gè)接口才能利用 JDK 動(dòng)態(tài)代理機(jī)制來(lái)生成一個(gè)代理對(duì)象,比如:

public interface UserInterface {public void test();}public class UserService implements UserInterface {public void test() {System.out.println("test...");}
}

利用 JDK 動(dòng)態(tài)代理來(lái)生成一個(gè)代理對(duì)象:

		public static void main(String[] args) {// 被代理對(duì)象UserService target = new UserService();/*** UserInterface接口的代理對(duì)象* 注意第一個(gè)參數(shù)可以是任意類的類加載器,而第二個(gè)參數(shù)必須是代理對(duì)象的類型*/Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before...");// 通過(guò)反射機(jī)制調(diào)用被代理對(duì)象的原始方法Object result = method.invoke(target, args);System.out.println("after...");return result;}});UserInterface userService = (UserInterface) proxy;userService.test();}

Untitled

如果你把 new Class[]{UserInterface.class},替換成 new Class[]{UserService.class},那么代碼會(huì)直接報(bào)錯(cuò):

Untitled

Untitled

表示一定要是個(gè)接口。

由于這個(gè)限制,所以產(chǎn)生的代理對(duì)象的類型是 UserInterface,而不是 UserService,這是需要注意的。

2、ProxyFactory

上面我們介紹了兩種動(dòng)態(tài)代理技術(shù),那么在 Spring 中進(jìn)行了封裝,封裝出來(lái)的類叫做 ProxyFactory,表示是創(chuàng)建代理對(duì)象的一個(gè)工廠,使用起來(lái)會(huì)比上面的更加方便,比如:

		public static void main(String[] args) {// 被代理對(duì)象UserService target = new UserService();// 創(chuàng)建代理對(duì)象工廠ProxyFactory proxyFactory = new ProxyFactory();// 設(shè)置要代理的目標(biāo)類proxyFactory.setTarget(target);/*** 注意:如果沒(méi)有加上下面這行代碼,那么默認(rèn)走的是cglib動(dòng)態(tài)代理;* 而如果我們?cè)O(shè)置了接口,那么走的就是jdk動(dòng)態(tài)代理*/proxyFactory.setInterfaces(UserInterface);// 設(shè)置代理邏輯,MethodInterceptor表示方法攔截器proxyFactory.addAdvice(new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}});// 通過(guò)代理對(duì)象工廠,獲取代理對(duì)象UserInterface userService = (UserInterface) proxyFactory.getProxy();userService.test();}

通過(guò) ProxyFactory,我們可以不再關(guān)心到底是用 cglib 還是 JDK 動(dòng)態(tài)代理了,ProxyFactory 會(huì)幫助我們?nèi)ヅ袛?#xff0c;如果 UserService 實(shí)現(xiàn)了接口,那么ProxyFactory 底層就會(huì)采用 JDK 動(dòng)態(tài)代理,如果沒(méi)有實(shí)現(xiàn)接口,就會(huì)采用 cglib 動(dòng)態(tài)代理。上面的代碼,就是由于 UserService 實(shí)現(xiàn)了 UserInterface 接口,所以最后產(chǎn)生的代理對(duì)象是 UserInterface 類型。

3、Advice的分類

1、Before Advice:方法調(diào)用前執(zhí)行

public class XiexuBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] args, Object target) throws Throwable {System.out.println("方法調(diào)用前執(zhí)行");}
}

2、After Returning Advice:方法 Return 后執(zhí)行

		public class XiexuAfterReturningAdvice implements AfterReturningAdvice {/*** @param returnValue 執(zhí)行完被代理方法之后的返回值* @param method      被代理方法* @param args        方法所需要的參數(shù)* @param target      被代理對(duì)象* @throws Throwable*/@Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("方法return后執(zhí)行");}}

3、After Throwing Advice:方法拋異常后執(zhí)行

Untitled

public class XiexuThrowsAdvice implements ThrowsAdvice {/*** NullPointerException ex:當(dāng)方法拋出的異常類型為NullPointerException類型時(shí),才會(huì)調(diào)用該方法*/public void afterThrowing(Method method, Object[] args, Object target, NullPointerException ex) {System.out.println("方法拋出異常后執(zhí)行");}}

4、After Advice:方法執(zhí)行完之后執(zhí)行,不管當(dāng)前方法有沒(méi)有拋出異常,這個(gè) Advice 方法都會(huì)執(zhí)行

5、Around Advice:這是功能最強(qiáng)大的 Advice,可以自定義執(zhí)行順序

public class XiexuAroundAdvice implements MethodInterceptor {@Nullable@Overridepublic Object invoke(@NotNull MethodInvocation invocation) throws Throwable {System.out.println("方法執(zhí)行Around前");// 執(zhí)行被代理方法Object proceed = invocation.proceed();System.out.println("方法執(zhí)行Around后");return proceed;}
}

3.1、MethodInterceptor鏈

除了Around advice,其他 advice 在執(zhí)行完各自的邏輯代碼后,都會(huì)自動(dòng)調(diào)用 proceed() 去執(zhí)行被代理方法,而每次調(diào)用 proceed() 就會(huì)去看還有沒(méi)有設(shè)置其他的 advice,如果有就會(huì)繼續(xù)執(zhí)行其他 advice 的代理邏輯。

這里就是用到了「責(zé)任鏈」設(shè)計(jì)模式。

	public static void main(String[] args) {// 被代理對(duì)象UserService target = new UserService();// 代理對(duì)象工廠ProxyFactory proxyFactory = new ProxyFactory();// 設(shè)置目標(biāo)對(duì)象proxyFactory.setTarget(target);proxyFactory.addAdvice(new XiexuBeforeAdvice());proxyFactory.addAdvice(new XiexuAroundAdvice());proxyFactory.addAdvice(new XiexuAroundAdvice());// 獲取代理對(duì)象UserService proxy = (UserService) proxyFactory.getProxy();proxy.test(); // 執(zhí)行這行代碼的時(shí)候,底層就會(huì)去執(zhí)行invocation.proceed()}

Untitled

proceed() 方法源碼:

	@Override@Nullablepublic Object proceed() throws Throwable {/*** currentInterceptorIndex初始值為-1,每調(diào)用一個(gè)Interceptor就會(huì)加1* 當(dāng)調(diào)用完了最后一個(gè)Interceptor后就會(huì)執(zhí)行被代理的方法*/if (this.currentInterceptorIndex == this.interceptorsAndDynamicMethodMatchers.size() - 1) {// 執(zhí)行被代理的方法,點(diǎn)進(jìn)invokeJoinpoint()看看return invokeJoinpoint();}// currentInterceptorIndex初始值為-1Object interceptorOrInterceptionAdvice =this.interceptorsAndDynamicMethodMatchers.get(++this.currentInterceptorIndex);/*** 如果當(dāng)前interceptor是InterceptorAndDynamicMethodMatcher,則先進(jìn)行匹配,匹配成功后再調(diào)用該interceptor* 如果沒(méi)有匹配則遞歸調(diào)用proceed()方法,調(diào)用下一個(gè)interceptor*/if (interceptorOrInterceptionAdvice instanceof InterceptorAndDynamicMethodMatcher) {InterceptorAndDynamicMethodMatcher dm =(InterceptorAndDynamicMethodMatcher) interceptorOrInterceptionAdvice;Class<?> targetClass = (this.targetClass != null ? this.targetClass : this.method.getDeclaringClass());// 動(dòng)態(tài)匹配,根據(jù)方法參數(shù)進(jìn)行匹配if (dm.methodMatcher.matches(this.method, targetClass, this.arguments)) {return dm.interceptor.invoke(this);} else {// 不匹配則執(zhí)行下一個(gè)MethodInterceptorreturn proceed();}} else {/*** 直接調(diào)用MethodInterceptor,傳入this,在內(nèi)部會(huì)再次調(diào)用proceed()方法進(jìn)行遞歸* 比如MethodBeforeAdviceInterceptor*/return ((MethodInterceptor) interceptorOrInterceptionAdvice).invoke(this);}}

4、Advisor的理解

跟 Advice 類似的還有一個(gè) Advisor 的概念,一個(gè) Advisor 是由一個(gè) Pointcut 和一個(gè) Advice 組成的,通過(guò) Pointcut 可以指定需要被代理的邏輯,比如一個(gè) UserService 類中有兩個(gè)方法,按上面 ProxyFactory 的例子,這兩個(gè)方法都會(huì)被代理、被增強(qiáng),那么我們現(xiàn)在可以通過(guò) Advisor,來(lái)控制具體代理哪一個(gè)方法,比如:

public class Test {public static void main(String[] args) {// 被代理對(duì)象UserService target = new UserService();// 代理對(duì)象工廠ProxyFactory proxyFactory = new ProxyFactory();// 設(shè)置目標(biāo)對(duì)象proxyFactory.setTarget(target);proxyFactory.addAdvisor(new PointcutAdvisor() {/*** Pointcut可以去定義我們的代理邏輯要應(yīng)用到哪個(gè)方法或哪個(gè)類上面* @return*/@Overridepublic Pointcut getPointcut() {return new StaticMethodMatcherPointcut() {@Overridepublic boolean matches(Method method, Class<?> targetClass) {// 表示只有test()方法才需要走代理邏輯return method.getName().equals("test");}};}/*** Advice只是表示一段代理邏輯* @return*/@Overridepublic Advice getAdvice() {return new XiexuAroundAdvice();}/*** 這個(gè)方法可以忽略* @return*/@Overridepublic boolean isPerInstance() {return false;}});// 獲取代理對(duì)象UserInterface userService = (UserInterface) proxyFactory.getProxy();userService.test();}}

Untitled

上面代碼表示,產(chǎn)生的代理對(duì)象,只有在執(zhí)行 test() 這個(gè)方法時(shí)才會(huì)被增強(qiáng),才會(huì)執(zhí)行額外的邏輯,而在執(zhí)行其他方法時(shí)是不會(huì)被增強(qiáng)的。

5、創(chuàng)建代理對(duì)象的方式

上面介紹了 Spring 中所提供的 ProxyFactory、Advisor、Advice、PointCut 等技術(shù)來(lái)實(shí)現(xiàn)代理對(duì)象的創(chuàng)建,但是我們?cè)谑褂?Spring 時(shí),并不會(huì)直接這么去使用 ProxyFactory,比如說(shuō),我們希望 ProxyFactory 所產(chǎn)生的代理對(duì)象能直接就是 Bean,能直接從 Spring 容器中得到 UserSerivce 的代理對(duì)象,而這些 Spring 都是支持的,只不過(guò)作為開(kāi)發(fā)者的我們肯定得先告訴 Spring,哪些類需要被代理,代理邏輯是什么。

5.1、ProxyFactoryBean

		// 將產(chǎn)生的代理對(duì)象成為一個(gè)Bean@Beanpublic ProxyFactoryBean userService() {UserService userService = new UserService();// 創(chuàng)建ProxyFactoryBean對(duì)象ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();// 設(shè)置要代理的對(duì)象proxyFactoryBean.setTarget(userService);// 代理邏輯proxyFactoryBean.addAdvice(new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}});return proxyFactoryBean;}

通過(guò)這種方式來(lái)定義一個(gè) UserService 的 Bean,并且是經(jīng)過(guò)了 AOP 的。但是這種方式只能針對(duì)某一個(gè) Bean。它是一個(gè) FactoryBean,所以利用的就是FactoryBean 技術(shù),間接地將 UserService 的代理對(duì)象作為了 Bean。

ProxyFactoryBean 還有額外的功能,比如可以把某個(gè) Advice 或 Advisor 定義成為 Bean,然后在 ProxyFactoryBean 中進(jìn)行設(shè)置:

		@Beanpublic MethodInterceptor XiexuAroundAdvice() {return new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic ProxyFactoryBean userService() {// 被代理對(duì)象UserService userService = new UserService();ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();// 設(shè)置目標(biāo)對(duì)象proxyFactoryBean.setTarget(userService);proxyFactoryBean.setInterceptorNames("XiexuAroundAdvice");return proxyFactoryBean;}

5.2、BeanNameAutoProxyCreator

ProxyFactoryBean 得自己指定被代理的對(duì)象,那么我們可以通過(guò) BeanNameAutoProxyCreator 指定某個(gè) bean 的名字,來(lái)對(duì)該 bean 進(jìn)行代理

		@Beanpublic MethodInterceptor XiexuAroundAdvice() {return new MethodInterceptor() {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("before...");Object result = invocation.proceed();System.out.println("after...");return result;}};}@Beanpublic BeanNameAutoProxyCreator beanNameAutoProxyCreator() {BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();beanNameAutoProxyCreator.setBeanNames("userSe*");beanNameAutoProxyCreator.setInterceptorNames("XiexuAroundAdvice");beanNameAutoProxyCreator.setProxyTargetClass(true);return beanNameAutoProxyCreator;}

通過(guò) BeanNameAutoProxyCreator 可以對(duì)批量的 Bean 進(jìn)行 AOP,并且指定了代理邏輯,指定了一個(gè) InterceptorName,也就是一個(gè) Advice,前提條件是這個(gè) Advice 也得是一個(gè) Bean,這樣 Spring 才能找到,但是 BeanNameAutoProxyCreator 的缺點(diǎn)很明顯,它只能根據(jù) beanName 來(lái)指定想要代理的 Bean。

5.3、DefaultAdvisorAutoProxyCreator

public class AppConfig {/*** 定義一個(gè)Advisor類型的Bean** @return*/@Beanpublic DefaultPointcutAdvisor defaultPointcutAdvisor() {NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();pointcut.addMethodName("test");DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();defaultPointcutAdvisor.setPointcut(pointcut);defaultPointcutAdvisor.setAdvice(new XiexuAfterReturningAdvice());return defaultPointcutAdvisor;}@Beanpublic DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();return defaultAdvisorAutoProxyCreator;}}

通過(guò) DefaultAdvisorAutoProxyCreator 會(huì)直接去找所有 Advisor 類型的 Bean,然后根據(jù) Advisor 中的 PointCutAdvice 信息,確定要代理的 Bean 以及代理邏輯。

通過(guò)這種方式,我們得依靠某一個(gè)類來(lái)實(shí)現(xiàn)定義我們的 Advisor,或者 Advice,或者 Pointcut,那么這個(gè)步驟能不能更加簡(jiǎn)化一點(diǎn)呢?

答案是可以的,我們可以通過(guò)注解的方式進(jìn)行簡(jiǎn)化!

比如我們可以只定義一個(gè)類,然后通過(guò)在類中的方法上加上某些注解,來(lái)定義 PointCut 以及 Advice,比如:

		@Aspect@Componentpublic class XiexuAspect {@Before("execution(public void cn.xx.UserService.test())")public void xiexuBefore(JoinPoint joinPoint) {System.out.println("xiexuBefore");}}

通過(guò)上面這個(gè)類,我們就直接定義好了所要代理的方法(通過(guò)一個(gè)表達(dá)式),以及代理邏輯(被 @Before 修飾的方法),簡(jiǎn)單明了,這樣對(duì)于 Spring 來(lái)說(shuō),它要做的就是來(lái)解析這些注解了,解析之后得到對(duì)應(yīng)的 Pointcut 對(duì)象、Advice 對(duì)象,生成 Advisor 對(duì)象,扔進(jìn) ProxyFactory 中,進(jìn)而產(chǎn)生對(duì)應(yīng)的代理對(duì)象,具體怎么解析這些注解就是 @EnableAspectJAutoProxy 注解所要做的事情了,后面詳細(xì)分析。

6、對(duì)Spring AOP的理解

OOP 表示面向?qū)ο缶幊?#xff0c;是一種編程思想,AOP 表示面向切面編程,也是一種編程思想,而我們上面所描述的就是 Spring 為了讓程序員更加方便的做到面向切面編程所提供的技術(shù)支持,換句話說(shuō),就是 Spring 提供了一套機(jī)制,可以讓我們更加容易的進(jìn)行 AOP,所以這套機(jī)制我們也可以稱之為 Spring AOP。

但是值得注意的是,上面所提供的注解的方式來(lái)定義 PointcutAdvice,Spring 并不是首創(chuàng),首創(chuàng)是 AspectJ,而且也不僅僅只有 Spring 提供了一套機(jī)制來(lái)支持 AOP,還有比如 JBoss 4.0、aspectwerkz 等技術(shù)都提供了對(duì)于 AOP 的支持。而剛剛說(shuō)的注解的方式,Spring 是依賴了 AspectJ 的,換句話說(shuō),Spring 是直接把 AspectJ 中所定義的那些注解直接拿過(guò)來(lái)用,自己沒(méi)有再重新定義了,不過(guò)也僅僅只是把注解的定義復(fù)制過(guò)來(lái)了,每個(gè)注解具體底層是怎么解析的,還是 Spring 自己做的,所以我們?cè)谑褂?Spring 時(shí),如果你想用 @Before、@Around 等注解,是需要單獨(dú)引入 AspectJ 相關(guān) jar 包的,比如:

compile group: 'org.aspectj', name: 'aspectjrt', version: '1.9.5'
compile group: 'org.aspectj', name: 'aspectjweaver', version: '1.9.5'

值得注意的是:AspectJ 是在編譯時(shí)對(duì)字節(jié)碼進(jìn)行了修改,是直接在 UserService 類對(duì)應(yīng)的字節(jié)碼中進(jìn)行增強(qiáng)的,也就是可以理解為是在編譯時(shí)就會(huì)去解析@Before 這些注解,然后得到代理邏輯,加入到被代理類中的字節(jié)碼中去的,所以如果想用 AspectJ 技術(shù)來(lái)生成代理對(duì)象 ,是需要用單獨(dú)的 AspectJ 編譯器的。我們?cè)陧?xiàng)目中很少這么使用,我們僅僅只是用了 @Before 這些注解,而我們?cè)趩?dòng) Spring 的過(guò)程中,Spring 會(huì)去解析這些注解,然后利用動(dòng)態(tài)代理機(jī)制生成代理對(duì)象的。

IDEA 中使用 AspectJ:https://blog.csdn.net/gavin_john/article/details/80156963

7、AOP中的概念

上面我們已經(jīng)提到 Advisor、Advice、PointCut 等概念了,還有一些其他的概念,首先關(guān)于 AOP 中的概念本身是比較難理解的,Spring 官網(wǎng)上是這么說(shuō)的:

Let us begin by defining some central AOP concepts and terminology. These terms are not Spring-specific. Unfortunately, AOP terminology is not particularly intuitive. However, it would be even more confusing if Spring used its own terminology

意思是,AOP 中的這些概念并不是 Spring 特有的,而且不幸的是,AOP 中的概念不是特別直觀的,如果 Spring 重新定義自己的那可能會(huì)導(dǎo)致更加混亂。

1、Aspect:表示切面,比如被 @Aspect 注解的類就是切面,可以在切面中去定義 Pointcut、Advice 等等。

2、Join point:表示連接點(diǎn),表示一個(gè)程序在執(zhí)行過(guò)程中的一個(gè)點(diǎn),比如一個(gè)方法的執(zhí)行(被代理方法)、一個(gè)異常的處理,在 Spring AOP 中,一個(gè)連接點(diǎn)通常表示一個(gè)方法的執(zhí)行。

3、Advice:表示通知,表示在一個(gè)特定連接點(diǎn)上所采取的動(dòng)作。Advice 分為不同的類型,后面詳細(xì)討論,在很多 AOP 框架中,包括 Spring,會(huì)用Interceptor 攔截器來(lái)實(shí)現(xiàn) Advice,并且會(huì)在連接點(diǎn)周圍維護(hù)一個(gè) Interceptor 鏈。

4、Pointcut:表示切點(diǎn),用來(lái)匹配一個(gè)或多個(gè)連接點(diǎn),Advice 與切點(diǎn)表達(dá)式是關(guān)聯(lián)在一起的,Advice 將會(huì)執(zhí)行在和切點(diǎn)表達(dá)式所匹配的連接點(diǎn)上。

5、Introduction:可以使用 @DeclareParents 來(lái)給所匹配的類添加一個(gè)接口,并指定一個(gè)默認(rèn)實(shí)現(xiàn)。

6、Target object:目標(biāo)對(duì)象,也就是被代理對(duì)象。

7、AOP Proxy:表示代理工廠,用來(lái)創(chuàng)建代理對(duì)象的,在 Spring Framework 中,要么是 JDK 動(dòng)態(tài)代理,要么是 CGLIB 動(dòng)態(tài)代理。

8、Weaving:表示織入,表示創(chuàng)建代理對(duì)象的動(dòng)作,這個(gè)動(dòng)作可以發(fā)生在編譯時(shí)期(比如 Aspejctj),也可以發(fā)生在運(yùn)行時(shí)期(比如 Spring AOP)。

8、Advice在Spring AOP中對(duì)應(yīng)的API

上面說(shuō)到的 AspjectJ 中的注解,其中有五個(gè)是用來(lái)定義 Advice 的,表示代理邏輯,以及執(zhí)行時(shí)機(jī):

1、@Before

2、@AfterReturning

3、@AfterThrowing

4、@After

5、@Around

我們前面也提到過(guò),Spring 自己也提供了類似的實(shí)現(xiàn)類:

1、接口MethodBeforeAdvice,繼承了接口BeforeAdvice

2、接口AfterReturningAdvice,繼承了接口AfterAdvice

3、接口ThrowsAdvice,繼承了接口AfterAdvice

4、接口AfterAdvice,繼承了接口Advice

5、接口MethodInterceptor,繼承了接口Interceptor

Spring 會(huì)把這五個(gè)注解解析成對(duì)應(yīng)的 Advice 類:

1、@Before:AspectJMethodBeforeAdvice,實(shí)際上就是一個(gè) MethodBeforeAdvice

2、@AfterReturning:AspectJAfterReturningAdvice,實(shí)際上就是一個(gè) AfterReturningAdvice

3、@AfterThrowing:AspectJAfterThrowingAdvice,實(shí)際上就是一個(gè) MethodInterceptor

4、@After:AspectJAfterAdvice,實(shí)際上就是一個(gè) MethodInterceptor

5、@Around:AspectJAroundAdvice,實(shí)際上就是一個(gè) MethodInterceptor

9、TargetSource的使用

在我們?nèi)粘5?AOP 中,被代理對(duì)象就是 Bean 對(duì)象,是由 BeanFactory 給我們創(chuàng)建出來(lái)的,但是 Spring AOP 中提供了 TargetSource 機(jī)制,可以讓我們自定義邏輯來(lái)創(chuàng)建被代理對(duì)象。

比如之前提到的 @Lazy 注解,當(dāng)加在屬性上時(shí),會(huì)產(chǎn)生一個(gè)代理對(duì)象并賦值給這個(gè)屬性,產(chǎn)生代理對(duì)象的代碼為:

	/*** 創(chuàng)建@Lazy懶加載的代理對(duì)象** @param descriptor* @param beanName* @return*/protected Object buildLazyResolutionProxy(final DependencyDescriptor descriptor, final @Nullable String beanName) {// 獲取Spring的Bean工廠BeanFactory beanFactory = getBeanFactory();Assert.state(beanFactory instanceof DefaultListableBeanFactory, "BeanFactory needs to be a DefaultListableBeanFactory");final DefaultListableBeanFactory dlbf = (DefaultListableBeanFactory) beanFactory;/*** 創(chuàng)建TargetSource對(duì)象*/TargetSource ts = new TargetSource() {@Overridepublic Class<?> getTargetClass() {return descriptor.getDependencyType();}@Overridepublic boolean isStatic() {return false;}/*** Lazy的效果:* 當(dāng)屬性上有@Lazy注解,剛開(kāi)始進(jìn)行依賴注入時(shí),該屬性是被賦了一個(gè)代理對(duì)象,* 當(dāng)你真正用到該屬性時(shí),這時(shí)候才會(huì)根據(jù)當(dāng)前屬性的類型和名字,去BeanFactory中找到對(duì)應(yīng)的Bean,這時(shí)候才會(huì)真正去執(zhí)行對(duì)應(yīng)Bean的原方法。* 當(dāng)set方法的參數(shù)有@Lazy注解時(shí),同理。* @return*/@Overridepublic Object getTarget() {Set<String> autowiredBeanNames = (beanName != null ? new LinkedHashSet<>(1) : null);// 根據(jù)屬性的類型和名字去Bean工廠找被代理的對(duì)象Object target = dlbf.doResolveDependency(descriptor, beanName, autowiredBeanNames, null);if (target == null) {Class<?> type = getTargetClass();if (Map.class == type) {return Collections.emptyMap();} else if (List.class == type) {return Collections.emptyList();} else if (Set.class == type || Collection.class == type) {return Collections.emptySet();}throw new NoSuchBeanDefinitionException(descriptor.getResolvableType(), "Optional dependency not present for lazy injection point");}if (autowiredBeanNames != null) {for (String autowiredBeanName : autowiredBeanNames) {if (dlbf.containsBean(autowiredBeanName)) {dlbf.registerDependentBean(autowiredBeanName, beanName);}}}// 找到被代理的對(duì)象,直接返回return target;}@Overridepublic void releaseTarget(Object target) {}};// 創(chuàng)建ProxyFactory對(duì)象ProxyFactory pf = new ProxyFactory();// 設(shè)置被代理對(duì)象為T(mén)argetSourcepf.setTargetSource(ts);Class<?> dependencyType = descriptor.getDependencyType();if (dependencyType.isInterface()) {pf.addInterface(dependencyType);}// 返回一個(gè)代理對(duì)象return pf.getProxy(dlbf.getBeanClassLoader());}

這段代碼就利用了 ProxyFactory 來(lái)生成代理對(duì)象,以及使用了 TargetSource,以達(dá)到代理對(duì)象在執(zhí)行某個(gè)方法時(shí),會(huì)去調(diào)用 TargetSource 的 getTarget() 方法得到一個(gè)被代理對(duì)象。

10、ProxyFactory選擇CGLIB或JDK動(dòng)態(tài)代理的原理

ProxyFactory 在生成代理對(duì)象之前需要先決定到底是使用 JDK 動(dòng)態(tài)代理還是 CGLIB 動(dòng)態(tài)代理:

	@Overridepublic AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {/*** config指的是我們?cè)谕饷鎰?chuàng)建的ProxyFactory對(duì)象* NativeDetector.inNativeImage():當(dāng)前Spring項(xiàng)目是不是在GraalVM虛擬機(jī)上運(yùn)行的,如果是則使用JDK動(dòng)態(tài)代理創(chuàng)建代理對(duì)象* config.isOptimize():如果isOptimize為true,則會(huì)使用cglib動(dòng)態(tài)代理創(chuàng)建代理對(duì)象,因?yàn)镾pring認(rèn)為cglib比jdk動(dòng)態(tài)代理要快* config.isProxyTargetClass():要代理的是不是一個(gè)類,如果為true則使用cglib動(dòng)態(tài)代理創(chuàng)建代理對(duì)象* hasNoUserSuppliedProxyInterfaces(config):當(dāng)前ProxyFactory對(duì)象有沒(méi)有去添加接口(addInterface),* 如果添加了則返回false并使用JDK動(dòng)態(tài)代理創(chuàng)建代理對(duì)象,如果沒(méi)有添加接口則返回true并使用cglib動(dòng)態(tài)代理創(chuàng)建代理對(duì)象*/if (!NativeDetector.inNativeImage() &&/*** 類似于:* ProxyFactory proxyFactory = new ProxyFactory();* proxyFactory.setOptimize(true);* proxyFactory.setProxyTargetClass(true);* 如果添加了proxyFactory.addInterface();* 那么hasNoUserSuppliedProxyInterfaces(config)為false,如果沒(méi)有添加則為true*/(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.");}/*** targetClass.isInterface():如果被代理的類是一個(gè)接口* 舉個(gè)例子:* ProxyFactory proxyFactory = new ProxyFactory();* proxyFactory.setTargetClass(UserInterface.class);* 這樣的話就表示被代理類是一個(gè)接口* Proxy.isProxyClass(targetClass):當(dāng)前所設(shè)置的被代理類是不是已經(jīng)進(jìn)行過(guò)JDK動(dòng)態(tài)代理而生成的代理類*/if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {/*** 使用jdk動(dòng)態(tài)代理創(chuàng)建代理對(duì)象*/return new JdkDynamicAopProxy(config);}/*** 返回Cglib創(chuàng)建的代理對(duì)象*/return new ObjenesisCglibAopProxy(config);} else {/*** 使用jdk動(dòng)態(tài)代理創(chuàng)建代理對(duì)象*/return new JdkDynamicAopProxy(config);}}

11、代理對(duì)象創(chuàng)建過(guò)程

11.1、JdkDynamicAopProxy

1、在構(gòu)造 JdkDynamicAopProxy 對(duì)象時(shí),會(huì)先拿到被代理對(duì)象自己所實(shí)現(xiàn)的接口,并且額外增加 SpringProxy、Advised、DecoratingProxy 三個(gè)接口,組合成一個(gè) Class[],并賦值給 proxiedInterfaces 屬性

2、并且檢查這些接口中是否定義了equals()、hashcode()方法

3、執(zhí)行 Proxy.newProxyInstance(classLoader, this.proxiedInterfaces, this),得到代理對(duì)象,JdkDynamicAopProxy 作為 InvocationHandler,代理對(duì)象在執(zhí)行某個(gè)方法時(shí),會(huì)進(jìn)入到 JdkDynamicAopProxy 的 invoke() 方法中

12、代理對(duì)象執(zhí)行過(guò)程

1、在使用 ProxyFactory 創(chuàng)建代理對(duì)象之前,需要往 ProxyFactory 中先添加 Advisor

2、代理對(duì)象在執(zhí)行某個(gè)方法時(shí),會(huì)把 ProxyFactory 中的 Advisor 拿出來(lái)和當(dāng)前正在執(zhí)行的方法進(jìn)行匹配篩選

3、把和當(dāng)前正在執(zhí)行的方法所匹配的 Advisor 適配成 MethodInterceptor

4、把和當(dāng)前方法匹配的 MethodInterceptor 鏈,以及被代理對(duì)象、代理對(duì)象、代理類、當(dāng)前 Method 對(duì)象、方法參數(shù)封裝成 MethodInvocation 對(duì)象

5、調(diào)用 MethodInvocation 的 proceed() 方法,開(kāi)始執(zhí)行各個(gè) MethodInterceptor 以及被代理對(duì)象的對(duì)應(yīng)方法

6、按順序調(diào)用每個(gè) MethodInterceptor 的 invoke() 方法,并且會(huì)把 MethodInvocation 對(duì)象傳入 invoke() 方法

7、直到執(zhí)行完最后一個(gè) MethodInterceptor 了,就會(huì)調(diào)用 invokeJoinpoint() 方法,從而執(zhí)行被代理對(duì)象的當(dāng)前方法

12.1、各注解對(duì)應(yīng)的MethodInterceptor

1、@Before 對(duì)應(yīng)的是 AspectJMethodBeforeAdvice,在進(jìn)行動(dòng)態(tài)代理時(shí)會(huì)把 AspectJMethodBeforeAdvice 轉(zhuǎn)成 MethodBeforeAdviceInterceptor

  • 先執(zhí)行 advice 對(duì)應(yīng)的方法
  • 再執(zhí)行 MethodInvocation 的 proceed(),會(huì)執(zhí)行下一個(gè) Interceptor,如果沒(méi)有下一個(gè) Interceptor 了,會(huì)執(zhí)行 target 對(duì)應(yīng)的方法

2、@After 對(duì)應(yīng)的是 AspectJAfterAdvice,直接實(shí)現(xiàn)了 MethodInterceptor

  • 先執(zhí)行 MethodInvocation 的 proceed(),會(huì)執(zhí)行下一個(gè) Interceptor,如果沒(méi)有下一個(gè) Interceptor 了,會(huì)執(zhí)行 target 對(duì)應(yīng)的方法
  • 再執(zhí)行 advice 對(duì)應(yīng)的方法

3、@Around 對(duì)應(yīng)的是 AspectJAroundAdvice,直接實(shí)現(xiàn)了 MethodInterceptor

  • 直接執(zhí)行 advice 對(duì)應(yīng)的方法,由 @Around 自己決定要不要繼續(xù)往后面調(diào)用

4、@AfterThrowing 對(duì)應(yīng)的是 AspectJAfterThrowingAdvice,直接實(shí)現(xiàn)了 MethodInterceptor

  • 先執(zhí)行 MethodInvocation的 proceed(),會(huì)執(zhí)行下一個(gè) Interceptor,如果沒(méi)有下一個(gè) Interceptor 了,會(huì)執(zhí)行 target 對(duì)應(yīng)的方法
  • 如果上面拋了 Throwable,那么則會(huì)執(zhí)行 advice 對(duì)應(yīng)的方法

5、@AfterReturning 對(duì)應(yīng)的是 AspectJAfterReturningAdvice,在進(jìn)行動(dòng)態(tài)代理時(shí)會(huì)把 AspectJAfterReturningAdvice 轉(zhuǎn)成 AfterReturningAdviceInterceptor

  • 先執(zhí)行 MethodInvocation 的 proceed(),會(huì)執(zhí)行下一個(gè) Interceptor,如果沒(méi)有下一個(gè) Interceptor 了,會(huì)執(zhí)行 target 對(duì)應(yīng)的方法
  • 執(zhí)行上面的方法后得到最終的方法的返回值
  • 再執(zhí)行 Advice 對(duì)應(yīng)的方法

13、AbstractAdvisorAutoProxyCreator

DefaultAdvisorAutoProxyCreator 的父類是 AbstractAdvisorAutoProxyCreator。

Untitled

AbstractAdvisorAutoProxyCreator 非常強(qiáng)大以及重要,只要 Spring 容器中存在這個(gè)類型的 Bean,就相當(dāng)于開(kāi)啟了 AOP,AbstractAdvisorAutoProxyCreator實(shí)際上就是一個(gè) BeanPostProcessor,所以在創(chuàng)建某個(gè) Bean 時(shí),就會(huì)進(jìn)入到它對(duì)應(yīng)的生命周期方法中,比如在某個(gè) Bean 初始化之后,會(huì)調(diào)用wrapIfNecessary() 方法進(jìn)行 AOP,底層邏輯是:AbstractAdvisorAutoProxyCreator 會(huì)找到所有的 Advisor,然后判斷當(dāng)前這個(gè) Bean 是否存在某個(gè) Advisor 與之匹配(根據(jù) Pointcut),如果匹配就表示當(dāng)前這個(gè) Bean 有對(duì)應(yīng)的切面邏輯,需要進(jìn)行AOP,需要產(chǎn)生一個(gè)代理對(duì)象。

14、@EnableAspectJAutoProxy

這個(gè)注解主要就是往 Spring 容器中添加了一個(gè) AnnotationAwareAspectJAutoProxyCreator 類型的Bean。

Untitled

AspectJAwareAdvisorAutoProxyCreator 繼承了 AbstractAdvisorAutoProxyCreator,重寫(xiě)了 findCandidateAdvisors() 方法,AbstractAdvisorAutoProxyCreator 只能找到所有 Advisor 類型的 Bean 對(duì)象,但是 AspectJAwareAdvisorAutoProxyCreator 除了可以找到所有 Advisor 類型的 Bean 對(duì)象,還能把 @Aspect 注解所標(biāo)注的 Bean 中的 @Before 等注解及方法進(jìn)行解析,并生成對(duì)應(yīng)的 Advisor 對(duì)象。

@Aspect
@Component
public class XxAspect {@Before("execution(public void cn.xx.UserService.test())")public void xiexuBefore(JoinPoint joinPoint) {System.out.println("xiexuBefore");}}

所以,我們可以這樣理解 @EnableAspectJAutoProxy,其實(shí)就是向 Spring 容器中添加了一個(gè) AbstractAdvisorAutoProxyCreator 類型的Bean,從而開(kāi)啟了 AOP,并且還會(huì)解析 @Before 等注解并生成 Advisor。

15、Spring中AOP原理流程圖

https://www.processon.com/view/link/5faa4ccce0b34d7a1aa2a9a5

http://m.risenshineclean.com/news/59796.html

相關(guān)文章:

  • 怎么看別人網(wǎng)站怎么做的優(yōu)化經(jīng)典軟文案例100例簡(jiǎn)短
  • 建設(shè)銀行網(wǎng)站百度一下百度平臺(tái)app下載
  • SEO優(yōu)化之如何做網(wǎng)站URL優(yōu)化sem廣告
  • last login wordpress貴港seo關(guān)鍵詞整站優(yōu)化
  • wordpress電影插件seo還有哪些方面的優(yōu)化
  • 龍巖網(wǎng)站設(shè)計(jì)培訓(xùn)百度推廣一個(gè)點(diǎn)擊多少錢
  • 中英文切換網(wǎng)站怎么做線上銷售水果營(yíng)銷方案
  • 批量上傳產(chǎn)品WordPress百度seo最成功的優(yōu)化
  • 網(wǎng)站關(guān)鍵詞優(yōu)化排名網(wǎng)頁(yè)設(shè)計(jì)框架圖
  • 網(wǎng)絡(luò)推廣公司盈利模式seo分析師招聘
  • 各大搜索引擎提交網(wǎng)站入口大全網(wǎng)站的營(yíng)銷推廣
  • 如何做好網(wǎng)站管理工作女教師遭網(wǎng)課入侵視頻大全
  • 寧波建筑公司排名無(wú)錫seo
  • 網(wǎng)頁(yè)網(wǎng)站制作公司學(xué)電腦辦公軟件培訓(xùn)班
  • 之力seo網(wǎng)站關(guān)鍵詞優(yōu)化工具
  • 苗木網(wǎng)站模板seo管理軟件
  • 義烏商城集團(tuán)的網(wǎng)站建設(shè)站長(zhǎng)之家ip地址查詢
  • 廣州建外貿(mào)網(wǎng)站什么企業(yè)需要網(wǎng)絡(luò)營(yíng)銷和網(wǎng)絡(luò)推廣
  • 樂(lè)云seo網(wǎng)站建設(shè)公司seo搜索引擎優(yōu)化就業(yè)前景
  • 什么網(wǎng)站專做二手名表做關(guān)鍵詞優(yōu)化的公司
  • 佛山精品網(wǎng)站建設(shè)優(yōu)化大師官方正版下載
  • 手機(jī)網(wǎng)站制作費(fèi)用百度指數(shù)數(shù)據(jù)分析平臺(tái)入口
  • 便宜網(wǎng)站建設(shè)模板網(wǎng)站谷歌排名查詢
  • 手機(jī)頁(yè)面模板站長(zhǎng)工具seo優(yōu)化
  • 家居在線設(shè)計(jì)平臺(tái)seo優(yōu)化報(bào)價(jià)
  • 邯鄲市建設(shè)局網(wǎng)站材料下載入口北京seo方法
  • 南京建設(shè)監(jiān)理協(xié)會(huì)網(wǎng)站企業(yè)網(wǎng)絡(luò)的組網(wǎng)方案
  • 三亞建設(shè)工程信息網(wǎng)站外鏈交換平臺(tái)
  • 蘇州做網(wǎng)站外包的公司有哪些win7優(yōu)化
  • 英文二手汽車網(wǎng)站建設(shè)網(wǎng)絡(luò)項(xiàng)目免費(fèi)的資源網(wǎng)