Spring-Aop編程(三)-AspectJ

AspectJ

1. 介紹

AspectJ是一個基於Java語言的AOP框架,Spring2.0之後新增了對AspectJ切點表達式支持,@AspectJ 是AspectJ1.5新增功能,經過JDK5註解技術,容許直接在Bean類中定義切面,它是一種新版本Spring框架,建議使用AspectJ方式來開發AOP。主要用途:自定義開發java

2.切入點表達式

  爲了可以靈活定義切入點位置,Spring AOP提供了多種切入點指示符。spring

execution———用來匹配執行方法的鏈接點

  語法結構:   execution(   方法修飾符  方法返回值  方法所屬類 匹配方法名 (  方法中的形參表 )  方法申明拋出的異常  )express

  其中紅色字體的部分時不能省略的,各部分都支持通配符 「*」 來匹配所有編程

  比較特殊的爲形參表部分,其支持兩種通配符app

  •   "*":表明一個任意類型的參數;
  •   「..」:表明零個或多個任意類型的參數。

  例如:框架

    ()匹配一個無參方法ide

    (..)匹配一個可接受任意數量參數和類型的方法字體

    (*)匹配一個接受一個任意類型參數的方法this

    (*,Integer)匹配一個接受兩個參數的方法,第一個能夠爲任意類型,第二個必須爲Integer。spa

  下面舉一些execution的使用實例:

分類 示例 描述
經過方法簽名定義切入點 execution(public * * (..)) 匹配全部目標類的public方法,第一個*爲返回類型,第二個*爲方法名
execution(* save* (..)) 匹配全部目標類以save開頭的方法,第一個*表明返回類型
execution(**product(*,String)) 匹配目標類全部以product結尾的方法,而且其方法的參數表第一個參數可爲任意類型,第二個參數必須爲String
經過類定義切入點 execution(* aop_part.Demo1.service.*(..)) 匹配service接口及其實現子類中的全部方法
經過包定義切入點 execution(* aop_part.*(..)) 匹配aop_part包下的全部類的全部方法,但不包括子包
execution(* aop_part..*(..)) 匹配aop_part包下的全部類的全部方法,包括子包。(當".."出現再類名中時,後面必須跟「*」,表示包、子孫包下的全部類)
execution(* aop_part..*.*service.find*(..)) 匹配aop_part包及其子包下的全部後綴名爲service的類中,全部方法名必須以find爲前綴的方法
經過方法形參定義切入點 execution(*foo(String,int)) 匹配全部方法名爲foo,且有兩個參數,其中,第一個的類型爲String,第二個的類型爲int
execution(* foo(String,..)) 匹配全部方法名爲foo,且至少含有一個參數,而且第一個參數爲String的方法(後面能夠有任意個類型不限的形參)

within————經過類匹配模式申明切入點(只能經過類型匹配鏈接點)

    例如:within(aop_part..*)             表示匹配包aop_part以及子包的全部方法

    因爲execution能夠匹配包、類、方法,而within只能匹配包、類,所以execution徹底能夠代替within的功能。


this————限定AOP代理必須時指定類型的實例,用於匹配該對象的全部鏈接點

    例如:this(aop_part.service.GodService)        表示匹配了GodService接口的代理對象的全部鏈接點


target————經過判斷目標類的類型肯定判斷的是否匹配

    this經過判斷代理類的類型來決定是否和切入點匹配,二者限定的對象都是指定類型的實例。

    例如: target(aop_part.service.GodService)      表示匹配實現了GodService接口的目標對象的全部鏈接點


args————用於對鏈接點的參數類型進行限制,要求參數類型時指定類型的實例

    例如:args(aop_part.service)                     表示匹配時,出入的參數類型時service的方法

    其與execution(**(aop_part.service))的區別爲,execution針對的時方法簽名,而args針對的是運行時的實際參數類型。

    args既匹配buyGoods(service newService),也匹配buyGoods(Buyservice newService)   <Buyservice爲service的子類>

    execution只匹配buyGoods(service newService)


組合切入點

    支持 &&、 || 、!

    與其餘語言所表明的意思相同

    例:args(aop_part.service)  &&execution(**(aop_part.service))

3.AspectJ 通知類型

aop聯盟定義通知類型,具備特性接口,必須實現,從而肯定方法名稱。

aspectj 通知類型,只定義類型名稱。已經方法格式。

個數:6種,知道5種,掌握1中。

before:前置通知(應用:各類校驗)在方法執行前執行,若是通知拋出異常,阻止方法運行

afterReturning:後置通知(應用:常規數據處理)方法正常返回後執行,若是方法中拋出異常,通知沒法執行必須在方法執行後才執行,因此能夠得到方法的返回值。

around:環繞通知(應用:十分強大,能夠作任何事情)方法執行先後分別執行,能夠阻止方法的執行必須手動執行目標方法

afterThrowing:拋出異常通知(應用:包裝異常信息)方法拋出異常後執行,若是方法沒有拋出異常,沒法執行

after:最終通知(應用:清理現場) 方法執行完畢後執行,不管方法中是否出現異常

Spring Aop實例:

方式一 :註解配置 

UserService.java

package com.zk.b_annotation;

public interface UserService {
	
	public void addUser();
	public String updateUser();
	public void deleteUser();

}

UserServiceImpl.java

package com.zk.b_annotation;

import org.springframework.stereotype.Service;

@Service("userServiceId")
public class UserServiceImpl implements UserService {

	@Override
	public void addUser() {
		System.out.println("d_aspect.b_anno addUser");
	}

	@Override
	public String updateUser() {
		System.out.println("d_aspect.b_anno updateUser");
		int i = 1/ 0;
		return "陽志就是";
	}

	@Override
	public void deleteUser() {
		
		System.out.println("d_aspect.b_anno deleteUser");
	}
}

  

切面

MyAspect.java

package com.zk.b_annotation;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component;

/**
 * 切面類,含有多個通知
 */
@Component
@Aspect
public class MyAspect {
	
	//前置通知
//	@Before("execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))")
@Before("myPointCut()") public void myBefore(JoinPoint joinPoint){ System.out.println("前置通知" + joinPoint.getSignature().getName()); } //聲明公共切入點 @Pointcut("execution(* com.zk.b_annotation.UserServiceImpl.*(..))") private void myPointCut(){ } // @AfterReturning(value="myPointCut()" ,returning="ret")
@AfterReturning("myPointCut()") public void myAfterReturning(JoinPoint joinPoint,Object ret){ System.out.println("後置通知" + joinPoint.getSignature().getName() + " , -->" + ret); } // @Around(value = "myPointCut()")
@Around("myPointCut") public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{ System.out.println("前置通知"); //手動執行目標方法 Object obj = joinPoint.proceed(); System.out.println("後置通知"); return obj; } // @AfterThrowing(value="execution(* com.itheima.d_aspect.b_anno.UserServiceImpl.*(..))" ,throwing="e")
@AfterThrowing("myPointCut()") public void myAfterThrowing(JoinPoint joinPoint,Throwable e){ System.out.println("拋出異常通知" + e.getMessage()); } @After("myPointCut()") public void myAfter(JoinPoint joinPoint){ 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: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">
	
	<!-- 1.掃描 註解類 -->
	<context:component-scan base-package="com.zk.b_annotation"></context:component-scan>
	
	<!-- 2.肯定 aop註解生效 -->
	<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>

  

TestAspectAnno.java

package com.zk.b_annotation;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAspectAnno {
	
	@Test
	public void demo01(){
		String xmlPath = "com/zk/b_annotation/beans.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		
		//得到目標bean
		UserService userService = (UserService) applicationContext.getBean("userServiceId");
		userService.addUser();
		userService.updateUser();
		userService.deleteUser();
	}

}

  

運行效果圖:

方式二:xml配置 

UserService.java

package com.itheima.d_aspect.a_xml;

public interface UserService {
	
	public void addUser();
	public String updateUser();
	public void deleteUser();

}

 

UserServiceImpl.java

package com.itheima.d_aspect.a_xml;

public class UserServiceImpl implements UserService {

	@Override
	public void addUser() {
		System.out.println("d_aspect.a_xml addUser");
	}

	@Override
	public String updateUser() {
		System.out.println("d_aspect.a_xml updateUser");
		int i = 1/ 0;
		return "陽志就是屌";
	}

	@Override
	public void deleteUser() {
		
		System.out.println("d_aspect.a_xml deleteUser");
	}

}

  

MyAspect.java

package com.itheima.d_aspect.a_xml;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;

/**
 * 切面類,含有多個通知
 */
public class MyAspect {
	
	public void myBefore(JoinPoint joinPoint){
		System.out.println("前置通知 : " + joinPoint.getSignature().getName());
	}
	
	public void myAfterReturning(JoinPoint joinPoint,Object ret){
		System.out.println("後置通知 : " + joinPoint.getSignature().getName() + " , -->" + ret);
	}
	
	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
		System.out.println("前");
		//手動執行目標方法
		Object obj = joinPoint.proceed();
		
		System.out.println("後");
		return obj;
	}
	
	public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
		System.out.println("拋出異常通知 : " + e.getMessage());
	}
	
	public void myAfter(JoinPoint joinPoint){
		System.out.println("最終通知");
	}

}

  

TestAspectXml.java

package com.itheima.d_aspect.a_xml;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class TestAspectXml {
	
	@Test
	public void demo01(){
		String xmlPath = "com/itheima/d_aspect/a_xml/beans.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(xmlPath);
		
		//得到目標類
		UserService userService = (UserService) applicationContext.getBean("userServiceId");
		userService.addUser();
		userService.updateUser();
		userService.deleteUser();
	}

}

  

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 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd">
	<!-- 1 建立目標類 -->
	<bean id="userServiceId" class="com.itheima.d_aspect.a_xml.UserServiceImpl"></bean>
	<!-- 2 建立切面類(通知) -->
	<bean id="myAspectId" class="com.itheima.d_aspect.a_xml.MyAspect"></bean>
	<!-- 3 aop編程 
		<aop:aspect> 將切面類 聲明「切面」,從而得到通知(方法)
			ref 切面類引用
		<aop:pointcut> 聲明一個切入點,全部的通知均可以使用。
			expression 切入點表達式
			id 名稱,用於其它通知引用
	-->
	<aop:config>
		<aop:aspect ref="myAspectId">
			<aop:pointcut expression="execution(* com.itheima.d_aspect.a_xml.UserServiceImpl.*(..))" id="myPointCut"/>
			
			<!-- 3.1 前置通知 
				<aop:before method="" pointcut="" pointcut-ref=""/>
					method : 通知,及方法名
					pointcut :切入點表達式,此表達式只能當前通知使用。
					pointcut-ref : 切入點引用,能夠與其餘通知共享切入點。
				通知方法格式:public void myBefore(JoinPoint joinPoint){
					參數1:org.aspectj.lang.JoinPoint  用於描述鏈接點(目標方法),得到目標方法名等
				例如:
			
			-->
			<aop:before method="myBefore" pointcut-ref="myPointCut"/>
			<!-- 3.2後置通知  ,目標方法後執行,得到返回值
				<aop:after-returning method="" pointcut-ref="" returning=""/>
					returning 通知方法第二個參數的名稱
				通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){
					參數1:鏈接點描述
					參數2:類型Object,參數名 returning="ret" 配置的
				例如:
			
			-->
			<aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
			<!-- 3.3 環繞通知 
				<aop:around method="" pointcut-ref=""/>
				通知方法格式:public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
					返回值類型:Object
					方法名:任意
					參數:org.aspectj.lang.ProceedingJoinPoint
					拋出異常
				執行目標方法:Object obj = joinPoint.proceed();
				例如:
			
			-->
			<aop:around method="myAround" pointcut-ref="myPointCut"/>
			<!-- 3.4 拋出異常
				<aop:after-throwing method="" pointcut-ref="" throwing=""/>
					throwing :通知方法的第二個參數名稱
				通知方法格式:public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
					參數1:鏈接點描述對象
					參數2:得到異常信息,類型Throwable ,參數名由throwing="e" 配置
				例如:
			
			-->
			<aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
			<!-- 3.5 最終通知 -->			
			<aop:after method="myAfter" pointcut-ref="myPointCut"/>
			
			
			
		</aop:aspect>
	</aop:config>
</beans>

  

運行效果:

 

 

相關文章
相關標籤/搜索