1爬虱、概念
AOP(Aspect Oriented Programming)意為:面向切面編程,通過預(yù)編譯方式和運(yùn)行期動(dòng)態(tài)代理實(shí)現(xiàn)程序功能的統(tǒng)一維護(hù)的一種技術(shù)蔽莱。AOP是OOP的延續(xù),是軟件開發(fā)中的一個(gè)熱點(diǎn)制轰,也是Spring框架中的一個(gè)重要內(nèi)容敦腔,是函數(shù)式編程的一種衍生范型均澳。利用AOP可以對(duì)業(yè)務(wù)邏輯的各個(gè)部分進(jìn)行隔離,從而使得業(yè)務(wù)邏輯各部分之間的耦合度降低符衔,提高程序的可重用性找前,同時(shí)提高了開發(fā)的效率。
2判族、Aop在Spring中的作用
提供聲明式事務(wù)躺盛;允許用戶自定義切面
以下名詞需要了解下:
- 橫切關(guān)注點(diǎn):跨越應(yīng)用程序多個(gè)模塊的方法或功能。即是形帮,與我們業(yè)務(wù)邏輯無關(guān)的槽惫,但是我們需要關(guān)注的部分,就是橫切關(guān)注點(diǎn)辩撑。如日志 , 安全 , 緩存 , 事務(wù)等等 ....
- 切面(ASPECT):橫切關(guān)注點(diǎn) 被模塊化 的特殊對(duì)象界斜。即,它是一個(gè)類合冀。
- 通知(Advice):切面必須要完成的工作各薇。即,它是類中的一個(gè)方法君躺。
- 目標(biāo)(Target):被通知對(duì)象峭判。
- 代理(Proxy):向目標(biāo)對(duì)象應(yīng)用通知之后創(chuàng)建的對(duì)象。
- 切入點(diǎn)(PointCut):切面通知 執(zhí)行的 “地點(diǎn)”的定義晰洒。
- 連接點(diǎn)(JointPoint):與切入點(diǎn)匹配的執(zhí)行點(diǎn)朝抖。
SpringAOP中,通過Advice定義橫切邏輯谍珊,Spring中支持5種類型的Advice:
即 Aop 在 不改變?cè)写a的情況下 , 去增加新的功能 .
3治宣、使用Spring實(shí)現(xiàn)Aop
【重點(diǎn)】使用AOP織入急侥,需要導(dǎo)入一個(gè)依賴包!
<!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
1侮邀、第一種方式
通過 Spring API 實(shí)現(xiàn)
首先編寫我們的業(yè)務(wù)接口和實(shí)現(xiàn)類
public interface UserService {
public void add();
public void delete();
public void update();
public void search();
}
public class UserServiceImpl implements UserService{
@Override
public void add() {
System.out.println("增加用戶");
}
@Override
public void delete() {
System.out.println("刪除用戶");
}
@Override
public void update() {
System.out.println("更新用戶");
}
@Override
public void search() {
System.out.println("查詢用戶");
}
}
然后去寫我們的增強(qiáng)類 , 我們編寫兩個(gè) , 一個(gè)前置增強(qiáng) 一個(gè)后置增強(qiáng)
public class Log implements MethodBeforeAdvice {
//method : 要執(zhí)行的目標(biāo)對(duì)象的方法
//objects : 被調(diào)用的方法的參數(shù)
//Object : 目標(biāo)對(duì)象
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println( o.getClass().getName() + "的" + method.getName() + "方法被執(zhí)行了");
}
}
public class AfterLog implements AfterReturningAdvice {
//returnValue 返回值
//method被調(diào)用的方法
//args 被調(diào)用的方法的對(duì)象的參數(shù)
//target 被調(diào)用的目標(biāo)對(duì)象
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("執(zhí)行了" + target.getClass().getName()
+"的"+method.getName()+"方法,"
+"返回值:"+returnValue);
}
}
最后去spring的文件中注冊(cè) , 并實(shí)現(xiàn)aop切入實(shí)現(xiàn) , 注意導(dǎo)入約束 .
<?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
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!--注冊(cè)bean-->
<bean id="userService" class="com.nie.service.UserServiceImpl"/>
<bean id="log" class="com.nie.log.Log"/>
<bean id="afterLog" class="com.nie.log.AfterLog"/>
<!-- 配置aop-->
<aop:config>
<!--切入點(diǎn) expression:表達(dá)式匹配要執(zhí)行的方法-->
<aop:pointcut id="pointcut" expression="execution(* com.nie.service.UserServiceImpl.*(..))"/>
<!--執(zhí)行環(huán)繞; advice-ref執(zhí)行方法 . pointcut-ref切入點(diǎn)-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
測(cè)試
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.search();
}
}
Aop的重要性 : 很重要 . 一定要理解其中的思路 , 主要是思想的理解這一塊 .
Spring的Aop就是將公共的業(yè)務(wù) (日志 , 安全等) 和領(lǐng)域業(yè)務(wù)結(jié)合起來 , 當(dāng)執(zhí)行領(lǐng)域業(yè)務(wù)時(shí) , 將會(huì)把公共業(yè)務(wù)加進(jìn)來 . 實(shí)現(xiàn)公共業(yè)務(wù)的重復(fù)利用 . 領(lǐng)域業(yè)務(wù)更純粹 , 程序猿專注領(lǐng)域業(yè)務(wù) , 其本質(zhì)還是動(dòng)態(tài)代理 .
2坏怪、第二種方式
自定義類來實(shí)現(xiàn)Aop
目標(biāo)業(yè)務(wù)類不變依舊是userServiceImpl
第一步 : 寫我們自己的一個(gè)切入類
public class DiyPointcut {
public void before(){
System.out.println("---------方法執(zhí)行前---------");
}
public void after(){
System.out.println("---------方法執(zhí)行后---------");
}
}
去spring中配置
<!--第二種方式自定義實(shí)現(xiàn)-->
<!--注冊(cè)bean-->
<bean id="diy" class="com.kuang.config.DiyPointcut"/>
<!--aop的配置-->
<aop:config>
<!--第二種方式:使用AOP的標(biāo)簽實(shí)現(xiàn)-->
<aop:aspect ref="diy">
<aop:pointcut id="diyPonitcut" expression="execution(* com.kuang.service.UserServiceImpl.*(..))"/>
<aop:before pointcut-ref="diyPonitcut" method="before"/>
<aop:after pointcut-ref="diyPonitcut" method="after"/>
</aop:aspect>
</aop:config>
測(cè)試:
public class MyTest {
@Test
public void test(){
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService) context.getBean("userService");
userService.add();
}
}
3、第三種方式
使用注解實(shí)現(xiàn)
第一步:編寫一個(gè)注解實(shí)現(xiàn)的增強(qiáng)類
package com.kuang.config;
import org.aspectj.lang.ProceedingJoinPoint;
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.kuang.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("---------方法執(zhí)行前---------");
}
@After("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("---------方法執(zhí)行后---------");
}
@Around("execution(* com.kuang.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("環(huán)繞前");
System.out.println("簽名:"+jp.getSignature());
//執(zhí)行目標(biāo)方法proceed
Object proceed = jp.proceed();
System.out.println("環(huán)繞后");
System.out.println(proceed);
}
}
第二步:在Spring配置文件中绊茧,注冊(cè)bean铝宵,并增加支持注解的配置
<!--第三種方式:注解實(shí)現(xiàn)-->
<bean id="annotationPointcut" class="com.kuang.config.AnnotationPointcut"/>
<!--開啟注解支持-->
<aop:aspectj-autoproxy/>
aop:aspectj-autoproxy:說明
通過aop命名空間的<aop:aspectj-autoproxy />聲明自動(dòng)為spring容器中那些配置@aspectJ切面的bean創(chuàng)建代理,織入切面华畏。當(dāng)然鹏秋,spring 在內(nèi)部依舊采用AnnotationAwareAspectJAutoProxyCreator進(jìn)行自動(dòng)代理的創(chuàng)建工作,但具體實(shí)現(xiàn)的細(xì)節(jié)已經(jīng)被<aop:aspectj-autoproxy />隱藏起來了
<aop:aspectj-autoproxy />有一個(gè)proxy-target-class屬性亡笑,默認(rèn)為false侣夷,表示使用jdk動(dòng)態(tài)代理織入增強(qiáng),當(dāng)配為<aop:aspectj-autoproxy poxy-target-class="true"/>時(shí)仑乌,表示使用CGLib動(dòng)態(tài)代理技術(shù)織入增強(qiáng)百拓。不過即使proxy-target-class設(shè)置為false,如果目標(biāo)類沒有聲明接口晰甚,則spring將自動(dòng)使用CGLib動(dòng)態(tài)代理衙传。