Spring学习(9)AOP之AspectJ

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/SDDDLLL/article/details/86628155

AspectJ其实是基于AOP思想的一个框架,在之前的通知顾问等等各种技术,在AspectJ同样能够实现。并且实现的更加方便和简单。平时开发的时候,就是使用这种方式进行开发的,

在AspectJ中常见的通知有五种类型,比之前的增加了一个最终通知。

  • 前置通知
  • 后置通知
  • 环绕通知
  • 异常通知
  • 最终通知

最终通知是指,无论程序执行是否正常,这个通知都会执行,类似于finally语句。

并且AspectJ除了提供五种通知以外,还定义了专门的表达式指定切入点。因为切入点是一个函数名,一个目标类可能有很多个切入点(函数),我们在顾问中指定切入点,如果一个一个列出那就太麻烦。这时候我们可以使用AspectJ提供的表达式:

execution (

    [modifies-pattern]:访问权限类型
    ret-type-pattern:返回值类型
    [declaring-type-pattern]:全限定类名
    name-pattern:方法名
    [throws-pattern]:抛出的异常类型
)

切入点表达式要匹配的就是目标方法的方法名。所以execution表达式中明显就是方法的签名。

好了,说了这么多看看AspectJ是如何使用的。

一、开发环境搭建

1、导入jar包(或者是maven构建依赖)

这里需要提供的是两个jar

2、更换配置文件的约束

<?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">
     
</beans>

二、基于注解的AOP实现

1、定义接口

//主目标接口
public interface ISomeService {
	//目标方法
	void doFirst();
	String doSecond();
	void doThird();
}

2、接口实现类

package com.fdd.annotation;
public class SomeServiceImpl implements ISomeService {

	public void doFirst() {
		System.out.println("doFirst");	
	}

	public String doSecond() {
		System.out.println("doSecond");
		return "abcde";
	}

	@Override
	public void doThird() {
		System.out.println("doThird"+3/0);
	}

}

3、定义一个POJO类,也就是切面

@Aspect
public class MyAspect {
	
	@Before(value = "execution(* *..ISomeService.doFirst(..))")
	public void myBefore(){
		System.out.println("执行前置通知");
	}
	
	@Before(value = "execution(* *..ISomeService.doFirst(..))")
	public void myBefore(JoinPoint jp){
		System.out.println("执行前置通知 jp= "+jp);
	}
	
	@AfterReturning(value = "execution(* *..ISomeService.doSecond(..))")
	public void myAfterReturning(){
		System.out.println("执行后置通知 ");
	}
	
	@AfterReturning(value = "execution(* *..ISomeService.doSecond(..))",returning="result")
	public void myAfterReturning(Object result){
		System.out.println("执行后置通知 result= "+result);
	}

	@Around(value = "execution(* *..ISomeService.doSecond(..))")
	public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("环绕通知:目标方法执行之前执行");
		
		Object result=pjp.proceed();
		
		System.out.println("环绕通知:目标方法执行之后执行");
		//在这里,可以对中间结果进行一些其他的操作
		if(result!=null){
			result=((String)result).toUpperCase();
		}
		return result;	
	}
	
	@AfterThrowing(value = "execution(* *..ISomeService.doThird(..))")
	public void myAfterThrowing(){
		System.out.println("执行异常通知");
	}
	
	@AfterThrowing(value = "execution(* *..ISomeService.doThird(..))",throwing="ex")
	public void myAfterThrowing(Exception ex){
		System.out.println("执行异常通知 ex= "+ex.getMessage());
	}
	
	//自定义异常只需要把Exception更改就可以了改成UserNameException或者是其他自定义的类名
	
	@After(value = "doThirdPointcut()")
	public void myAfter(){
		System.out.println("----执行最终通知,在异常通知之前");
	}
	
	//定义了一个切入点 叫做doThirdPointcut
	@Pointcut(value = "execution(* *..ISomeService.doThird(..))")
	public void doThirdPointcut(){
		
	}
	
}

 (0)在类前添加@Aspect

(1)前置通知@Before

     里面包含一个JointPoint类型参数。这个参数含有切入点表达式、方法签名、目标对象等等数据

(2)后置通知@AfterReturning

里面含有returning属性,表示获取返回值

(3)环绕通知@Around

里面有ProceedingJointPoint参数。这个参数有一个proceed方法,用于执行目标方法,若目标方法有返回值,则可以直接获得。并将结果返回,其实就是可以修改目标方法的返回值,也就是拦截了目标方法的执行。

(4)@AfterThrowing异常通知

(5)@After最终通知

(6)@Pointcut定义切入点

这个方法是用于切入点表达式的编写,这是因为如果使用多个execution相同时,那么程序的编写和维护就会很麻烦,

4、配置文件

<?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">
     
     <!-- 注册切面 -->
  	<bean id="myAspect" class="com.fdd.annotation.MyAspect"></bean>
	<!-- 注册目标对象 -->
	<bean id="someService" class="com.fdd.annotation.SomeServiceImpl"></bean>
	<!-- 注册Aspectj的自动代理 -->
	<aop:aspectj-autoproxy/>
</beans>

5、测试

	@Test
	public void test01(){
		String resource = "com/fdd/annotation/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
        //这里是目标对象的id
		ISomeService service =(ISomeService) ac.getBean("someService");
		
		service.doFirst();
		System.out.println("==========");
		service.doSecond();
		System.out.println("==========");
		service.doThird();
	}

三、基于XML的AOP实现

1、定义接口

//主目标接口
public interface ISomeService {
	//目标方法
	void doFirst();
	String doSecond();
	void doThird();
}

2、接口实现类

package com.fdd.xml;
public class SomeServiceImpl implements ISomeService {

	public void doFirst() {
		System.out.println("doFirst");	
	}

	public String doSecond() {
		System.out.println("doSecond");
		return "abcde";
	}

	@Override
	public void doThird() {
		System.out.println("doThird"+3/0);
	}

}

3、定义切面

public class MyAspect {	
	
	public void myBefore(){
		System.out.println("执行前置通知");
	}
	
	public void myBefore(JoinPoint jp){
		System.out.println("执行前置通知 jp= "+jp);
	}
	
	public void myAfterReturning(){
		System.out.println("执行后置通知 ");
	}	

	public void myAfterReturning(Object result){
		System.out.println("执行后置通知 result= "+result);
	}
	
	public Object myAround(ProceedingJoinPoint pjp) throws Throwable{
		System.out.println("环绕通知:目标方法执行之前执行");
		
		Object result=pjp.proceed();
		
		System.out.println("环绕通知:目标方法执行之后执行");
		//在这里,可以对中间结果进行一些其他的操作
		if(result!=null){
			result=((String)result).toUpperCase();
		}
		return result;	
	}
	
	public void myAfterThrowing(){
		System.out.println("执行异常通知");
	}
	
	public void myAfterThrowing(Exception ex){
		System.out.println("执行异常通知 ex= "+ex.getMessage());
	}
	
	//自定义异常只需要把Exception更改就可以了改成UserNameException或者是其他自定义的类名

	public void myAfter(){
		System.out.println("----执行最终通知,在异常通知之前");
	}
	
	public void doThirdPointcut(){
		
	}
	
}

4、定义配置文件

<?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">
     
     <!-- 注册切面 -->
  	<bean id="myAspect" class="com.fdd.xml.MyAspect"></bean>
	<!-- 注册目标对象 -->
	<bean id="someService" class="com.fdd.xml.SomeServiceImpl"></bean>
	
	<!-- AOP配置 -->
	<aop:config>
		<aop:pointcut expression="execution(* *..ISomeService.doFirst(..))" id="doFirstPointcut"/>
		<aop:pointcut expression="execution(* *..ISomeService.doSecond(..))" id="doSecondPointcut"/>
		<aop:pointcut expression="execution(* *..ISomeService.doThird(..))" id="doThirdPointcut"/>
		<aop:aspect ref="myAspect" id="myAspect" >
			<aop:before method="myBefore" pointcut-ref="doFirstPointcut"/>
			<aop:before method="myBefore(org.aspectj.lang.JoinPoint)" pointcut-ref="doFirstPointcut"/>
			<aop:after-returning method="myAfterReturning" pointcut-ref="doSecondPointcut"/>
			<aop:after-returning method="myAfterReturning(java.lang.Object)"  pointcut-ref="doSecondPointcut" returning="result"/>
			<aop:around method="myAround" pointcut-ref="doSecondPointcut"/>
			<aop:after-throwing method="myAfterThrowing" pointcut-ref="doThirdPointcut"/>
			<aop:after method="myAfter" pointcut-ref="doFirstPointcut"/>
		</aop:aspect>
	</aop:config>

</beans>

5、测试

	@Test
	public void test01(){
		String resource = "com/fdd/xml/applicationContext.xml";
		ApplicationContext ac = new ClassPathXmlApplicationContext(resource);
		ISomeService service =(ISomeService) ac.getBean("someService");
		
		service.doFirst();
		System.out.println("==========");
		service.doSecond();
		System.out.println("==========");
		service.doThird();
	}

猜你喜欢

转载自blog.csdn.net/SDDDLLL/article/details/86628155