AOP编程详细解析

1.什么是AOP

   AOP全称为Aspect Oriented Programming的缩写,也意为:面向切面编程,通过预编译手段和运行期动态代理实现程序功能的统一维护技术。采用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时也提高了开发效率。AOP采取横向抽取机制,取代了纵向继承体系重复的代码。

1.1AOP应用场景

   AOP典型的应用场景有:事务管理,性能监控、安全监测、日志等。

1.2AOP实现原理

   AOP底层采用代理的机制进行实现的。代理的方式有两种:jdk动态代理、cglib代理(字节码增强)

1.3AOP相关的术语

    1.target:目标类。需要被代理的类,也是需要通过代理增强的类。

    2.JoinPoint:连接点。连接点就是指需要增强类(target)可能拦截到的方法。如同target中。

    3.PointCut:切入点。已经被增强的连接点(在众多连接点中已经被增强的方法,就叫切入点。切入点是连接点的子集)。

    4.advice:通知(增强)。增强的代码(在切入点中增强所需的代码就是通知,例如:事务管理就是在切入点方法中前后开启事务和提交事务)。

    5.Weaving:织入。把增强代码(advice)应用到目标类(target)来创建新的代理对象(proxy)的过程就叫做织入。

    6.proxy:代理类。

    7.Aspect:切面。是切入点(PointCut)和通知(advice)的结合。

2.手动方式实现AOP编程

2.1采用JDK动态代理实现手动方式

   采用jdk动态代理需要的条件是:需要代理的类是采用接口+实现类的方式。(因为代理是采用目标类所实现的接口来生成目标类的代理)。

 第一步:准备目标类(target):

    接口:

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

   实现类:

public class UserServiceImpl implements UserService{

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

	@Override
	public void updateUser() {
		System.out.println("updateUser");
	}

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

}

  第二步:准备切面类(也是增强代码所在的类advice)

       切面类代码:

public class MyAspect {
	
	public void before() {
		System.out.println("前方法");
	}
	
	public void after() {
		System.out.println("后方法 ");
	};
}

  第三步:创建生成代理类工厂实现对目标类的代理

     创建代理类通过Proxy类中的静态方法newProxyInstance(类加载器,代理类实现的接口,InvacationHandler处理类)

public class MyBeanFactory {
	
	//应为这个类是生成代理类,所以就通过这个方法产生代理类 
	public static UserService createService() {
		//首先需要目标类
		UserService userService = new UserServiceImpl();
		//切面类
		MyAspect myAspect = new MyAspect();
		
		/* 3 代理类:将目标类(切入点)和 切面类(通知) 结合 --> 切面
		 * 	Proxy.newProxyInstance
		 * 		参数1:loader ,类加载器,动态代理类 运行时创建,任何类都需要类加载器将其加载到内存。
		 * 			一般情况:当前类.class.getClassLoader();
		 * 					目标类实例.getClass().get...
		 * 		参数2:Class[] interfaces 代理类需要实现的所有接口
		 * 			方式1:目标类实例.getClass().getInterfaces()  ;注意:只能获得自己接口,不能获得父元素接口
		 * 			方式2:new Class[]{UserService.class}   
		 * 			例如:jdbc 驱动  --> DriverManager  获得接口 Connection
		 * 		参数3:InvocationHandler  处理类,接口,必须进行实现类,一般采用匿名内部
		 * 			提供 invoke 方法,代理类的每一个方法执行时,都将调用一次invoke
		 * 				参数31:Object proxy :代理对象
		 * 				参数32:Method method : 代理对象当前执行的方法的描述对象(反射)
		 * 					执行方法名:method.getName()
		 * 					执行方法:method.invoke(对象,实际参数)
		 * 				参数33:Object[] args :方法实际参数
		 * 
		 */
		UserService obj = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader()
				, userService.getClass().getInterfaces()
				, new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						//执行前
						myAspect.before();
						//执行目标类的方法
						Object obj = method.invoke(userService, args);
						//执行后
						myAspect.after();
						return obj;
					}
				} );
		return obj;
	}
}
2.2采用cglib(字节码增强)方式实现手动方式

   使用cglib字节码增强方式实现代理,需要导入相关的jar包(cglib.jar和asm.jar),但是一般Spring的核心包总已经提供了对cglib的支持。

   使用cglib字节码生成代理类不需要实现目标类的接口,而是通过目标类直接生成代理类(cglib生成代理类是采用继承的方式  实现代理)

   第一步:准备目标类(target)

     目标类代码:

public class UserServiceImpl{

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

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

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

}

    第二步:准备切面类(advice)

       切面类代码:

public class MyAspect {
	
	public void before() {
		System.out.println("前方法");
	}
	
	public void after() {
		System.out.println("后方法 ");
	};
}

   第三步:创建自定义工厂对目标类进行代理

      使用cglib创建代理采用的核心类是Enhancer,通过Enhancer类中create方法创建目标类的代理。但是在执行create方法之前需要确定代理目标类(也就是代理类的父类),确定父类是通过Enhancer类中的setSupperClass(父类的字节码)。也需要对Enhancer设置回调函数,也就是调用setCallback(Callback)。

  代码:

public class MyBeanFactory {
	
	//应为这个类是生成代理类,所以就通过这个方法产生代理类 
	public static UserServiceImpl createService() {
		//首先需要目标类
		UserServiceImpl userService = new UserServiceImpl();
		//切面类
		MyAspect myAspect = new MyAspect();
		//代理类: 采用cglib,底层创建目标类的子类
		//核心类
		Enhancer enhancer = new Enhancer();
		//确定父类
		enhancer.setSuperclass(userService.getClass());
		/**
		 * 设置回调函数:MethodInterceptor接口 等效于jdk中 InvacationHandler接口
		 * intercept()方法等效于jdk 的invoke()方法
		 * 参数1、参数2、参数3和invoke方法一样。
		 * 参数4调用代理类父类的目标方法
		 */
		enhancer.setCallback(new MethodInterceptor() {
			@Override
			public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
				//执行前方法
				myAspect.before();
				//执行目标方法
				//Object object = method.invoke(userService, args);
				//methodProxy 执行代理类父类的目标方法相当于执行userServiceImpl中的目标方法
				//Object object = methodProxy.invokeSuper(proxy, args);
				Object object = methodProxy.invoke(userService, args);
				//执行后方法
				myAspect.after();
				return object;
			}
		});
		//创建代理类
		UserServiceImpl userServiceProxy = (UserServiceImpl) enhancer.create();
		return userServiceProxy;
	}
}

3.通过AOP联盟定义的规范和Spring提供的支持实现半自动方式

 3.1.AOP联盟定义的通知类型

     1.AOP联盟定义的通知类型在org.aopalliance.aop.Advice中。

     2.Spring按照通知(advice)在目标方法的前后分为五类:

        前置通知org.springframework.aop.MethodBeforeAdvice:在目标方法执行前进行增强。

        后置通知org.springframework.aop.AfterReturningAdvice:在目标方法执行后进行增强。

        环绕通知org.aopalliance.intercept.MethodInterceptor:在目标方法执行前后进行增强,但是必须手动执行目标方法。

        异常抛出通知org.springframework.aop.ThrowsAdvice:在方法执行过程中抛出异常后进行增强。

        引介通知org.springframework.aop.IntroductionInterceptor:在目标类中添加一些新的属性和方法时进行增强。

 3.2.需要导入的jar包

   需要导入aop(org.aopalliance.jar)规范和Spring对规范的实现(spring-aop.jar)。

 3.3.进行半自动方式AOP编程
     第一步:准备目标类(target)

        目标类所实现的接口:

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

          目标类:

public class UserServiceImpl implements UserService{

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

	@Override
	public void updateUser() {
		System.out.println("updateUser");
	}

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

}
     第二步:准备切面类(advice)

       这里用我们经常用到的环绕通知进行演示。

       使用aop联盟方式进行aop编程,切面类需要按照aop联盟规范进行定义,使用环绕通知,advice类就需要实现接口MethodInterceptor。

     代码:

public class MyAspect implements MethodInterceptor{
	
	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		
		//执行前方法
		System.out.println("前方法");
		
		//手动执行目标方法
		Object object = mi.proceed();
		
		//执行后方法
		System.out.println("后方法");
		return object;
	};
}
     第三步:在Spring配置文件中进行配置

      Spring配置文件配置,首先需要向配置文件中配置目标类和切面类bean,然后再通过ProxyFactoryBean来对目标类进行自动生成代理(也就是对目标类进行加强)。由于是通过Spring容器来自动对目标类进行代理,所以需要给ProxyFactoryBean注入目标类所实现的接口(通过接口可以通过jdk方式生成代理,如果没有配置接口,就会采用cglib方式进行代理。这种代理方式也是Spring的默认方式),也需要注入目标类(不管是jdk代理还是cglib代理都需要目标类),同时也需要注入切面类。如果不管是否有注入接口,都需要采用cglib方式进行代理,就给ProxyFactoryBean类中注入optimize,并且设置为true。

      配置文件如下:

<!-- 1 创建目标类 -->
	<bean id="userServiceId" class="com.test.c_proxy_by_FactoryBean.UserServiceImpl"></bean>	
	
	<!-- 2创建切面类 -->
	<bean id="myAspect" class="com.test.c_proxy_by_FactoryBean.MyAspect"></bean>
	
	<!-- 3 创建代理类 
		* 使用工厂bean FactoryBean ,底层调用 getObject() 返回特殊bean
		* ProxyFactoryBean 用于创建代理工厂bean,生成特殊代理对象
			interfaces : 确定接口们
				通过<array>可以设置多个值
				只有一个值时,value=""
			target : 确定目标类
			interceptorNames : 通知 切面类的名称,类型String[],如果设置一个值 value=""
			optimize :强制使用cglib
				<property name="optimize" value="true"></property>
		底层机制
			如果目标类有接口,采用jdk动态代理
			如果没有接口,采用cglib 字节码增强
			如果声明 optimize = true ,无论是否有接口,都采用cglib
		
	-->
	<bean id="proxyUserService" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!-- 代理类所需要实现的接口,通过接口去实现目标类的代理 -->
		<property name="interfaces" value="com.test.c_proxy_by_FactoryBean.UserService"></property>
		<!-- 目标类:通过Spring创建代理类需要指定代理类代理的目标类 -->
		<property name="target" ref="userServiceId"></property>
		<!-- 通知切面类名称 -->
		<property name="interceptorNames" value="myAspect"></property>
	</bean>

      这种方式也是通过Spring提供的一个特殊的Bean来自动对目标类进行代理或者增强。所以我们使用的时候是直接使用的代理类,而不是使用目标类。

4.Spring AOP编程:全自动

  第一步:准备目标类(target)

     目标类接口:

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

    目标类:

public class UserServiceImpl implements UserService{

	@Override
	public void addUser() {
		System.out.println("addUser");
		//int a = 1/0;
	}

	@Override
	public String updateUser() {
		System.out.println("updateUser");
		return "超哥";
	}

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

}

  第二步:准备切面类(advice)

  这里也是用环绕通知演示

public class MyAspect implements MethodInterceptor{
	
	@Override
	public Object invoke(MethodInvocation mi) throws Throwable {
		
		//执行前方法
		System.out.println("前方法");
		
		//手动执行目标方法
		Object object = mi.proceed();
		
		//执行后方法
		System.out.println("后方法");
		return object;
	};
}
   第三步:在Spring配置文件中进行配置

    在配置前需要给配置文件中加入aop的头信息。

<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

<!-- 1 创建目标类 -->
	<bean id="userServiceId" class="com.test.d_proxy_by_SpringAOP.UserServiceImpl"></bean>	
	
	<!-- 2创建切面类(通知) -->
	<bean id="myAspect" class="com.test.d_proxy_by_SpringAOP.MyAspect"></bean>

   最后进行aop编程:

<!-- 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="false">
		<aop:pointcut expression="execution(* com.test.d_proxy_by_SpringAOP.*.*(..))" id="myPointCut"/>
		<aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
	</aop:config>

这样在使用过程中就直接使用目标类就可以了,因为已经对目标类进行了加强。(其实采用这种方式进行增强原理是:在执行目标方法前通过了后处理bean(BeanPostProcessor)调用来对目标类进行代理,并返回。这样在执行目标类中的方法,而不是执行的是目标类中的方法,而是执行的是代理类中的方法)。

5.使用AOP框架AspectJ来进行AOP编程

  5.1.AspectJ介绍

    AspectJ是一个基于Java语言的AOP框架。

   Spring在2.0的时候提供了对AspectJ的切入点(PointCut)表达式的支持(切入点表达式就是从target(或者是说JoinPoint)中去选出需要增强的方法)

  5.2.切入点表达式

      通过execution()来描述方法,也就是从target中(或者说是JoinPoint中)选出需要增强的方法。至于如何选出就是在execution()中写入选择的表达式。

execution()语法介绍:execution(需要筛选方法的修饰符 筛选方法的返回值  包.类.方法名(方法参数) throws 异常)。

    修饰符:一般可以省略。

           public   公共方法(private protect.....)

           *           任意修饰符

     返回值:返回值不能进行省略。

           void       返回值为空

           String     返回值为字符串(其它省略)

           *             任意返回值

      包:可以省略,但是一般不省略。

           com.test.a         固定包

           com.test.a.*.service   a包下的任意子包下的service包

           com.test.a..        a包下的所有子包

      类:可以省略,但是一般不省略。

           UserServiceImpl    指定类

           *Impl                      以Impl结尾的类

           User*                     以User开头的类

           *                            任意类

      方法名:不能省略。

            addUser               固定方法

            add*                     以add开头的方法

            *Delete                 以Delete结尾的方法

            *                            任意方法 

      参数:不能省略。

            ()                      无参数

            (int)                  一个int参数

            (int,int)            两个int参数

             (..)                   参数任意

       throws,可以省略。一般我们也不写。

  5.3AspectJ通知类型

   

     before:前置通知(应用:各种校验)

     在方法执行前执行,如果通知抛出异常,阻止方法运行

     afterReturning:后置通知(应用:常规数据处理)

     方法正常返回后执行,如果方法中抛出异常,通知无法执行

     必须在方法执行后才执行,所以可以获得方法的返回值。

     around:环绕通知(应用:十分强大,可以做任何事情)

     方法执行前后分别执行,可以阻止方法的执行

     必须手动执行目标方法

     afterThrowing:抛出异常通知(应用:包装异常信息)

     方法抛出异常后执行,如果方法没有抛出异常,无法执行

     after:最终通知(应用:清理现场)

     方法执行完毕后执行,无论方法中是否出现异常

5.3.导入jar包

   导入的jar主要有四个:aop联盟(aopallicance.jar),Spring对AOP联盟的支持(Spring-aop.jar),AspectJ(aspectJ.weaver.jar),Spring对AspectJ的支持(Spring-aspectJ.jar)

5.4.使用AspectJ方式进行AOP编程
     第一步:准备目标类

         目标类所实现的接口:

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

         目标类:

public class UserServiceImpl implements UserService{

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

	@Override
	public void updateUser() {
		System.out.println("updateUser");
	}

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

}
     第二步:准备切面类

      切面类不需要向AOP联盟那样必须实现他的规范,而是采用AspectJ提供通知名任意(方法名任意)

     代码:

public class MyAspect {

	//JoinPoint 用于描述连接点(目标方法),可以获得目标方法名等。
	public void myBefore(JoinPoint joinPoint) {
		System.out.println("前置通知" + joinPoint.getSignature().getModifiers());
	}
	
	//后置通知
	//	通知方法格式:public void myAfterReturning(JoinPoint joinPoint,Object ret){
	//		参数1:连接点描述
	//		参数2:类型Object,参数名 returning="ret" 配置的
	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() {
		System.out.println("最终通知");
	}
}
   第三步:Spring配置文件进行配置

    

<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.test.e_proxy_by_AspectJXML.UserServiceImpl"></bean>	
	
	<!-- 2创建切面类(通知) -->
	<bean id="myAspect" class="com.test.e_proxy_by_AspectJXML.MyAspect"></bean>
	
	<!-- 3aop编程
		<aop:aspect>将切面类声明成“切面”,从而获得通知(方法)
		ref 切面类引用
		<aop:pointcut>声明一个切入点,所有通知都可以使用。
		expression 切入点表达式
		id 名称用于其他通知引用
	 -->
	 <aop:config proxy-target-class="false">
	 	<aop:pointcut expression="execution(* com.test.e_proxy_by_AspectJXML.UserServiceImpl.*(..))" id="myPointCut"/>
	 	<aop:aspect ref="myAspect">
	 		<!-- 
	 			3.1前置通知:
	 				<aop:before method="" pointcut="" pointcut-ref=""/>
	 				method:通知,及方法名。
	 				pointcut:切入点表达式,此表达式只能当前通知使用。
	 				pointcut-ref:切入点引用,可以与其他通知共享切入点。
	 			<aop:before method="myBefore"  pointcut-ref="myPointCut"/>
	 		 -->
	 		 <!-- 
	 		 	3.2后置通知:目标方法后执行,可以获得返回值。
	 		 		<aop:after-returning method="" pointcut-ref="" returning=""/>
	 		 		returning:第二个参数的名称。
	 		  <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>

6.使用AspectJ注解方式

第一步:修改配置文件

   使用注解的方式实现AOP编程,首先需要对Spring配置文件添加context头信息

<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/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd">

  然后打开Spring的注解扫描:

<!-- 添加注解扫描 -->
    <context:component-scan base-package="com.test.f_proxy_by_AspectJAnnotation"></context:component-scan>

  接下来是让AspectJ注解生效:

<!-- 让Aspect注解生效 :添加aspectj自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

整个Spring配置文件代码如下:

<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/context 
       					   http://www.springframework.org/schema/context/spring-context.xsd
       					   http://www.springframework.org/schema/aop 
       					   http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!-- 添加注解扫描 -->
    <context:component-scan base-package="com.test.f_proxy_by_AspectJAnnotation"></context:component-scan>
    
    <!-- 让Aspect注解生效 :添加aspectj自动代理-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

</beans>
第二步:准备目标类(target)

   目标类所实现的接口:

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

   目标类:

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

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

	@Override
	public void updateUser() {
		System.out.println("updateUser");
		//int a = 1/0;
	}

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

}
第三步:准备切面类并直接在切面类添加注解进行AOP编程

在切面类上添加@Aspect注解是指该类为切面类。

在切面类的方法中分别添加以下注解:

(在value中对AspectJ表达式进行引用:首先需要有可引用的pointcut。如何准备pointcut呢?

    在切面类中任意写一个无返回值无参数的方法,并在方法前面加上@Pointcut(里面写表达式)注解。

   后面引用就直接写该方法。

  )

 @Before(value="aspectJ表达式或者aspectJ表达式的引用"):该方法将作为增强代码(advice)织入(weaving)到目标类中(target)。  

代码如下:

@Component
@Aspect
public class MyAspect {
	
	//注解方式生成切入点引用
	@Pointcut(value="execution(* com.test.f_proxy_by_AspectJAnnotation.UserServiceImpl.*(..))")
	private void myPointCut() {
		
	}
	
	//添加前置通知注解:value属性里面写切入点表达式或者切入点引用
	//@Before("execution(* com.test.f_proxy_by_AspectJAnnotation.UserServiceImpl.*(..))")
	public void myBefore(JoinPoint joinPoint) {
		System.out.println("前置通知" + joinPoint.getSignature().getModifiers());
	}
	
	//添加后置通知
	//@AfterReturning(value="myPointCut()",returning="ret")
	public void myAfterReturning(JoinPoint joinPoint,Object ret) {
		System.out.println("后置通知"+joinPoint.getSignature().getName()+",---->"+ret);
	}
	
	//添加环绕通知
	//@Around("myPointCut()")
	public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
		//执行前方法
		System.out.println("前");
		//需要手动执行目标方法
		Object  obj =joinPoint.proceed();
		//执行后方法
		System.out.println("后");
		return obj;
	}
	
	//添加抛出异常通知
	//@AfterThrowing(value="myPointCut()",throwing="e")
	public void myAfterThrowing(JoinPoint joinPoint,Throwable e) {
		System.out.println("抛出异常通知:"+e.getMessage());
	}
	
	//添加最后通知
	@After("execution(* com.test.f_proxy_by_AspectJAnnotation.UserServiceImpl.*(..))")
	public void myAfter() {
		System.out.println("最终通知");
	}
}




  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值