重温Spring之旅6——基于XML配置方式进行AOP开发

本文通过实战案例介绍了 Spring AOP 的基本配置与使用方法,包括引入必要的命名空间、配置文件及依赖库,演示了五种通知类型的具体实现过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

要进行AOP编程,首先我们要在spring的配置文件中引入aop命名空间:

<?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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   <!-- 
   		添加基于spring的aop切面的命名空间:添加:
   		xmlns:aop="http://www.springframework.org/schema/aop"
   		http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    -->
</beans>
Spring提供了两种切面使用方式,实际工作中我们可以选用其中一种:

  • 基于XML配置方式进行AOP开发。
  • 基于注解方式进行AOP开发。
要进行AOP编程,需要引入的jar包
com.springsource.net.sf.cglib-2.2.0.jar:cglib代理
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.tools-1.6.6.RELEASE.jar
org.springframework.aop-3.0.2.RELEASE.jar:spring的面向切面编程,提供AOP(面向切面编程)实现
org.springframework.aspects-3.0.2.RELEASE.jar:spring提供对AspectJ框架的整合

基于XML配置—前置通知:

IUserManager.java
package com.xbmu.e.aop.xml.a_before;

public interface IUserManager {
	void saveUser(String username,String password);
	void updateUser(String username,String password);
	void deleteUser(String username);
	String findUser(String username);
}
UserManagerImpl.java
package com.xbmu.e.aop.xml.a_before;

public class UserManagerImpl implements IUserManager{

	@Override
	public void saveUser(String username, String password) {
		System.out.println("UserManagerImpl---saveUser");
		
	}

	@Override
	public void updateUser(String username, String password) {
		System.out.println("UserManagerImpl---updateUser");
		
	}

	@Override
	public void deleteUser(String username) {
		System.out.println("UserManagerImpl---deleteUser");
	}

	@Override
	public String findUser(String username) {
		System.out.println("UserManagerImpl---findUser");
		return username;
	}

}
Security.java
package com.xbmu.e.aop.xml.a_before;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

/**切面*/
public class Security {
	/**通知*/
	/**
	 * 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
	 * (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
	 * 
	 * org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
	 * getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
	 * 
	 * @param joinPoint 获取连接点的一些信息(目标对象中的方法)
	 */
	public void checkSecurity(JoinPoint joinPoint){
		System.out.println("进行安全检查!");
		System.out.println("连接点类:"+joinPoint.getClass());
		System.out.println("目标对象:"+joinPoint.getTarget());
		Signature signature = joinPoint.getSignature();
		System.out.println("方法名称:"+signature.getName());
		Object[] args = joinPoint.getArgs();
		if(null!=args && args.length>0){
			for (Object obj : args) {
				System.out.println("参数:"+obj);
			}
		}
	}
}
App.java
package com.xbmu.e.aop.xml.a_before;

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

public class App {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/a_before/beans.xml");
		IUserManager userManager = (IUserManager) ctx.getBean("userManage");
		/**
		 * 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
		 * 当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
		 */
		userManager.saveUser("张三", "123");
		System.out.println("**************************************");
		userManager.updateUser("李四", "456");
	}
}
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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   <!-- 
   		添加基于spring的aop切面的命名空间:添加:
   		xmlns:aop="http://www.springframework.org/schema/aop"
   		http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    -->
	<!-- 声明一个切面,该切面不具有灵魂 -->	
	<bean id="security" class="com.xbmu.e.aop.xml.a_before.Security"></bean>
	<bean id="userManage" class="com.xbmu.e.aop.xml.a_before.UserManagerImpl"></bean>
	<!-- 
		声明一个切入点
		通知、切入点、通知关联切入点等操作都要放置到aop:config中
		
   	  	注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	        当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
	-->
	<aop:config>
		<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
		<aop:aspect id="security1" ref="security">
			<!-- 
				声明切入点
					id:为切入点起个名字
					expression:表达式,定义切入点 
			-->
			<aop:pointcut  id="pointcutSave" 
				expression="execution(* com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..))" />
			<!--  
				将切入点和通知进行关联
				aop:before:前置通知
					* 在访问切入点之前进行通知
					* 如果在通知中出现异常,可以阻止程序到切入点
			
			-->
			<aop:before method="checkSecurity" pointcut-ref="pointcutSave"/>
		</aop:aspect>
	</aop:config>
	<!-- 
   		aop:pointcut:expression详细说明:?号表示该参数不是必须的
   		   execution(modifiers-pattern? :修饰符:不是必须的,如public,private等。 
   		                                 public * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
   		              ret-type-pattern :返回类型
 		                    String com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
							说明返回类型是String
 		                    Integer com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
							说明返回类型是Integer
 		                    *com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
							可以接收任意的返回类型
   		              declaring-type-pattern? :不是必须的,声明包中类的路径,
   		              		本例(com.xbmu.e.aop.xml.a_before.UserManagerImpl)
   		                    com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
   		              name-pattern:表示方法的名称
   		                    *com.xbmu.e.aop.xml.a_before.UserManagerImpl.saveUser(..)
							此时找saveUser的方法
   		                    * com.xbmu.e.aop.xml.a_before.UserManagerImpl.*(..)
							此时找该UserManageImpl类中所有的方法
   		                    * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..)
							此时找该UserManageImpl类中以save开头的所有方法
   		                    * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*get(..)
							此时找该UserManageImpl类中以save开头,get结束的所有方法
   		                     (param-pattern):方法的参数
   		                    * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*():'
   		                                        匹配了一个不接受任何参数的方法
   		                    * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(..):
   		                                        而(..)匹配了一个接受任意数量参数的方法(零或者更多)
   		                    * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(*): 
   		                                        模式(*)匹配了一个接受一个任何类型的参数的方法
   		                    * com.xbmu.e.aop.xml.a_before.UserManagerImpl.save*(*,String):
   		                                      模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型, 第二个则必须是String类型。
                                 (throws-pattern?)
   	                           除了返回类型模式(上面代码片断中的ret-type-pattern),名字模式和参数模式以外, 所有的部分都是可选的。
		   	    * 返回类型模式决定了方法的返回类型必须依次匹配一个连接点。 你会使用的最频繁的返回类型模式是*,
		   	            它代表了匹配任意的返回类型。一个全限定的类型名将只会匹配返回给定类型的方法。
		   	    * 名字模式匹配的是方法名。 你可以使用*通配符作为所有或者部分命名模式。 
		   	    * 参数模式稍微有点复杂:()匹配了一个不接受任何参数的方法, 而(..)匹配了一个接受任意数量参数的方法(零或者更多)。 
		   	            模式(*)匹配了一个接受一个任何类型的参数的方法。 模式(*,String)匹配了一个接受两个参数的方法,第一个可以是任意类型,
		   	            第二个则必须是String类型
   	    

         任意公共方法的执行:
		execution(public * *(..))
		
		任何一个名字以“set”开始的方法的执行:
		execution(* set*(..))
		
		AccountService接口定义的任意方法的执行:
		execution(* com.xyz.service.AccountService.*(..))
		
		在service包中定义的任意方法的执行
		execution(* com.xyz.service.*.*(..))
		
		在service包或其子包中定义的任意方法的执行:(项目经常用到)
		execution(* com.xyz.service..*.*(..))
        
    
    -->
</beans>
运行结果:


如果在通知中出现异常,可以阻止程序到切入点

Security.java

package com.xbmu.e.aop.xml.a_before;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

/**切面*/
public class Security {
	/**通知*/
	/**
	 * 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
	 * (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
	 * 
	 * org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
	 * getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
	 * 
	 * @param joinPoint 获取连接点的一些信息(目标对象中的方法)
	 */
	public void checkSecurity(JoinPoint joinPoint){
		System.out.println("进行安全检查!");
		System.out.println("连接点类:"+joinPoint.getClass());
		System.out.println("目标对象:"+joinPoint.getTarget());
		Signature signature = joinPoint.getSignature();
		System.out.println("方法名称:"+signature.getName());
		Object[] args = joinPoint.getArgs();
		if(null!=args && args.length>0){
			for (Object obj : args) {
				System.out.println("参数:"+obj);
			}
		}
		//阻止到切入点的程序,抛出异常
		if(true){
			throw new RuntimeException("出现异常");
		}
	}
}
运行结果:


基于XML配置—后置通知:

Security.java
package com.xbmu.e.aop.xml.b_afterreturn;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

/**切面*/
public class Security {
	/**通知*/
	/**
	 * 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
	 * (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
	 * 
	 * org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
	 * getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
	 * 
	 * @param joinPoint 获取连接点的一些信息(目标对象中的方法)
	 * 	spring容器中的定义:
	 * 	<aop:after-returning pointcut-ref="pointcutSave"
             method="checkSecurity" returning="returnvalue"/>
     * 后置通知获取切入点的返回值
	 * 注意:返回是一个Object对象
	 *     Object的参数名称必须是returning属性的值
	 *     Object returnvalue必须要放置到JoinPoint的后面
	 */
	public void checkSecurity(JoinPoint joinPoint,Object returnvalue){
		System.out.println("进行安全检查!");
		System.out.println("连接点类:"+joinPoint.getClass());
		System.out.println("目标对象:"+joinPoint.getTarget());
		Signature signature = joinPoint.getSignature();
		System.out.println("方法名称:"+signature.getName());
		Object[] args = joinPoint.getArgs();
		if(null!=args && args.length>0){
			for (Object obj : args) {
				System.out.println("参数:"+obj);
			}
		}
		System.out.println("返回值:"+returnvalue);
	}
}
App.java
package com.xbmu.e.aop.xml.b_afterreturn;

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

public class App {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/b_afterreturn/beans.xml");
		IUserManager userManager = (IUserManager) ctx.getBean("userManage");
		/**
		 * 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	       	当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
		 */
		userManager.saveUser("张三", "123");
		System.out.println("**************************************");
		userManager.updateUser("李四", "456");
		System.out.println("**************************************");
		String str = userManager.findUser("赵六");
		System.out.println("str:"+str);
	}
}
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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   <!-- 
   		添加基于spring的aop切面的命名空间:添加:
   		xmlns:aop="http://www.springframework.org/schema/aop"
   		http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    -->
	<!-- 声明一个切面,该切面不具有灵魂 -->	
	<bean id="security" class="com.xbmu.e.aop.xml.b_afterreturn.Security"></bean>
	<bean id="userManage" class="com.xbmu.e.aop.xml.b_afterreturn.UserManagerImpl"></bean>
	<!-- 
		声明一个切入点
		通知、切入点、通知关联切入点等操作都要放置到aop:config中
		
   	  	注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	        当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
	-->
	<aop:config>
		<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
		<aop:aspect id="security1" ref="security">
			<!-- 
				声明切入点
					id:为切入点起个名字
					expression:表达式,定义切入点 
			-->
			<aop:pointcut  id="pointcutSave" 
				expression="execution(* com.xbmu.e.aop.xml.b_afterreturn.UserManagerImpl.save*(..))" />
			<aop:pointcut id="pointcutFind" 
				expression="execution(* com.xbmu.e.aop.xml.b_afterreturn.UserManagerImpl.find*(..))" />
			<!--  
				将切入点和通知进行关联
				aop:after-returning:后置通知
					* 在访问切入点之前进行通知
					* 如果在通知中出现异常,可以阻止程序到切入点
					
				returning=在通知中可以获取到切入点的返回值
			-->
			<aop:after-returning pointcut-ref="pointcutSave" method="checkSecurity" returning="returnvalue"/>
			<aop:after-returning pointcut-ref="pointcutFind" method="checkSecurity" returning="returnvalue"/>
		</aop:aspect>
	</aop:config>
</beans>


运行结果:

如果在通知中出现异常,可以阻止程序到切入点
Security.java
package com.xbmu.e.aop.xml.b_afterreturn;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

/**切面*/
public class Security {
	/**通知*/
	/**
	 * 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
	 * (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
	 * 
	 * org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
	 * getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
	 * 
	 * @param joinPoint 获取连接点的一些信息(目标对象中的方法)
	 * 	spring容器中的定义:
	 * 	<aop:after-returning pointcut-ref="pointcutSave"
             method="checkSecurity" returning="returnvalue"/>
     * 后置通知获取切入点的返回值
	 * 注意:返回是一个Object对象
	 *     Object的参数名称必须是returning属性的值
	 *     Object returnvalue必须要放置到JoinPoint的后面
	 */
	public void checkSecurity(JoinPoint joinPoint,Object returnvalue){
		System.out.println("进行安全检查!");
		System.out.println("连接点类:"+joinPoint.getClass());
		System.out.println("目标对象:"+joinPoint.getTarget());
		Signature signature = joinPoint.getSignature();
		System.out.println("方法名称:"+signature.getName());
		Object[] args = joinPoint.getArgs();
		if(null!=args && args.length>0){
			for (Object obj : args) {
				System.out.println("参数:"+obj);
			}
		}
		System.out.println("返回值:"+returnvalue);
		//阻止到切入点的程序,抛出异常
		if(true){
			throw new RuntimeException("出现异常");
		}
	}
}
运行结果:


基于XML配置—异常通知

Security.java
package com.xbmu.e.aop.xml.c_afterthrowing;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

/**切面*/
public class Security {
	/**通知*/
	/**
	 * 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
	 * (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
	 * 
	 * org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
	 * getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
	 * 
	 * @param joinPoint 获取连接点的一些信息(目标对象中的方法)
	 * 	spring容器中的定义:
	 * 	<aop:after-returning pointcut-ref="pointcutSave"
             method="checkSecurity" returning="returnvalue"/>
     * 后置通知获取切入点的返回值
	 * 注意:返回是一个Object对象
	 *     Object的参数名称必须是returning属性的值
	 *     Object returnvalue必须要放置到JoinPoint的后面
	 */
	public void checkSecurity(JoinPoint joinPoint,Throwable throwExecution){
		System.out.println("进行安全检查!");
		System.out.println("连接点类:"+joinPoint.getClass());
		System.out.println("目标对象:"+joinPoint.getTarget());
		Signature signature = joinPoint.getSignature();
		System.out.println("方法名称:"+signature.getName());
		Object[] args = joinPoint.getArgs();
		if(null!=args && args.length>0){
			for (Object obj : args) {
				System.out.println("参数:"+obj);
			}
		}
		System.out.println("异常:"+throwExecution);
	}
}
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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   <!-- 
   		添加基于spring的aop切面的命名空间:添加:
   		xmlns:aop="http://www.springframework.org/schema/aop"
   		http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    -->
	<!-- 声明一个切面,该切面不具有灵魂 -->	
	<bean id="security" class="com.xbmu.e.aop.xml.c_afterthrowing.Security"></bean>
	<bean id="userManage" class="com.xbmu.e.aop.xml.c_afterthrowing.UserManagerImpl"></bean>
	<!-- 
		声明一个切入点
		通知、切入点、通知关联切入点等操作都要放置到aop:config中
		
   	  	注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	        当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
	-->
	<aop:config>
		<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
		<aop:aspect id="security1" ref="security">
			<!-- 
				声明切入点
					id:为切入点起个名字
					expression:表达式,定义切入点 
			-->
			<aop:pointcut  id="pointcutSave" 
				expression="execution(* com.xbmu.e.aop.xml.c_afterthrowing.UserManagerImpl.save*(..))" />
			<!--  
				将切入点和通知进行关联
				aop:after-throwing:异常通知
   	  	 	     * 通知在切入点要抛出异常之后执行,如果切入点不抛出异常,此时不会执行通知
   	  	    
   	  	    	throwing="":用于在通知中查看切入点抛出的异常
			-->
			<aop:after-throwing pointcut-ref="pointcutSave" method="checkSecurity" throwing="throwExecution"/>
		</aop:aspect>
	</aop:config>
</beans>
运行结果:


通知在切入点要抛出异常之后执行,如果切入点不抛出异常,此时不会执行通知。
UserManagerImpl.java
package com.xbmu.e.aop.xml.c_afterthrowing;

public class UserManagerImpl implements IUserManager{

	@Override
	public void saveUser(String username, String password) {
		System.out.println("UserManagerImpl---saveUser");
		if(true){
			throw new RuntimeException("出现异常");
		}
		
	}

	@Override
	public void updateUser(String username, String password) {
		System.out.println("UserManagerImpl---updateUser");
		
	}

	@Override
	public void deleteUser(String username) {
		System.out.println("UserManagerImpl---deleteUser");
	}

	@Override
	public String findUser(String username) {
		System.out.println("UserManagerImpl---findUser");
		return username;
	}

}


基于XML配置—最终通知

Security.java
package com.xbmu.e.aop.xml.d_after;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;

/**切面*/
public class Security {
	/**通知*/
	/**
	 * 任何通知方法可以将第一个参数定义为org.aspectj.lang.JoinPoint类型
	 * (环绕通知需要定义第一个参数为org.aspectj.lang.ProceedingJoinPoint类型,它是org.aspectj.lang.JoinPoint的一个子类)。
	 * 
	 * org.aspectj.lang.JoinPoint接口提供了一系列有用的方法,比如getArgs():返回方法参数、getThis():返回代理对象、
	 * getTarget():返回目标、 getSignature():返回正在被通知的方法相关信息和 toString()打印出正在被通知的方法的有用信息。
	 * 
	 * @param joinPoint 获取连接点的一些信息(目标对象中的方法)
	 */
	public void checkSecurity(JoinPoint joinPoint){
		System.out.println("进行安全检查!");
		System.out.println("连接点类:"+joinPoint.getClass());
		System.out.println("目标对象:"+joinPoint.getTarget());
		Signature signature = joinPoint.getSignature();
		System.out.println("方法名称:"+signature.getName());
		Object[] args = joinPoint.getArgs();
		if(null!=args && args.length>0){
			for (Object obj : args) {
				System.out.println("参数:"+obj);
			}
		}
	}
}
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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   <!-- 
   		添加基于spring的aop切面的命名空间:添加:
   		xmlns:aop="http://www.springframework.org/schema/aop"
   		http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    -->
	<!-- 声明一个切面,该切面不具有灵魂 -->	
	<bean id="security" class="com.xbmu.e.aop.xml.d_after.Security"></bean>
	<bean id="userManage" class="com.xbmu.e.aop.xml.d_after.UserManagerImpl"></bean>
	<!-- 
		声明一个切入点
		通知、切入点、通知关联切入点等操作都要放置到aop:config中
		
   	  	注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	        当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
	-->
	<aop:config>
		<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
		<aop:aspect id="security1" ref="security">
			<!-- 
				声明切入点
					id:为切入点起个名字
					expression:表达式,定义切入点 
			-->
			<aop:pointcut  id="pointcutSave" 
				expression="execution(* com.xbmu.e.aop.xml.d_after.UserManagerImpl.save*(..))" />
			<!--  
				将切入点和通知进行关联
				aop:after:最终通知
   	  	 	     * 最终通知在切入点无论是否抛出异常都会执行通知
   	  	 	     
			-->
			<aop:after pointcut-ref="pointcutSave" method="checkSecurity"/>
		</aop:aspect>
	</aop:config>
</beans>
App.java
package com.xbmu.e.aop.xml.d_after;

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

public class App {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/d_after/beans.xml");
		IUserManager userManager = (IUserManager) ctx.getBean("userManage");
		/**
		 * 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	       	当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
		 */
		userManager.saveUser("张三", "123");
		System.out.println("**************************************");
		userManager.updateUser("李四", "456");
	}
}
运行结果:

最终通知在切入点无论是否抛出异常都会执行通知
UserManagerImpl.java
package com.xbmu.e.aop.xml.d_after;

public class UserManagerImpl implements IUserManager{

	@Override
	public void saveUser(String username, String password) {
		System.out.println("UserManagerImpl---saveUser");
		if(true){
			throw new RuntimeException("出现异常");
		}
		
	}

	@Override
	public void updateUser(String username, String password) {
		System.out.println("UserManagerImpl---updateUser");
		
	}

	@Override
	public void deleteUser(String username) {
		System.out.println("UserManagerImpl---deleteUser");
	}

	@Override
	public String findUser(String username) {
		System.out.println("UserManagerImpl---findUser");
		return username;
	}

}

基于XML配置—环绕通知

Security.java
package com.xbmu.e.aop.xml.e_around;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;

/**切面*/
public class Security {
	/**通知*/
	/**
	 * 
	 * 如果是环绕通知:
	 *    * 环绕通知在一个方法执行之前和之后执行。它使得通知有机会 在一个方法执行之前和执行之后运行。
	 *      而且它可以决定这个方法在什么时候执行,如何执行,甚至是否执行
	 *    * 通知的第一个参数必须是 ProceedingJoinPoint类型。
	 *      在通知体内,调用 ProceedingJoinPoint的proceed()方法会导致 后台的连接点方法执行。
	 * 第一个参数:
	 * 		* ProceedingJoinPoint joinPoint,获取连接点的一些信息(目标对象中的方法)
	 *      * 如果是环绕通知,可以有返回值,是一个Object对象
	 */
	public Object checkSecurity(ProceedingJoinPoint joinPoint){
		Object returnValue = null;
		try {
			returnValue = joinPoint.proceed();//调切入点的方法
		} catch (Throwable e) {
			e.printStackTrace();
		}
		
		System.out.println("进行安全检查!");
		System.out.println("连接点类:"+joinPoint.getClass());
		System.out.println("目标对象:"+joinPoint.getTarget());
		Signature signature = joinPoint.getSignature();
		System.out.println("方法名称:"+signature.getName());
		Object [] arg = joinPoint.getArgs();
		if(arg!=null && arg.length>0){
			for(Object o:arg){
				System.out.println("参数:"+o);
			}
		}
		
		return returnValue;
	}
}
App.java
package com.xbmu.e.aop.xml.e_around;

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

public class App {
	public static void main(String[] args) {
		ApplicationContext ctx = new ClassPathXmlApplicationContext("com/xbmu/e/aop/xml/e_around/beans.xml");
		IUserManager userManager = (IUserManager) ctx.getBean("userManage");
		/**
		 * 注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	       	当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
		 */
		userManager.saveUser("张三", "123");
		System.out.println("**************************************");
		userManager.updateUser("李四", "456");
	}
}
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-3.0.xsd
           http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context-3.0.xsd
           http://www.springframework.org/schema/aop
           http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
   <!-- 
   		添加基于spring的aop切面的命名空间:添加:
   		xmlns:aop="http://www.springframework.org/schema/aop"
   		http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop-3.0.xsd"
    -->
	<!-- 声明一个切面,该切面不具有灵魂 -->	
	<bean id="security" class="com.xbmu.e.aop.xml.e_around.Security"></bean>
	<bean id="userManage" class="com.xbmu.e.aop.xml.e_around.UserManagerImpl"></bean>
	<!-- 
		声明一个切入点
		通知、切入点、通知关联切入点等操作都要放置到aop:config中
		
   	  	注意:当程序调用目标对象的方法时,该方法如果在切入点的范围之内,此时通知可以对切入点进行拦截
   	        当程序调用目标对象的方法时,该方法如果没有在切入点的范围之内,此时通知不能对切入点进行拦截,只能访问目标对象的方法
	-->
	<aop:config>
		<!-- 注入切面,后续会将切面中的通知关联到切入点,相当于将切面注入灵魂 -->
		<aop:aspect id="security1" ref="security">
			<!-- 
				声明切入点
					id:为切入点起个名字
					expression:表达式,定义切入点 
			-->
			<aop:pointcut  id="pointcutSave" 
				expression="execution(* com.xbmu.e.aop.xml.e_around.UserManagerImpl.save*(..))" />
			<!--  
				将切入点和通知进行关联
   	  	 		aop:around:环绕通知
   	  	 	     * 环绕通知表示可以在切入点的前后动态的执行通知
   	  	 	     
			-->
			<aop:around pointcut-ref="pointcutSave" method="checkSecurity"/>
		</aop:aspect>
	</aop:config>
</beans>
运行结果:



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

上善若水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值