AOP 爲 Aspect Oriented Programming 的縮寫,意思爲面向切面編程,是經過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。面試
目的:
利用AOP能夠對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度下降,提升程序的可重用性,同時提升了開發的效率。spring
做用:在程序運行期間,在不修改源碼的狀況下對方法進行功能加強express
優點: 減小重複代碼,提升開發效率,而且便於維護編程
AOP 的底層是經過 Spring 提供的的動態代理技術實現的。在運行期間,Spring經過動態代理技術動態的生成代理對象,代理對象方法執行時進行加強功能的介入,在去調用目標對象的方法,從而完成功能的加強。app
JDK 代理 : 基於接口的動態代理技術框架
cglib 代理:基於父類的動態代理技術ide
①目標類接口測試
public interface TargetInterface { public void method(); }
②目標類spa
public class Target implements TargetInterface { @Override public void method() { System.out.println("Target running...."); } }
③動態代理代碼代理
Target target = new Target(); //建立目標對象 //建立代理對象 TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(target.getClass() .getClassLoader(),target.getClass().getInterfaces(),new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("前置加強代碼..."); Object invoke = method.invoke(target, args); System.out.println("後置加強代碼..."); return invoke; } } );
④ 調用代理對象的方法測試
// 測試,當調用接口的任何方法時,代理對象的代碼都無需修改 proxy.method();
①目標類
public class Target { public void method() { System.out.println("Target running...."); } }
②動態代理代碼
Target target = new Target(); //建立目標對象 Enhancer enhancer = new Enhancer(); //建立加強器 enhancer.setSuperclass(Target.class); //設置父類 enhancer.setCallback(new MethodInterceptor() { //設置回調 @Override public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { System.out.println("前置代碼加強...."); Object invoke = method.invoke(target, objects); System.out.println("後置代碼加強...."); return invoke; } }); Target proxy = (Target) enhancer.create(); //建立代理對象
③調用代理對象的方法測試
//測試,當調用接口的任何方法時,代理對象的代碼都無需修改 proxy.method();
aop:面向切面編程
aop底層實現:基於JDK的動態代理 和 基於Cglib的動態代理
aop的重點概念:
Pointcut(切入點):被加強的方法 Advice(通知/ 加強):封裝加強業務邏輯的方法 Aspect(切面):切點+通知 Weaving(織入):將切點與通知結合的過程
開發明確事項:
誰是切點(切點表達式配置) 誰是通知(切面類中的加強方法) 將切點和通知進行織入配置
①導入 AOP 相關座標
<!--導入spring的context座標,context依賴aop--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!--spring測試的依賴--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.2.5.RELEASE</version> </dependency> <!-- aspectj的織入 --> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.2</version> </dependency>
②建立目標接口和目標類(內部有切點)
public interface TestService { public void save(); } public class TestServiceImpl implements TestService { public void save() { System.out.println("save方法runnning......"); } }
③建立切面類(內部有加強方法)
public class Advice { //前置加強的通知 public void before(){ System.out.println("前置加強......"); } }
④將目標類和切面類的對象建立權交給 spring
<!--配置目標類--> <bean id="testService" class="com.duanping.service.impl.TestServiceImpl"></bean> <!--配置切面類--> <bean id="advice" class="com.duanping.advices.Advice"></bean>
⑤在 applicationContext.xml 中配置織入關係
導入aop命名空間
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd ">
配置切點表達式和前置加強的織入關係
<!--配置織入: 告訴spring框架 哪些方法(切點)須要進行哪些加強(前置、後置....) --> <aop:config> <!-- 聲明切面 引入advice的bean做爲切面對象--> <aop:aspect ref="advice"> <!--切面: 通知+切點 配置對切點的方法進行前置加強--> <aop:before method="before" pointcut="execution(public void com.duanping.service.impl.TestServiceImpl.save())"></aop:before> </aop:aspect> </aop:config>
⑥測試代碼
@RunWith(SpringJUnit4Cla***unner.class) @ContextConfiguration("classpath:applicationContext.xml") public class AopTest { @Autowired private TestService testService; @Test public void test1(){ testService.save(); } }
⑦測試結果
表達式語法:
execution([修飾符] 返回值類型 包名.類名.方法名(參數))
訪問修飾符能夠省略
返回值類型、包名、類名、方法名可使用星號* 表明任意
包名與類名之間一個點 . 表明當前包下的類,兩個點 … 表示當前包及其子包下的類
參數列表可使用兩個點 … 表示任意個數,任意類型的參數列表
例如:
execution(public void com.itheima.aop.Target.method()) execution(void com.itheima.aop.Target.*(..)) execution(* com.itheima.aop.*.*(..)) execution(* com.itheima.aop..*.*(..)) execution(* *..*.*(..))
通知的配置語法:
<aop:通知類型 method=「切面類中方法名」 pointcut=「切點表達式"></aop:通知類型>
當多個加強的切點表達式相同時,能夠將切點表達式進行抽取,在加強中使用 pointcut-ref 屬性代替 pointcut 屬性來引用抽取後的切點表達式。
<!--對切點的抽取--> <aop:pointcut id="point" expression="execution(* com.duanping.service.impl.*.*(..))"/> <aop:before method="before" pointcut-ref="point"></aop:before>
在配置文件中開啓組件掃描和 AOP 的自動代理
<!--組件掃描--> <context:component-scan base-package="com.itheima.aop"/> <!--aop的自動代理--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
通知的配置語法:@通知註解(「切點表達式")
同 xml配置
aop 同樣,咱們能夠將切點表達式抽取。抽取方式是在切面內定義方法,在該方法上使用@Pointcut註解定義切點表達式,而後在在加強註解中進行引用
@Pointcut("execution(* com.duanping..*.*(..))") public void pointcut(){} //前置加強的通知 @Before("pointcut()") public void before(){ System.out.println("前置加強......"); }
註解aop開發步驟
①使用@Aspect標註切面類
②使用@通知註解標註通知方法
③在配置文件中配置aop自動代理aop:aspectj-autoproxy/\
你們看完有什麼不懂的能夠在下方留言討論,也能夠關注我私信問我,我看到後都會回答的。也能夠關注個人公衆號:前程有光,金三銀四跳槽面試季,整理了1000多道將近500多頁pdf文檔的Java面試題資料,文章都會在裏面更新,整理的資料也會放在裏面。謝謝你的觀看,以爲對你有幫助的話能夠專一我點個贊支持一下!