什麼是AOP?
AOP(Aspect Oriented Programming)意為:面向切面程式設計,通過預編譯方式和運作期動态代理實作程式功能的統一維護的一種技術。AOP是0OP的延續,是軟體開發中的一個熱點,也是Spring架構中的一個重要内容,是函數式程式設計的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,進而使得業務邏輯各部分之間的耦合度降低,提高程式的可重用性,同時提高了開發的效率。
AOP在Spring中的作用:
提供聲明式事務,允許使用者自定義切面
橫切關注點:跨越應用程式多個子產品的方法或功能。即是,與我們業務邏輯無關的,但是我們需要關注的部分,就是橫切關注點。如日志,安全,緩存,事務等等..
切面(ASPECT):橫切關注點被子產品化的特殊對象。即,它是一個類。
通知(Advice):切面必須要完成的工作。即,它是類中的一個方法。
目标(Target):被通知對象。
代理(Proxy):向目标對象應用通知之後建立的對象。
切入點(PointCut):切面通知執行的"地點"的定義。
連接配接點(JointPoint):與切入點比對的執行點。
在SpringAOP中,通過Advice定義切面邏輯,在Spring中支援五種類型的Advice:
即AOP在不改變原有代碼的情況下,去增加新的功能
執行個體:
接口:
public interface Userservice {
void add();
void delete();
}
接口實作類:
public class UserserviceImpl implements Userservice {
@Override
public void add() {
System.out.println("增加");
}
@Override
public void delete() {
System.out.println("減少");
}
}
待會要給上面類附加的輸出日志功能
public class Log implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println(o.getClass().getName() + "的" + method.getName() + "被執行了");
}
}
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
System.out.println("執行了" + method.getName() + "方法,傳回結果為" + o);
}
}
方式一:使用原生的spring API接口
配置檔案beans.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注冊bean-->
<bean id="userservice" class="com.ys.service.UserserviceImpl"/>
<bean id="log" class="com.ys.log.Log"/>
<bean id="afterlog" class="com.ys.log.AfterLog"/>
<!--配置一:使用原生的spring API接口-->
<!--配置AOP,導入AOP的依賴-->
<aop:config>
<!--切入點;expression表達式,execution:要執行的位置-->
<aop:pointcut id="pointcut" expression="execution(* com.ys.service.UserserviceImpl.*(..))"/>
<!--執行環繞增加-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterlog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
測試:
public class UserserviceImplTest {
@Test
public void Test1() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 動态代理的是接口
Userservice userservice = context.getBean("userservice", Userservice.class);
userservice.add();
}
}
結果:
方式二:自定義類
給上面的 UserserviceImpl類再增加一些功能如下:
public class DiyPointCut {
public void before() {
System.out.println("--------方法執行前---------");
}
public void after() {
System.out.println("--------方法執行後---------");
}
}
配置beans.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注冊bean-->
<bean id="userservice" class="com.ys.service.UserserviceImpl"/>
<bean id="diypointcut" class="com.ys.diy.DiyPointCut"/>
<aop:config>
<!--自定義切面,ref是要引用的類-->
<aop:aspect ref="diypointcut">
<!--切入點-->
<aop:pointcut id="point" expression="execution(* com.ys.service.UserserviceImpl.*(..))"/>
<!--通知-->
<aop:before method="before" pointcut-ref="point"/>
<aop:after method="after" pointcut-ref="point"/>
</aop:aspect>
</aop:config>
</beans>
測試:
public class UserserviceImplTest {
@Test
public void Test1() {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
// 動态代理的是接口
Userservice userservice = context.getBean("userservice", Userservice.class);
userservice.add();
}
}
結果:
方式三:使用注解
要切入的類
@Aspect//标注這是一個類的切面
public class AnnotationPointCut {
@Before("execution(* com.ys.service.UserserviceImpl.*(..))")
public void before1() {
System.out.println("====方法執行前=====");
}
@After("execution(* com.ys.service.UserserviceImpl.*(..))")
public void after1() {
System.out.println("====方法執行後=====");
}
// 在環繞增強中,我們可以給定一個參數,代表我們要擷取代理的切入點
@Around("execution(* com.ys.service.UserserviceImpl.*(..))")
public void around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("環繞前");
// 獲得前面
Signature signature = joinPoint.getSignature();
System.out.println("signature:" + signature);
Object proceed = joinPoint.proceed();//執行方法
System.out.println("環繞後");
}
}
配置beans.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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注冊bean-->
<bean id="userservice" class="com.ys.service.UserserviceImpl"/>
<!--先注冊bean,這裡直接是在類的前面加@Component注解完成注冊-->
<!--開啟注解支援-->
<aop:aspectj-autoproxy/>
<bean id="annotationpointcut" class="com.ys.diy.AnnotationPointCut"/>
</beans>
測試同上
結果如下
以上學習參考B站狂神說Java教程
有不對的地方歡迎真正哈!
O(∩_∩)O哈哈~,覺得不錯喜歡的夥伴支援一下哦!!