時(shí)間:2017年09月03日星期日
說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com
教學(xué)源碼:https://github.com/zccodere/s...
學(xué)習(xí)源碼:https://github.com/zccodere/s...
課程章節(jié)
概覽 AOP使用 AOP原理 AOP開(kāi)源運(yùn)用 課程實(shí)戰(zhàn) 課程總結(jié)
面向切面編程是一種編程范式
編程范式概覽
面向過(guò)程編程 面向?qū)ο缶幊?面向函數(shù)編程(函數(shù)式編程) 事件驅(qū)動(dòng)編程(GUI開(kāi)發(fā)中比較常見(jiàn)) 面向切面編程
AOP是什么
是一種編程范式,不是編程語(yǔ)言 解決特定問(wèn)題,不能解決所有問(wèn)題 是OOP的補(bǔ)充,不是替代
AOP的初衷
DRY:Don’t Repeat Yourself代碼重復(fù)性問(wèn)題 SOC:Separation of Concerns關(guān)注點(diǎn)分離 -水平分離:展示層->服務(wù)層->持久層 -垂直分離:模塊劃分(訂單、庫(kù)存等) -切面分離:分離功能性需求與非功能性需求
使用AOP的好處
集中處理某一關(guān)注點(diǎn)/橫切邏輯 可以很方便地添加/刪除關(guān)注點(diǎn) 侵入性少,增強(qiáng)代碼可讀性及可維護(hù)性
AOP的應(yīng)用場(chǎng)景
權(quán)限控制 緩存控制 事務(wù)控制 審計(jì)日志 性能監(jiān)控 分布式追蹤 異常處理
支持AOP的編程語(yǔ)言
Java .NET C/C++ Ruby Python PHP …1-2 簡(jiǎn)單案例
案例背景
產(chǎn)品管理的服務(wù) 產(chǎn)品添加、刪除的操作只能管理員才能進(jìn)行 普通實(shí)現(xiàn)VS AOP實(shí)現(xiàn)
創(chuàng)建一個(gè)名為springaopguide的maven項(xiàng)目pom如下
完成后的項(xiàng)目結(jié)構(gòu)如下
代碼編寫
1.編寫Product類
package com.myimooc.springaopguide.domain; /** * @title 產(chǎn)品領(lǐng)域模型 * @describe 產(chǎn)品實(shí)體對(duì)象 * @author zc * @version 1.0 2017-09-03 */ public class Product { private Long id; private String name; public Long getId() { return id; } public void setId(Long id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } }
2.編寫CurrentUserHolder類
package com.myimooc.springaopguide.security; /** * @title 獲取用戶信息 * @describe 模擬用戶的切換,將用戶信息存入當(dāng)前線程 * @author zc * @version 1.0 2017-09-03 */ public class CurrentUserHolder { private static final ThreadLocalholder = new ThreadLocal<>(); public static String get(){ return holder.get() == null ? "unkown" : holder.get(); } public static void set(String user){ holder.set(user); } }
3.編寫AdminOnly類
package com.myimooc.springaopguide.security; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @title 管理員權(quán)限注解 * @describe 被該注解聲明的方法需要管理員權(quán)限 * @author zc * @version 1.0 2017-09-03 */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.METHOD) public @interface AdminOnly { }
4.編寫SecurityAspect類
package com.myimooc.springaopguide.security; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import com.myimooc.springaopguide.service.AuthService; /** * @title 權(quán)限校驗(yàn)切面類 * @describe * @author zc * @version 1.0 2017-09-03 */ // 聲明為一個(gè)切面 @Aspect @Component public class SecurityAspect { @Autowired private AuthService authService; // 使用要攔截標(biāo)注有AdminOnly的注解進(jìn)行操作 @Pointcut("@annotation(AdminOnly)") public void adminOnly(){ } @Before("adminOnly()") public void check(){ authService.checkAccess(); } }
5.編寫AuthService類
package com.myimooc.springaopguide.service; import java.util.Objects; import org.springframework.stereotype.Service; import com.myimooc.springaopguide.security.CurrentUserHolder; /** * @title 權(quán)限校驗(yàn)類 * @describe 對(duì)用戶權(quán)限進(jìn)行校驗(yàn) * @author zc * @version 1.0 2017-09-03 */ @Service public class AuthService { public void checkAccess(){ String user = CurrentUserHolder.get(); if(!Objects.equals("admin", user)){ throw new RuntimeException("operation not allow"); } } }
6.編寫ProductService類
package com.myimooc.springaopguide.service; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.myimooc.springaopguide.domain.Product; /** * @title 產(chǎn)品服務(wù)類 * @describe 產(chǎn)品相關(guān)業(yè)務(wù)服務(wù)-傳統(tǒng)方式實(shí)現(xiàn)權(quán)限校驗(yàn) * @author zc * @version 1.0 2017-09-03 */ @Service public class ProductService { @Autowired private AuthService AuthService; public void insert(Product product){ AuthService.checkAccess(); System.out.println("insert product"); } public void delete(Long id){ AuthService.checkAccess(); System.out.println("delete product"); } }
7.編寫ProductServiceAop類
package com.myimooc.springaopguide.service; import org.springframework.stereotype.Service; import com.myimooc.springaopguide.domain.Product; import com.myimooc.springaopguide.security.AdminOnly; /** * @title 產(chǎn)品服務(wù)類 * @describe 產(chǎn)品相關(guān)業(yè)務(wù)服務(wù)-AOP方式實(shí)現(xiàn)權(quán)限校驗(yàn) * @author zc * @version 1.0 2017-09-03 */ @Service public class ProductServiceAop { @AdminOnly public void insert(Product product){ System.out.println("insert product"); } @AdminOnly public void delete(Long id){ System.out.println("delete product"); } }
8.編寫AopGuideApplicationTests類
package com.myimooc.springaopguide; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.context.junit4.SpringRunner; import com.myimooc.springaopguide.security.CurrentUserHolder; import com.myimooc.springaopguide.service.ProductService; import com.myimooc.springaopguide.service.ProductServiceAop; /** * @title 單元測(cè)試類 * @describe 測(cè)試權(quán)限校驗(yàn)服務(wù)是否生效 * @author zc * @version 1.0 2017-09-03 */ @RunWith(SpringRunner.class) @SpringBootTest public class AopGuideApplicationTests { @Autowired private ProductService productService; @Test(expected = Exception.class) public void annoInsertTest(){ CurrentUserHolder.set("tom"); productService.delete(1L); } @Test public void adminInsertTest(){ CurrentUserHolder.set("admin"); productService.delete(1L); } @Autowired private ProductServiceAop productServiceAop; @Test(expected = Exception.class) public void annoInsertAopTest(){ CurrentUserHolder.set("tom"); productServiceAop.delete(1L); } @Test public void adminInsertAopTest(){ CurrentUserHolder.set("admin"); productServiceAop.delete(1L); } }第二章:使用詳解 2-1 本節(jié)內(nèi)容
Spring AOP使用方式
XML配置+Pointcut expression【不推薦使用方式】 注解方式+ Pointcut expression【推薦使用該方式】
Aspectj注解
@Aspect:用于聲明當(dāng)前類是一個(gè)切面 @Pointcut:用于描述在哪些類、哪些方法上執(zhí)行切面的代碼 Advice:描述想要在這些方法執(zhí)行的什么時(shí)機(jī)進(jìn)行攔截
本章內(nèi)容
Pointcut express:切面表達(dá)式 5種Advice:建言的五種細(xì)分怎么使用2-2 切面表達(dá)式
切面表達(dá)式
1.designators(指示器) execution() 描述通過(guò)什么樣的方式去匹配哪些類、哪些方法 2.wildcards(通配符) * .. + 使用通配符進(jìn)行描述 3.operators(運(yùn)算符) && || ! 使用運(yùn)算符進(jìn)行多條件的判斷
Designators(指示器)
匹配方法 execution() 匹配注解 @target() @args() @within() @annotation() 匹配包/類型 @within() 匹配對(duì)象 this() bean() target() 匹配參數(shù) args()
Wildcards(通配符)
* 匹配任意數(shù)量的字符 + 匹配指定類及其子類 .. 一般用于匹配任意參數(shù)的子包或參數(shù)
Operators(運(yùn)算符)
&& 與操作符 || 或操作符 ! 非操作符2-3 匹配包類
// 匹配 ProductServiceAop 類里面的所有方法 @Pointcut("within(com.myimooc.springaopguide.service.ProductServiceAop)") public void matchType(){} // 匹配 com.myimooc.springaopguide.service 包及子包下所有類的方法 @Pointcut("within(com.myimooc.springaopguide.service..*)") public void matchPackage(){}2-4 匹配對(duì)象
// 匹配AOP對(duì)象的目標(biāo)對(duì)象為指定類型的方法,即DemoDao的aop代理對(duì)象的方法 @Pointcut("this(com.myimooc.springaopguide.dao.DemoDao)") public void testDemo(){} // 匹配實(shí)現(xiàn)IDao接口的目標(biāo)對(duì)象(而不是aop代理后的對(duì)象)的方法,這里即DemoDao的方法 @Pointcut("target(com.myimooc.springaopguide.dao.IDao)") public void targetDemo(){} // 匹配所有以Service結(jié)尾的bean里面的方法 @Pointcut("bean(*Service)") public void beanDemo(){}2-5 匹配參數(shù)
// 匹配任何以find開(kāi)頭而且只有一個(gè)Long參數(shù)的方法 @Pointcut("execution(* *..find*(Long))") public void argsDemo1(){} // 匹配任何只有一個(gè)Long參數(shù)的方法 @Pointcut("args(Long)") public void argsDemo2(){} // 匹配任何以find開(kāi)頭而且第一個(gè)參數(shù)為L(zhǎng)ong型的方法 @Pointcut("execution(* *..find*(Long,..))") public void argsDemo3(){} // 匹配第一個(gè)參數(shù)為L(zhǎng)ong型的方法 @Pointcut("args(Long,..))") public void argsDemo4(){}2-6 匹配注解
// 匹配方法標(biāo)注有AdminOnly的注解的方法 @Pointcut("@annotation(com.myimooc.springaopguide.security.AdminOnly)") public void annoDemo(){} // 匹配標(biāo)注有Beta的類底下的方法,要求的annotation的RetentionPolicy級(jí)別為CLASS @Pointcut("@within(com.google.common.annotations.Beta)") public void annoWithDemo(){} // 匹配標(biāo)注有Repository的類底下的方法,要求的RetentionPolicy級(jí)別為RUNTIME @Pointcut("@target(org.springframework.stereotype.Repository)") public void annoTargetDemo(){} // 匹配傳入的參數(shù)類標(biāo)注有Repository注解的方法 @Pointcut("@args(org.springframework.stereotype.Repository)") public void annoArgsDemo(){}2-7 匹配方法
execution()格式
execution( modifier-pattern? // 修飾符匹配 ret-type-pattern // 返回值匹配 declaring-type-pattern? // 描述值包名 name-pattern(param-pattern) // 方法名匹配(參數(shù)匹配) throws-pattern?// 拋出異常匹配 )
execution()實(shí)例
// 匹配 使用public修飾符 任意返回值 在com.myimooc.springaopguide.service包及子下 // 以Service結(jié)尾的類 任意方法(任意參數(shù)) @Pointcut("execution(public * com.myimooc.springaopguide.service..*Service.*(..))") public void matchCondition(){}2-8 建言注解
5中Advice(建言)注解
@Before,前置通知 @After(finally),后置通知,方法執(zhí)行完之后 @AfterReturning,返回通知,成功執(zhí)行之后 @AfterThrowing,異常通知,拋出異常之后 @Around,環(huán)繞通知
5中Advice(建言)實(shí)例
// 定義切點(diǎn),攔截使用NeedSecured注解修飾的方法 @Pointcut("@within(com.myimooc.demo.security.NeedSecured)") public void annoTargetVsWithinDemo(){} // 使用NeedSecured注解修飾 且 在com.myimooc包下的方法 @Before("annoTargetVsWithinDemo() && within(com.myimooc..*)") public void beforeDemo(){ System.out.println("被攔截方法執(zhí)行之前執(zhí)行"); } @After("annoTargetVsWithinDemo() && within(com.myimooc..*)") public void afterDemo(){ System.out.println("被攔截方法執(zhí)行之后執(zhí)行"); } @AfterReturning("annoTargetVsWithinDemo() && within(com.myimooc..*)") public void afterReturning(){ System.out.println("代碼成功之后執(zhí)行"); } @AfterThrowing("annoTargetVsWithinDemo() && within(com.myimooc..*)") public void afterThrowing(){ System.out.println("代碼執(zhí)行拋出異常之后執(zhí)行"); } @Around("annoTargetVsWithinDemo() && within(com.myimooc..*)") public Object aroundDemo(ProceedingJoinPoint pjp) throws Throwable{ System.out.println("相當(dāng)于@Before"); try{ Object result = pjp.proceed(pjp.getArgs()); System.out.println("相當(dāng)于@AfterReturning"); return result; }catch (Throwable throwable) { System.out.println("相當(dāng)于@AfterThrowing"); throw throwable; }finally { System.out.println("相當(dāng)于@After"); } }
Advice中的參數(shù)及結(jié)果綁定
@Before("annoTargetVsWithinDemo() && within(com.myimooc..*) && args(userId)") public void beforeWithArgs(JoinPoint joinPoint,Long userId){ System.out.println("被攔截方法執(zhí)行之前執(zhí)行,args:"+userId); } @AfterReturning(value="annoTargetVsWithinDemo() && within(com.myimooc..*)",returning="returnValue") public void getResult(Object returnValue){ if(returnValue != null){ System.out.println("代碼成功之后執(zhí)行,result:"+returnValue); } }第三章:實(shí)現(xiàn)原理 3-1 本節(jié)內(nèi)容
上節(jié)回顧
Pointcut expression的組成部分 各種designators的區(qū)別 5中advice及參數(shù)、結(jié)果綁定
實(shí)現(xiàn)原理
概述 設(shè)計(jì):代理模式、責(zé)任鏈模式 實(shí)現(xiàn):JDK實(shí)現(xiàn)、cglib實(shí)現(xiàn)3-2 原理概述
原理概述:植入的時(shí)機(jī)
1.編譯期(AspectJ) 2.類加載時(shí)(Aspectj 5+) 3.運(yùn)行時(shí)(Spring AOP)【本節(jié)課講解內(nèi)容】
運(yùn)行時(shí)值入
運(yùn)行時(shí)織入是怎么實(shí)現(xiàn)的 從靜態(tài)代理到動(dòng)態(tài)代理 基于接口代理與基于繼承代理3-3 代理模式
代理AOP對(duì)象
Caller:調(diào)用方 Proxy:AOP代理對(duì)象 Target:目標(biāo)對(duì)象
代理模式類圖
客戶端通過(guò)接口來(lái)引用目標(biāo)對(duì)象 代理對(duì)象把真正的方法委托目標(biāo)對(duì)象來(lái)執(zhí)行,自己執(zhí)行額外的邏輯
代碼編寫
1.編寫Subject類
package com.myimooc.myproxydemo.pattern; /** * @title 代理對(duì)象接口 * @describe * @author zc * @version 1.0 2017-09-13 */ public interface Subject { void request(); }
2.編寫RealSubject類
package com.myimooc.myproxydemo.pattern; /** * @title 目標(biāo)對(duì)象 * @describe 實(shí)現(xiàn)了Subject接口 * @author zc * @version 1.0 2017-09-13 */ public class RealSubject implements Subject{ @Override public void request() { System.out.println("real subject execute request"); } }
3.編寫Proxy類
package com.myimooc.myproxydemo.pattern; /** * @title 代理對(duì)象 * @describe 同樣也實(shí)現(xiàn)了Subject接口 * @author zc * @version 1.0 2017-09-13 */ public class Proxy implements Subject{ // 需要引用目標(biāo)對(duì)象 private RealSubject realSubject; // 強(qiáng)制必須傳入目標(biāo)對(duì)象 public Proxy(RealSubject realSubject) { this.realSubject = realSubject; } @Override public void request() { // 在目標(biāo)對(duì)象方法執(zhí)行之前做一些額外的事情 System.out.println("before"); try{ // 代理對(duì)象不會(huì)做真實(shí)的業(yè)務(wù)邏輯,還是委托給真實(shí)的目標(biāo)對(duì)象執(zhí)行 realSubject.request(); }catch (Exception e) { System.out.println("ex:"+e.getMessage()); throw e; }finally { // 在目標(biāo)對(duì)象方法執(zhí)行之后做一些額外的事情 System.out.println("after"); } } }
4.編寫Client類
package com.myimooc.myproxydemo.pattern; /** * @title 客戶端 * @describe 測(cè)試代理模式 * @author zc * @version 1.0 2017-09-13 */ public class Client { public static void main(String[] args) { Subject subject = new Proxy(new RealSubject()); subject.request(); } }3-4 JDK代理
靜態(tài)代理與動(dòng)態(tài)代理
靜態(tài)代理的缺點(diǎn):每當(dāng)需要代理的方法越多的時(shí)候,重復(fù)的邏輯就越多 動(dòng)態(tài)代理的兩類實(shí)現(xiàn):基于接口代理與基于繼承代理 兩類實(shí)現(xiàn)的代表技術(shù):JDK代理與Cglib代理
JDK實(shí)現(xiàn)要點(diǎn)
類:java.lang.reflect.Proxy 接口:InvocationHandler 只能基于接口進(jìn)行動(dòng)態(tài)代理
代碼編寫
1.編寫JdkSubject類
package com.myimooc.myproxydemo.jdkimpl; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import com.myimooc.myproxydemo.pattern.RealSubject; /** * @title 動(dòng)態(tài)代理類 * @describe 相當(dāng)于AOP的aspect * @author zc * @version 1.0 2017-09-13 */ public class JdkSubject implements InvocationHandler{ // 同樣需要引入目標(biāo)對(duì)象 private RealSubject realSubject; public JdkSubject(RealSubject realSubject) { this.realSubject = realSubject; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 在目標(biāo)對(duì)象方法執(zhí)行之前做一些額外的事情 System.out.println("before"); Object result = null; try{ // 代理對(duì)象不會(huì)做真實(shí)的業(yè)務(wù)邏輯,還是委托給真實(shí)的目標(biāo)對(duì)象執(zhí)行 result = method.invoke(realSubject, args); }catch (Exception e) { System.out.println("ex:"+e.getMessage()); throw e; }finally { // 在目標(biāo)對(duì)象方法執(zhí)行之后做一些額外的事情 System.out.println("after"); } return result; } }
2.編寫Client類
package com.myimooc.myproxydemo.jdkimpl; import java.lang.reflect.Proxy; import com.myimooc.myproxydemo.pattern.RealSubject; import com.myimooc.myproxydemo.pattern.Subject; /** * @title 動(dòng)態(tài)代理類 * @describe JDK實(shí)現(xiàn)動(dòng)態(tài)代理測(cè)試類 * @author zc * @version 1.0 2017-09-13 */ public class Client { public static void main(String[] args) { Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader(), new Class[]{Subject.class}, new JdkSubject(new RealSubject())); subject.request(); } }3-5 JDK解析
JDK代理源碼解析
Proxy.newProxyInstance(首先,調(diào)用該方法) getProxyClass0、ProxyClassFactory、ProxyGenerator(然后,分別調(diào)用方法,生成字節(jié)碼) newInstance(最后,利用反射根據(jù)字節(jié)碼生成實(shí)例)3-6 Cglib代理
代碼編寫
1.編寫DemoMethodInterceptor類
package com.myimooc.myproxydemo.cglib; import java.lang.reflect.Method; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; /** * @title 需要植入的代碼類 * @describe 需要實(shí)現(xiàn)MethodInterceptorj接口 * @author zc * @version 1.0 2017-09-13 */ public class DemoMethodInterceptor implements MethodInterceptor{ @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before in cglib"); Object result = null; try{ // 代理類調(diào)用父類的方法 proxy.invokeSuper(obj, args); }catch (Exception e) { System.out.println("ex:"+e.getMessage()); throw e; }finally { // 在目標(biāo)對(duì)象方法執(zhí)行之后做一些額外的事情 System.out.println("after in cglib"); } return result; } }
2.編寫Client類
package com.myimooc.myproxydemo.cglib; import com.myimooc.myproxydemo.pattern.RealSubject; import com.myimooc.myproxydemo.pattern.Subject; import net.sf.cglib.proxy.Enhancer; /** * @title 動(dòng)態(tài)代理類 * @describe Cglib實(shí)現(xiàn)動(dòng)態(tài)代理測(cè)試類 * @author zc * @version 1.0 2017-09-13 */ public class Client { public static void main(String[] args) { // 實(shí)例化Enhancer對(duì)象 Enhancer enhancer = new Enhancer(); // 設(shè)置需要代理的對(duì)象 enhancer.setSuperclass(RealSubject.class); // 設(shè)置需要植入的代碼 enhancer.setCallback(new DemoMethodInterceptor()); // 生成代理類 Subject subject = (Subject)enhancer.create(); subject.request(); } }
JDK與Cglib代理對(duì)比
JDK只能針對(duì)有接口的類的接口方法進(jìn)行動(dòng)態(tài)代理 Cglib基于繼承來(lái)實(shí)現(xiàn)代理,無(wú)法對(duì)static、final類進(jìn)行代理 Cglib基于繼承來(lái)實(shí)現(xiàn)代理,無(wú)法對(duì)private、static方法進(jìn)行代理3-7 Spring選擇
Spring創(chuàng)建代理bean時(shí)序圖
SpringAOP對(duì)兩種實(shí)現(xiàn)的選擇
如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,則默認(rèn)采用JDK動(dòng)態(tài)代理 如果目標(biāo)對(duì)象沒(méi)有實(shí)現(xiàn)接口,則采用Cglib進(jìn)行動(dòng)態(tài)代理 如果目標(biāo)對(duì)象實(shí)現(xiàn)了接口,但設(shè)置強(qiáng)制cglib代理,則使用cglib代理 在SpringBoot中,通過(guò)@EnableAspectJAutoProxy(proxyTargetClass=true)設(shè)置3-8 鏈?zhǔn)秸{(diào)用
當(dāng)多個(gè)AOP作用到同一個(gè)目標(biāo)對(duì)象時(shí),采用責(zé)任鏈模式
責(zé)任鏈模式類圖
代碼編寫
1.編寫Handler類
package com.myimooc.myproxydemo.chain; /** * @title 責(zé)任鏈模式 * @describe 抽象接口 * @author zc * @version 1.0 2017-09-13 */ public abstract class Handler { // 后繼Handler,是否有類進(jìn)行處理 private Handler sucessor; // 對(duì)外暴露 public void execute(){ handleProcess(); if(sucessor != null){ sucessor.execute(); } } // 由子類實(shí)現(xiàn) protected abstract void handleProcess(); public Handler getSucessor() { return sucessor; } public void setSucessor(Handler sucessor) { this.sucessor = sucessor; } }
2.編寫Client類
package com.myimooc.myproxydemo.chain; /** * @title 責(zé)任鏈模式 * @describe 測(cè)試類 * @author zc * @version 1.0 2017-09-13 */ public class Client { static class HandlerA extends Handler{ @Override protected void handleProcess() { System.out.println("handle by a"); } } static class HandlerB extends Handler{ @Override protected void handleProcess() { System.out.println("handle by b"); } } static class HandlerC extends Handler{ @Override protected void handleProcess() { System.out.println("handle by c"); } } public static void main(String[] args) { HandlerA handlerA = new HandlerA(); HandlerB HandlerB = new HandlerB(); HandlerC HandlerC = new HandlerC(); // 設(shè)置鏈接關(guān)系 handlerA.setSucessor(HandlerB); HandlerB.setSucessor(HandlerC); handlerA.execute(); } }
3.編寫Chain類
package com.myimooc.myproxydemo.chain; import java.util.List; /** * @title 責(zé)任鏈模式 * @describe 封裝鏈?zhǔn)疥P(guān)系 * @author zc * @version 1.0 2017-09-13 */ public class Chain { private Listhandlers; private int index = 0; public Chain(List handlers){ this.handlers = handlers; } public void proceed(){ if(index >= handlers.size()){ return; } handlers.get(index++).execute(this); } }
4.編寫ChainHandler類
package com.myimooc.myproxydemo.chain; /** * @title 責(zé)任鏈模式 * @describe 對(duì)Handler進(jìn)行封裝 * @author zc * @version 1.0 2017-09-13 */ public abstract class ChainHandler { public void execute(Chain chain){ handleProcess(); chain.proceed(); } // 由子類實(shí)現(xiàn) protected abstract void handleProcess(); }
5.編寫ChainClient類
package com.myimooc.myproxydemo.chain; import java.util.Arrays; import java.util.List; /** * @title 責(zé)任鏈模式 * @describe 有順序的鏈?zhǔn)秸{(diào)用測(cè)試類 * @author zc * @version 1.0 2017-09-13 */ public class ChainClient { static class ChainHandlerA extends ChainHandler{ @Override protected void handleProcess() { System.out.println("handle by a"); } } static class ChainHandlerB extends ChainHandler{ @Override protected void handleProcess() { System.out.println("handle by b"); } } static class ChainHandlerC extends ChainHandler{ @Override protected void handleProcess() { System.out.println("handle by c"); } } public static void main(String[] args) { // 聲明鏈?zhǔn)秸{(diào)用順序 List第四章:代碼解讀 4-1 本節(jié)內(nèi)容handlers = Arrays.asList( new ChainHandlerA(), new ChainHandlerB(), new ChainHandlerC() ); Chain chain = new Chain(handlers); chain.proceed(); } }
上節(jié)回顧
靜態(tài)代理與動(dòng)態(tài)代理 JDK代理與Cglib代理區(qū)別及局限 代理模式與責(zé)任鏈模式
Spring AOP在開(kāi)源項(xiàng)目里面的應(yīng)用:三個(gè)例子
事務(wù):@Transactional:Spring如何利用Transaction進(jìn)行事務(wù)控制 安全:@PreAuthorize:Spring Security如何利用PreAuthorize進(jìn)行安全控制 緩存:@Cacheable:Spring Cache如何利用Cacheable進(jìn)行緩存控制
通過(guò)案例來(lái)講解,源碼可到我的github地址查看
第五章:實(shí)戰(zhàn)案例 5-1 案例背景實(shí)戰(zhàn)案例背景
商家產(chǎn)品管理系統(tǒng) 記錄產(chǎn)品修改的操作記錄 什么人在什么時(shí)間修改了哪些產(chǎn)品的哪些字段修改為什么值
實(shí)現(xiàn)思路
利用aspect去攔截增刪改方法 利用反射獲取對(duì)象的新舊值 利用@Around的advice去記錄操作記錄5-2 案例實(shí)現(xiàn)
創(chuàng)建名為mydatalog的maven項(xiàng)目pom如下
4.0.0 com.myimooc mydatalog 0.0.1-SNAPSHOT jar mydatalog http://maven.apache.org org.springframework.boot spring-boot-starter-parent 1.5.2.RELEASE UTF-8 UTF-8 1.8 org.springframework.boot spring-boot-starter-aop org.springframework.boot spring-boot-starter-data-jpa mysql mysql-connector-java org.springframework.boot spring-boot-starter-test test commons-beanutils commons-beanutils com.alibaba fastjson 1.2.36
完成后的項(xiàng)目結(jié)構(gòu)圖如下
受篇幅限制,源碼請(qǐng)到我的github地址查看
第六章:課程總結(jié) 6-1 課程總結(jié)要點(diǎn)清單
AOP的適用范圍及優(yōu)劣勢(shì) AOP的概念及Spring切面表達(dá)式 AOP的實(shí)現(xiàn)原理及運(yùn)用
使用SpringAOP的注意事項(xiàng)
不宜把重要的業(yè)務(wù)邏輯放到AOP中處理 無(wú)法攔截static、final、private方法 無(wú)法攔截內(nèi)部方法調(diào)用
課程小結(jié)
合理利用面向切面編程提高代碼質(zhì)量 掌握SpringAOP概念及實(shí)現(xiàn)原理 了解AOP的優(yōu)缺點(diǎn)及SpringAOP的使用局限
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://www.ezyhdfw.cn/yun/70475.html
摘要:入門篇學(xué)習(xí)總結(jié)時(shí)間年月日星期三說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。主要的功能是日志記錄,性能統(tǒng)計(jì),安全控制,事務(wù)處理,異常處理等等。 《Spring入門篇》學(xué)習(xí)總結(jié) 時(shí)間:2017年1月18日星期三說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:https://github.com/zccodere/s...個(gè)人學(xué)習(xí)源碼:https://git...
摘要:時(shí)間年月日星期日說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。慕課網(wǎng)教學(xué)示例源碼個(gè)人學(xué)習(xí)源碼第一章課程介紹課程介紹本課程緊接著小時(shí)學(xué)會(huì)課程,請(qǐng)先看入門課。異常返回通知在連接點(diǎn)拋出異常后執(zhí)行。 時(shí)間:2017年3月19日星期日說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)示例源碼:https://github.com/zccodere/s...個(gè)人學(xué)習(xí)源碼:htt...
摘要:事務(wù)管理學(xué)習(xí)總結(jié)時(shí)間年月日星期二說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。一致性一致性指事務(wù)前后數(shù)據(jù)的完整性必須保持一致。聲明式事務(wù)管理基于的方式很少使用需要為每個(gè)進(jìn)行事務(wù)管理的類,配置一個(gè)進(jìn)行增強(qiáng)。 《Spring事務(wù)管理》學(xué)習(xí)總結(jié) 時(shí)間:2017年2月7日星期二說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com/教學(xué)示例源碼:https://github.com...
摘要:時(shí)間年月日星期六說(shuō)明本文部分內(nèi)容均來(lái)自慕課網(wǎng)。慕課網(wǎng)教學(xué)源碼學(xué)習(xí)源碼第一章課程介紹課程簡(jiǎn)介是啥讀音是輕量級(jí)的依賴注入框架說(shuō)明一個(gè)的框架需要有基礎(chǔ)什么是剝離注入輕量級(jí)代碼少易維護(hù)性能優(yōu)異,跟比較。 時(shí)間:2017年10月14日星期六說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com 教學(xué)源碼:https://github.com/zccodere/s......
時(shí)間:2017年08月16日星期三說(shuō)明:本文部分內(nèi)容均來(lái)自慕課網(wǎng)。@慕課網(wǎng):http://www.imooc.com教學(xué)源碼:無(wú)學(xué)習(xí)源碼:https://github.com/zccodere/s... 第一章:課程介紹 1-1 課程介紹 課程目錄 1.ssh知識(shí)點(diǎn)回顧 2.搭建ssm開(kāi)發(fā)環(huán)境 3.struts2整合spring 4.spring整合hibernate 5.案例:使用ssh框架開(kāi)發(fā)...
閱讀 2546·2021-11-16 11:45
閱讀 2531·2021-10-11 10:59
閱讀 2325·2021-10-08 10:05
閱讀 3990·2021-09-23 11:30
閱讀 2433·2021-09-07 09:58
閱讀 938·2019-08-30 15:55
閱讀 826·2019-08-30 15:53
閱讀 1981·2019-08-29 17:00