一:AOP介紹
1、什麼是AOP?
l AOP爲AspectOriented Programming的縮寫,意爲:面向切面編程,通過預編譯方式和運行期動態代理實現程序功能的統一維護的一種技術。AOP是OOP(面向對象編程)的延續,是軟件開發中的一個熱點,也是Spring框架中的一個重要內容,是函數式編程的一種衍生範型。利用AOP可以對業務邏輯的各個部分進行隔離,從而使得業務邏輯各部分之間的耦合度降低,提高程序的可重用性,同時提高了開發的效率。 l AOP採取橫向抽取機制,取代了傳統縱向繼承體系重複性代碼 l 經典應用:事務管理、性能監視、安全檢查、緩存 、日誌等 l Spring AOP使用純Java實現,不需要專門的編譯過程和類加載器,在運行期通過代理方式向目標類織入增強代碼 l AspectJ是一個基於Java語言的AOP框架,Spring2.0開始,Spring AOP引入對Aspect的支持,AspectJ擴展了Java語言,提供了一個專門的編譯器,在編譯時提供橫向代碼的織入。 |
2、AOP的實現原理
l AOP底層將採用代理機制進行實現。 l 接口 + 實現類:spring採用 jdk 的動態代理Proxy。 l 實現類:spring 採用 cglib字節碼增強。 |
3、AOP的術語
1.target:目標類,需要被代理的類。例如:UserService 2.Joinpoint(連接點):所謂連接點是指那些可能被攔截到的方法。例如:所有的方法 3.PointCut 切入點:已經被增強的連接點。例如:addUser() 4.advice 通知/增強,增強代碼。例如:after、before 5. Weaving(織入):是指把增強advice應用到目標對象target來創建新的代理對象proxy的過程. 6.proxy 代理類 7. Aspect(切面): 是切入點pointcut和通知advice的結合 一個線是一個特殊的面。 一個切入點和一個通知,組成成一個特殊的面。 |
public interface UserService {
public void addUser();
public void updataUser();
public void deleUser();
}
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("add");
}
@Override
public void updataUser() {
System.out.println("up");
}
@Override
public void deleUser() {
System.out.println("dele");
}
}
public class MyAspect implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("前置");
// 手動執行目標方法
mi.proceed();
System.out.println("後置");
return null;
}
}
通知
public class MyAspect implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("前置");
// 手動執行目標方法
mi.proceed();
System.out.println("後置");
return null;
}
}
要導入的xml
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
<?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">
<!-- 1 創建目標類 -->
<bean id="userServiceId" class="com.itheima.c_spring_aop.UserServiceImpl"></bean>
<!-- 2 創建切面類(通知) -->
<bean id="myAspectId" class="com.itheima.c_spring_aop.MyAspect"></bean>
<!-- 3 aop編程
3.1 導入命名空間
3.2 使用 <aop:config>進行配置
proxy-target-class="true" 聲明時使用cglib代理
<aop:pointcut> 切入點 ,從目標對象獲得具體方法
<aop:advisor> 特殊的切面,只有一個通知 和 一個切入點
advice-ref 通知引用
pointcut-ref 切入點引用
3.3 切入點表達式
execution(* com.itheima.c_spring_aop.*.*(..))
選擇方法 返回值任意 包 類名任意 方法名任意 參數任意
-->
<aop:config proxy-target-class="true">
<aop:pointcut expression="execution(* com.itheima.c_spring_aop.*.*(..))" id="myPointCut"/>
<aop:advisor advice-ref="myAspectId" pointcut-ref="myPointCut"/>
</aop:config>
</beans>
Testpublic class Test1 {
@Test
public void Demo1()
{
String Xml="com/hao/d_spring_aop/bean.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(Xml);
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updataUser();
userService.deleUser();
}
}
5、AspectJ
5.1 AspectJ簡介
l AspectJ是一個基於Java語言的AOP框架 l Spring2.0以後新增了對AspectJ切點表達式支持 l @AspectJ 是AspectJ1.5新增功能,通過JDK5註解技術,允許直接在Bean類中定義切面 新版本Spring框架,建議使用AspectJ方式來開發AOP l 主要用途:自定義開發. |
5.2切入點表達式
execution() 用於描述方法【掌握】 語法:execution(修飾符 返回值 包.類.方法名(參數) throws異常) 修飾符,一般省略 public 公共方法 * 任意 返回值,不能省略 void 返回沒有值 String 返回值字符串 * 任意 包,[省略] com.itheima.crm 固定包 com.itheima.crm.*.service crm包下面子包任意(例如:com.itheima.crm.staff.service) com.itheima.crm.. crm包下面的所有子包(含自己) com.itheima.crm.*.service.. crm包下面任意子包,固定目錄service,service目錄任意包 類,[省略] UserServiceImpl 指定類 *Impl 以Impl結尾 User* 以User開頭 * 任意 方法名,不能省略 addUser 固定方法 add* 以add開頭 *Do 以Do結尾 * 任意 (參數) () 無參 (int) 一個整型 (int,int) 兩個 (..) 參數任意 throws,可省略,一般不寫。
綜合1 execution(* com.hao.crm.*.service..*.*(..)) 綜合2 <aop:pointcutexpression="execution(* com.hao.*WithCommit.*(..)) || execution(* com.itheima.*Service.*(..))"id="myPointCut"/> |
5.3通知類型(其一)
around:環繞通知(應用:十分強大,可以做任何事情) 方法執行前後分別執行,可以阻止方法的執行 必須手動執行目標方法 |
5.4AspectJ基於註解簡單實現
1.導入Jar包
之前的4+1 l 4個: aop聯盟規範 aoplliance springaop 實現 aop aspect規範 aspectj.weaver springaspect 實現 aspects |
//接口
public interface UserService {
public void addUser();
public void updataUser();
public void deleUser();
}
// 實現類
@Service("userServiceId") // 替換<bean id="userServiceId" class="com.hao.e_spring_xml.UserServiceImpl">
public class UserServiceImpl implements UserService {
@Override
public void addUser() {
System.out.println("add XML");
}
@Override
public void updataUser() {
System.out.println("up XML");
}
@Override
public void deleUser() {
System.out.println("dele XML");
}
}
// 切面類
@Component // 組件
@Aspect // 替換<aop:aspect ref="myAspectId">
public class MyAspect {
@Before("exepression(* com.hao.f_spring_anno.UserServiceImpl.*(..))")
public void myBefore(JoinPoint joinPoint)
{
System.out.println("前置"+joinPoint.getSignature().getName());
}
public void myAfterreturnning(JoinPoint joinPoint,Object obj)
{
System.out.println("後置"+joinPoint.getSignature().getName());
}
//環繞
public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable
{
System.out.println("前");
// 手動執行目標方法
Object proceed = joinPoint.proceed();
System.out.println("後");
return proceed;
}
}
<?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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<!-- 掃描所有註解 -->
<context:component-scan base-package="com.hao.f_spring_anno"></context:component-scan>
<!-- 2 確定aop註解生效 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
<!-- 創建目標類 -->
<!-- 創建切面類 -->
<!-- aop 編程
<aop:aspect> : 將切面類聲明爲 切面 從而使用裏面的方法。ref引用切面類的ID
<aop:pointcut> : 聲明一個切入點 所有的通知都可以使用。expression:切入點表達式 id 引用的名稱
<aop:pointcut expression="exepression(* com.hao.e_spring_xml.UserServiceImpl.*(..))" id="myPointCut"/>
method: 切面類的方法
pointcut-ref: 共享式的引用
<aop:before method="myBefore" pointcut-ref="myPointCut"/>
-->
<!-- 環繞
<aop:around method="myAround" pointcut-ref="myPointCut"/>
-->
</beans>
//test
public class Test1 {
@Test
public void Demo1()
{
String Xml="com/hao/f_spring_anno/bean.xml";
ApplicationContext applicationContext = new ClassPathXmlApplicationContext(Xml);
UserService userService = (UserService) applicationContext.getBean("userServiceId");
userService.addUser();
userService.updataUser();
userService.deleUser();
}
}