javascript
Spring 面向切面编程(AOP) D5
Spring AOP簡介
問題提出
首先我們回顧一下OOP(Object Oriented Programming-面向?qū)ο缶幊?#xff09;,OOP引入了封裝、繼承、多態(tài)等概念建立了一種對象層次結(jié)構(gòu),用于模擬公共行為的一個集合。不過OOP允許開發(fā)者定義縱向的關(guān)系,并不適合定義橫向的關(guān)系(例如日志功能)。 日志代碼常常是橫向的散布在所有對象層次中,這種散布在各處的重復(fù)的代碼被稱為橫切(cross cutting)。如果仍然使用OOP設(shè)計,會導(dǎo)致大量的代碼重復(fù),不利于各模塊的重用。因而我們引入AOP的編程思想。
面向切面編程
AOP(Aspect Oriented Programming),即面向切面編程,可以說是OOP的補充和完善。
在面向切面編程的思想里面,把功能分為核心業(yè)務(wù)功能和周邊功能。
- 核心業(yè)務(wù): 比如登陸、CRUD等;
- 周邊功能: 比如性能統(tǒng)計、日志、事務(wù)管理等
上述的周邊功能在Spring的AOP思想中,被定義為切面。
在AOP思想里,核心業(yè)務(wù)功能和切面功能分別獨立開發(fā),隨后把切面功能和核心業(yè)務(wù)“編織”在一起,這就叫AOP。
AOP 好處
AOP能夠?qū)⒛切┖蜆I(yè)務(wù)無關(guān),卻被業(yè)務(wù)模塊共同調(diào)用的邏輯或責任(例如事務(wù)處理、日志管理、權(quán)限控制等)封裝起來,便于減少系統(tǒng)的重復(fù)代碼,降低模塊之間的耦合度,并且有利于未來的擴展和維護。
AOP 中的概念(理解即可)
-
切入點(Pointcut)
在哪些類、哪些方法上切入
-
通知(Advice)
在方法執(zhí)行的什么時機(方法前?后?前和后?)增強什么功能
-
切面(Aspect)
切面 = 切入點 + 通知,即在什么時機,哪個地方,增強什么功能!
-
織入(Weaving)
把切面加入到對象中,并創(chuàng)建出代理對象的過程。(Spring實現(xiàn))
AOP的一個案例
也可參照我的前一篇博客: Spring 代理模式
AOP 實現(xiàn)
問題背景說明:現(xiàn)有UserService接口(提供用戶的CRUD),UserServiceImpl類(實現(xiàn)接口中方法)。如下:(均在service包下)
package service;public interface UserService {public void add();public void delete();public void update();public void select(); } package service;public class UserServiceImpl implements UserService {public void add() {System.out.println("增加了一個用戶");}public void delete() {System.out.println("刪除了一個用戶");}public void update() {System.out.println("更新信息");}public void select() {System.out.println("查詢用戶");} }需求: 對方法的執(zhí)行實現(xiàn)追蹤,即添加簡易的日志功能!
注意: 使用aop織入,需要引入相應(yīng)的依賴,代碼如下:
<dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version> </dependency>方法一(使用原生Spring API接口)
首先創(chuàng)建log包,創(chuàng)建兩個類:Log 、 AfterLog,分別實現(xiàn)相應(yīng)的接口。代碼如下:
Log:
package log;import org.springframework.aop.MethodBeforeAdvice;import java.lang.reflect.Method;public class Log implements MethodBeforeAdvice {//method:要執(zhí)行的目標對象的方法//objects: 參數(shù)//target: 目標對象public void before(Method method, Object[] objects, Object target) throws Throwable {System.out.println(o.getClass().getName()+"的"+method.getName()+"被執(zhí)行了!");} }AfterLog:
package log;import org.springframework.aop.AfterReturningAdvice;import java.lang.reflect.Method;public class AfterLog implements AfterReturningAdvice {public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable {System.out.println("執(zhí)行了"+method.getName()+",返回結(jié)果為:"+returnValue);} }applicationContext.xml中配置:(放在resources包下)
<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--注冊bean--><bean id="userService" class="com.demut.service.UserServiceImpl"/><bean id="log" class="com.demut.log.Log"/><bean id="afterLog" class="com.demut.log.AfterLog"/><!--方式一: 使用原生Spring API接口--><!--配置aop: 需要導(dǎo)入aop的約束--><aop:config><!--切入點 : expression: 表達式,execution(要執(zhí)行的位置!* * * * *)--><aop:pointcut id="pointcut" expression="execution(* com.demut.service.UserServiceImpl.*(..))"/><!--執(zhí)行環(huán)繞增加!--><aop:advisor advice-ref="log" pointcut-ref="pointcut"/><aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/></aop:config></beans>測試類:
import com.demut.service.UserService; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext;public class MyTest {public static void main(String[] args) {ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");//動態(tài)代理 代理的是接口!!!UserService userService = context.getBean("userService", UserService.class);userService.select();} }運行結(jié)果:
此方法中重點關(guān)注,applicationContext.xml中配置!
方法二(自定義類來實現(xiàn))
創(chuàng)建diy包,在內(nèi)部創(chuàng)建類:DiyPointCut,類中內(nèi)容如下:
package com.demut.diy;public class DiyPointCut {public void before() {System.out.println("************方法執(zhí)行前************");}public void after() {System.out.println("************方法執(zhí)行后************");} }修改applicationContext.xml中內(nèi)容為:
<?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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--注冊bean--><bean id="userService" class="com.demut.service.UserServiceImpl"/><bean id="log" class="com.demut.log.Log"/><bean id="afterLog" class="com.demut.log.AfterLog"/><!--方式二:自定義類--><bean id="diy" class="com.demut.diy.DiyPointCut"/><aop:config><!--自定義切面ref要引用的類--><aop:aspect ref="diy"><!--切入點--><aop:pointcut id="point" expression="execution(* com.demut.service.UserServiceImpl.*(..))"/><!--通知--><aop:before method="before" pointcut-ref="point"/><aop:after method="after" pointcut-ref="point"/></aop:aspect></aop:config></beans>測試結(jié)果:
方法三(使用注解實現(xiàn))
使用到的注解:
- @Aspect
- @Before
- @After
- @Around
在diy包下新建類: AnnotationPointCut類:
package com.demut.diy;import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.Signature; import org.aspectj.lang.annotation.After; import org.aspectj.lang.annotation.Around; import org.aspectj.lang.annotation.Aspect; import org.aspectj.lang.annotation.Before;@Aspect //標注這個類是一個切面 public class AnnotationPointCut {@Before("execution(* com.demut.service.UserServiceImpl.*(..))")public void before() {System.out.println("==============方法執(zhí)行前==============");}@After("execution(* com.demut.service.UserServiceImpl.*(..))")public void after() {System.out.println("==============方法執(zhí)行后==============");}//在環(huán)繞增強中,我們可以給定一個參數(shù),代表我們要獲取處理切入的點@Around("execution(* com.demut.service.UserServiceImpl.*(..))")public void around(ProceedingJoinPoint jp) throws Throwable {System.out.println("環(huán)繞前");//獲取簽名~獲取執(zhí)行的是哪個類中的哪個方法Signature signature = jp.getSignature();System.out.println(signature);//執(zhí)行方法Object proceed = jp.proceed();System.out.println("環(huán)繞后");} }在applicationContext.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:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttps://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttps://www.springframework.org/schema/aop/spring-aop.xsd"><!--注冊bean--><bean id="userService" class="com.demut.service.UserServiceImpl"/><bean id="log" class="com.demut.log.Log"/><bean id="afterLog" class="com.demut.log.AfterLog"/><!--方式三:使用注解--><bean id="annotationPointCut" class="com.demut.diy.AnnotationPointCut"/><!--開啟注解支持--><aop:aspectj-autoproxy/></beans>測試結(jié)果:
【參考文章】
https://www.cnblogs.com/xrq730/p/4919025.html
https://www.jianshu.com/p/994027425b44
寫在最后
瀑布的水逆流而上,
蒲公英種子從遠處飄回,聚成傘的模樣,
太陽從西邊升起,落向東方。
子彈退回槍膛,
運動員回到起跑線上,
我交回錄取通知書,忘了十年寒窗。
廚房里飄來飯菜的香,
你把我的卷子簽好名字,
關(guān)掉電視,幫我把書包背上
你還在我身旁。
? ——戴暢
總結(jié)
以上是生活随笔為你收集整理的Spring 面向切面编程(AOP) D5的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 微信小程序商城项目(篇7):商城详情页实
- 下一篇: Springboot集成聚合数据火车票A