- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) > 編程語(yǔ)言 >
- Spring框架學(xué)習之AOP詳解
1.面向切面編程(方面),利用 AOP 可以對業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低,提高程序的可重用性,同時(shí)提高了開(kāi)發(fā)的效率。
2.通俗描述:不通過(guò)修改源代碼方式,在主干功能里面添加新功能
有兩種情況動(dòng)態(tài)代理
1.被代理的對象
public class UserDaoImpl implements UserDao { @Override public int add(int a, int b) { System.out.println("add執行"); return a + b; } @Override public String update(String id) { System.out.println("update執行"); return id; } }
2.代理
package cn.zj.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; import cn.zj.dao.UserDao; import cn.zj.dao.impl.UserDaoImpl; public class JDKProxy { public static void main(String[] args) { // 創(chuàng )建接口實(shí)現類(lèi)代理對象 Class[] interfaces = { UserDao.class }; UserDaoImpl userDao = new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); int result = dao.add(1, 2); System. out .println( "result:"+result); } } //創(chuàng )建代理對象代碼 class UserDaoProxy implements InvocationHandler { private Object target;// 目標類(lèi) public UserDaoProxy(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // 方法執行之前 System.out.println("方法執行之前.." + method.getName() + ";傳遞的參數:" + Arrays.toString(args)); // 增強方法 Object res = method.invoke(target, args); // 方法執行之后 System.out.println("方法執行之后.." + target); return res; } }
3.打印
方法執行之前..add;傳遞的參數:[1, 2] add執行 方法執行之后..cn.zj.dao.impl.UserDaoImpl@6c629d6e result:3
1.被代理的對象
public class Cat { public void eat() { System.out.println("貓吃魚(yú)"); } }
2.代理
public class CglibProxy { public static void main(String[] args) { Cat c = new CglibProxy().createProxyObject(Cat.class); c.eat(); } // JDK代理是對對象做代理,cglib代理是對類(lèi)做代理 public Cat createProxyObject(Class clazz) { // 1.創(chuàng )建內存中的動(dòng)態(tài)類(lèi) Enhance // 內存中造出一個(gè)沒(méi)有名稱(chēng)的動(dòng)態(tài)類(lèi) Enhancer enhancer = new Enhancer(); // 2.現在的類(lèi)最終完成原始類(lèi)的功能,同時(shí)對其進(jìn)行功能的增強,必須先具有原始類(lèi)對應的功能————繼承 enhancer.setSuperclass(clazz); // 3.進(jìn)行功能的增強 // 設置了方法的調用攔截 // 設置具體的回調操作 Callback callback = new MethodInterceptor() { // proxy:代理對象 // method:被攔截的方法對象 // args:調用參數 // methodProxy: public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { // 做增強 System.out.println("執行前"); // Object obj=method.invoke(proxy, args);//這種執行是代理類(lèi)的方法,而不是目標類(lèi)的,會(huì )造成內存溢出 // 以下的兩種都是執行目標類(lèi)的方法 // Object obj = methodProxy.invokeSuper(proxy, args);//執行目標類(lèi)的方法 // Object obj=method.invoke(proxy, args); Object res = methodProxy.invokeSuper(proxy, args); System.out.println("執行后"); return res; } }; enhancer.setCallback(callback); // 4.創(chuàng )建內存中的全新的類(lèi)的對象 Object proxyObj = enhancer.create(); return (Cat) proxyObj; } }
1.連接點(diǎn)(Joinpoint)
類(lèi)中的任意方法的運行時(shí)表示,可以簡(jiǎn)單理解為類(lèi)中的方法,也就是可以被增強的方法
2.切入點(diǎn)(Pointcut)
具有共性功能的方法的運行時(shí)表示,可以簡(jiǎn)單理解為具有共性功能的方法,也就是實(shí)際被增強的方法
注意:切入點(diǎn)對應的是被挖去了共性功能后的方法執行時(shí)匹配斷言(格式)
3.通知/增強(Advice)
共性功能模塊化,可以簡(jiǎn)單理解為將共性功能抽取出來(lái)制作成獨立的方法,實(shí)際增強的邏輯部分
類(lèi)型:前置,后置,異常,最終,環(huán)繞
4.切面(Aspect)
切入點(diǎn)與通知的對應關(guān)系,可以簡(jiǎn)單理解為被抽取的共性功能與共性功能被抽取位置對應的方法之間的關(guān)系,把通知應用到切入點(diǎn)的過(guò)程
5.目標對象(Target Object)
包含切入點(diǎn)的運行時(shí)對象,開(kāi)發(fā)階段制作的是目標對象對應的類(lèi)
6.AOP代理(AOP Proxy)
使用AOP的代理機制創(chuàng )建目標對象運行時(shí)代理對象,完成原始的功能
注意:原始目標對象已經(jīng)被挖去了共性功能,此時(shí)使用目標對象執行任務(wù)無(wú)法完成原始任務(wù),使用AOP代理機制,創(chuàng )建一個(gè)代理對象來(lái)完成原始目標對象的功能
7.織入(Weaving)
是一個(gè)將通知功能加入原始字節碼的動(dòng)態(tài)過(guò)程,將增強添加對目標類(lèi)具體連接點(diǎn)上的過(guò)程
Spring使用的是運行時(shí)織入機制
8.引入(Introduction)
一種特殊的機制,可以為一個(gè)類(lèi)的字節碼動(dòng)態(tài)的加入變量或方法
AspectJ 不是 Spring 組成部分,獨立 AOP 框架,一般把 AspectJ 和 Spirng 框架一起使
用,進(jìn)行 AOP 操作
1.jar包引入
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> <version>5.3.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> <version>5.3.6</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.3.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-expression --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-expression</artifactId> <version>5.3.6</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>5.3.6</version> </dependency> <!-- https://mvnrepository.com/artifact/commons-logging/commons-logging --> <dependency> <groupId>commons-logging</groupId> <artifactId>commons-logging</artifactId> <version>1.2</version> </dependency> <!-- https://mvnrepository.com/artifact/com.alibaba/druid --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.2.6</version> </dependency> <!-- @Resource注解需要 --> <dependency> <groupId>javax.annotation</groupId> <artifactId>javax.annotation-api</artifactId> <version>1.3.1</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>5.3.6</version> </dependency> <!-- https://mvnrepository.com/artifact/net.sourceforge.cglib/com.springsource.net.sf.cglib --> <dependency> <groupId>net.sourceforge.cglib</groupId> <artifactId>com.springsource.net.sf.cglib</artifactId> <version>2.2.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aopalliance/com.springsource.org.aopalliance --> <dependency> <groupId>org.aopalliance</groupId> <artifactId>com.springsource.org.aopalliance</artifactId> <version>1.0.0</version> </dependency> <!-- https://mvnrepository.com/artifact/org.aspectj/com.springsource.org.aspectj.weaver --> <dependency> <groupId>org.aspectj</groupId> <artifactId>com.springsource.org.aspectj.weaver</artifactId> <version>1.6.8.RELEASE</version> </dependency> </dependencies>
2.切入點(diǎn)表達式
作用:知道對哪個(gè)類(lèi)里面的哪個(gè)方法進(jìn)行增強
語(yǔ)法結構: execution([權限修飾符] [返回類(lèi)型] [類(lèi)全路徑] 方法名稱(chēng) )
舉例 1:對 com.zj.dao.BookDao 類(lèi)里面的 add 進(jìn)行增強
execution(* com.zj.dao.BookDao.add(…))
舉例 2:對 com.zj.dao.BookDao 類(lèi)里面的所有的方法進(jìn)行增強
execution(* com.zj.dao.BookDao.* (…))
舉例 3:對 com.zj.dao 包里面所有類(lèi),類(lèi)里面所有方法進(jìn)行增強
execution(* com.zj.dao.. (…))
3.xml方式
1.創(chuàng )建類(lèi)
package cn.zj.aop.xml; public class Book { public void buy() { System.out.println("buy............."); } }
2.增強類(lèi)
package cn.zj.aop.xml; public class BookProxy { public void before() { System.out.println("before........."); } }
3.xml
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--創(chuàng )建對象--> <bean id="book" class="cn.zj.aop.xml.Book"></bean> <bean id="bookProxy" class="cn.zj.aop.xml.BookProxy"></bean> <!--配置aop增強--> <aop:config> <!--切入點(diǎn)--> <aop:pointcut id="p" expression="execution(* cn.zj.aop.xml.Book.buy(..))"/> <!--配置切面--> <aop:aspect ref="bookProxy"> <!--增強作用在具體的方法上--> <aop:before method="before" pointcut-ref="p"/> </aop:aspect> </aop:config> </beans>
4.注解方式
1.創(chuàng )建類(lèi)
public class User { public void add() { System.out.println("add......."); } }
2.創(chuàng )建增強類(lèi)
package cn.zj.aop.an; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.AfterReturning; import org.aspectj.lang.annotation.AfterThrowing; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before; import org.aspectj.lang.annotation.Pointcut; import org.springframework.stereotype.Component; //增強的類(lèi) @Component @Aspect //生成代理對象 public class UserProxy { //前置通知 @Before(value = "execution(* cn.zj.aop.an.User.add(..))") public void before() { System.out.println("before........."); } //后置通知(返回通知) @AfterReturning(value = "execution(* cn.zj.aop.an.User.add(..))") public void afterReturning() { System.out.println("afterReturning........."); } //最終通知 @After(value = "execution(* cn.zj.aop.an.User.add(..))") public void after() { System.out.println("after........."); } //異常通知 @AfterThrowing(value = "execution(* cn.zj.aop.an.User.add(..))") public void afterThrowing() { System.out.println("afterThrowing........."); } //環(huán)繞通知 @Around(value = "execution(* cn.zj.aop.an.User.add(..))") public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable { System.out.println("環(huán)繞之前........."); //被增強的方法執行 proceedingJoinPoint.proceed(); System.out.println("環(huán)繞之后........."); } }
3.xml配置注解掃描
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <!-- 開(kāi)啟注解掃描 --> <context:component-scan base-package="cn.zj.aop.an"></context:component-scan> <!-- 開(kāi)啟Aspect生成代理對象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy> </beans>
4.測試
ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml"); User user = context.getBean("user", User.class); user.add();
5.相同點(diǎn)抽取
//相同切入點(diǎn)抽取 @Pointcut(value = "execution(* cn.zj.aop.an.User.add(..))") public void pointdemo() { } //前置通知 //@Before注解表示作為前置通知 @Before(value = "pointdemo()") public void before() { System.out.println("before........."); }
6.有多個(gè)增強類(lèi)多同一個(gè)方法進(jìn)行增強,設置增強類(lèi)優(yōu)先級
在增強類(lèi)上面添加注解 @Order(數字類(lèi)型值),數字類(lèi)型值越小優(yōu)先級越高
@Component @Aspect @Order(1) public class PersonProxy { //后置通知(返回通知) @Before(value = "execution(* cn.zj.aop.an.User.add(..))") public void afterReturning() { System.out.println("Person Before........."); } } //增強的類(lèi) @Component @Aspect //生成代理對象 @Order(2) public class UserProxy {
到此這篇關(guān)于Spring框架學(xué)習之AOP詳解的文章就介紹到這了,更多相關(guān)Spring框架AOP內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自本網(wǎng)站內容采集于網(wǎng)絡(luò )互聯(lián)網(wǎng)轉載等其它媒體和分享為主,內容觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如侵犯了原作者的版權,請告知一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容,聯(lián)系我們QQ:712375056,同時(shí)歡迎投稿傳遞力量。
Copyright ? 2009-2022 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 特網(wǎng)科技 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 百度云 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站