AOP(Aspect Oriented Programming) 面向切面編程,是目前軟件開發中的一個熱點,是Spring框架內容,利用AOP能夠對業務邏輯的各個部分隔離,從而使的業務邏輯各部分的耦合性下降,提升程序的可重用性,提高開發效率。java
AOP實現原理是java動態代理,可是jdk的動態代理必須實現接口,因此spring的aop是用cglib這個庫實現的,cglib使用裏asm這個直接操縱字節碼的框架,因此能夠作到不使用接口的狀況下實現動態代理。正則表達式
AOP是處理一些橫切行問題。這些橫切性問題不會影響到主邏輯的實現,可是會散落到代碼的各個部分,難以維護。AOP就是把這些問題和主業務邏輯分開,達到與主業務邏輯解耦的目的。spring
OOP面向對象編程,針對業務處理過程的實體及其屬性和行爲進行抽象封裝,以得到更加清晰高效的邏輯單元劃分。而AOP則是針對業務處理過程當中的切面進行提取,它所面對的是處理過程的某個步驟或階段,以得到邏輯過程的中各部分之間低耦合的隔離效果。這兩種設計思想在目標上有着本質的差別。編程
經過下面的圖能夠清晰的理解AOP與OOP的區別:緩存
AOP中的Joinpoint能夠有多種類型:構造方法調用,字段的設置和獲取,方法的調用,方法的執行,異常的處理執行,類的初始化。也就是說在AOP的概念中咱們能夠在上面的這些Joinpoint上織入咱們自定義的Advice,可是在Spring中卻沒有實現上面全部的joinpoint,確切的說,Spring只支持方法執行類型的Joinpoint性能優化
pom.xmlbash
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.2.4.RELEASE</version>
</dependency>
複製代碼
定義一個通用接口,全部實現此接口的類都有一個鹹魚方法和一個測試aop的方法app
public interface HelloWorld {
void saltedFish();
void testPrintTime();
}
複製代碼
實現1框架
public class HelloWorldImpl1 implements HelloWorld{
@Override
public void saltedFish() {
System.out.println("this is a salted fish =========== 1");
}
@Override
public void testPrintTime() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("testPrintTime 1=============111111111");
}
}
複製代碼
實現2ide
public class HelloWorldImpl2 implements HelloWorld{
@Override
public void saltedFish() {
System.out.println("this is a salted fish =========== 2");
}
@Override
public void testPrintTime() {
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("testPrintTime 2=============22222222");
}
}
複製代碼
定義一個Advice,實如今鏈接點以前以後該乾的事
public class TimeHandler implements MethodBeforeAdvice, AfterReturningAdvice {
Long before = 0L;
@Override
public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
Long after = System.currentTimeMillis();
System.out.println("==========代理後time, " + after + " ======= 間隔: " + (after - before) + "==========");
}
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
before = System.currentTimeMillis();
System.out.println("==========代理前time:" + before + "===========");
}
}
複製代碼
經過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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定義 -->
<bean id="h1" class="com.example.demo.aop.HelloWorldImpl1"></bean>
<bean id="h2" class="com.example.demo.aop.HelloWorldImpl2"></bean>
<!-- 定義advice -->
<bean id="timeHandler" class="com.example.demo.aop.TimeHandler"></bean>
<!-- 定義point cut -->
<bean id="timePointCut" class="org.springframework.aop.support.JdkRegexpMethodPointcut">
<property name="pattern" value=".*testPrintTime"></property>
</bean>
<!-- 切面 關聯切入點與通知 -->
<bean id="timeHandlerAdvisor" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="timeHandler"></property>
<property name="pointcut" ref="timePointCut"></property>
</bean>
<!-- 設置代理-->
<bean id="proxy1" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理的對象 -->
<property name="target" ref="h1"></property>
<!-- 使用的切面 -->
<property name="interceptorNames" value="timeHandlerAdvisor"></property>
<!-- 代理接口 -->
<property name="interfaces" value="com.example.demo.aop.HelloWorld"></property>
</bean>
<!-- 設置代理-->
<bean id="proxy2" class="org.springframework.aop.framework.ProxyFactoryBean">
<!-- 代理的對象 -->
<property name="target" ref="h2"></property>
<!-- 使用的切面 -->
<property name="interceptorNames" value="timeHandlerAdvisor"></property>
<!-- 代理接口 -->
<property name="interfaces" value="com.example.demo.aop.HelloWorld"></property>
</bean>
</beans>
複製代碼
測試類
public class AOPTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("./application.xml");
HelloWorld helloWorld1 = (HelloWorld) applicationContext.getBean("proxy1");
HelloWorld helloWorld2 = (HelloWorld) applicationContext.getBean("proxy2");
helloWorld1.saltedFish();
System.out.println("---------------------");
helloWorld1.testPrintTime();
System.out.println("=======================");
helloWorld2.saltedFish();
System.out.println("---------------------");
helloWorld2.testPrintTime();
}
}
複製代碼
打印
this is a salted fish =========== 1
---------------------
==========代理前time:1582477901748===========
testPrintTime 1=============111111111
==========代理後time, 1582477902750 ======= 間隔: 1002==========
=======================
this is a salted fish =========== 2
---------------------
==========代理前time:1582477902750===========
testPrintTime 2=============22222222
==========代理後time, 1582477903250 ======= 間隔: 500==========
複製代碼
複製代碼