Spring面向切面编程三

本文介绍了 Spring AOP 的四种实现方式,包括基于 XML 配置、自动代理器、AspectJ 注解及 AspectJ XML 配置。每种方式通过实例详细展示了如何设置切面、通知类型,并给出了相应的测试结果。

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

Spring AOP多种实现方式

1、四种方式实现

(1)基于XML配置实现AOP
(2)基于自动代理器实现AOP,
(3)基于AspectJ注解实现
(4)基于AspectJ使用XML配置实现

2、所需jar包准备

至少需要准备下面四个jar包文件

3、几种方式实现AOP代理

首先新建几个类,栗子都是基于下面类
PersonService接口类
public interface PersonService {

	public String eat();
	
	public String work();
		
	public String sleep();	

	public String dowrong();
}

PersonServiceImpl实现类

public class PersonServiceImpl implements PersonService {


	@Override
	public String eat() {
		System.out.println("要吃饭了");
		return null;
	}


	@Override
	public String work() {
		System.out.println("努力工作才有饭吃");
		return "No pain no gain .";
	}


	@Override
	public String sleep() {
		System.out.println("休息好,养足精神!");
		return "good night !";
	}


	@Override
	public String dowrong() {
		System.out.println("异常方法"+ 3/0);
		return null;
	}

}




(1)基于XML配置实现AOP

新建切面类,分别实现相应接口,注意异常通知特殊点
/**
 * 前置通知
 * @author Administrator
 *
 */
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		System.out.println("前置通知====实现梦想");
	}

}

/**
 * 后置通知
 * @author Administrator
 *
 */
public class MyMethodAfterAdvice implements AfterReturningAdvice {

	@Override
	public void afterReturning(Object returnValue, Method method,
			Object[] args, Object target) throws Throwable {
		System.out.println("后置通知====时间都去哪了");
		
	}

}

/**
 * 后置通知
 * @author Administrator
 *
 */
public class MyMethodAroundAdvice implements MethodInterceptor {

	@Override
	public Object invoke(MethodInvocation invocation) throws Throwable {
		System.out.println("环绕通知====执行前处理");
		Object result = invocation.proceed();
		result = StringUtils.upperCase((String)result);
		System.out.println("环绕通知====执行后处理");
		return result;
	}


}

/**
 * 后置通知
 * @author Administrator
 *
 */
public class MyThrowsAdvice implements ThrowsAdvice {
	
	//默认四个重载的afterThrowing方法,当目标方法抛出异常时执行
	public void afterThrowing(Exception ex){
		System.out.println("执行异常通知");
	}

	public void afterThrowing(UserException ex){
		System.out.println("执行用户自定义异常"+ex.getMessage());
	}

}


然后来看看XML配置

	<!-- 注册目标对象 -->
 	<bean name="personService" class="aop.springaop.test5.PersonServiceImpl"/>
	<!-- 注册切面通知 -->
	<bean name="beforeAdvice" class="aop.springaop.test5.MyMethodBeforeAdvice"/>
	<bean name="afterAdvice" class="aop.springaop.test5.MyMethodAfterAdvice"/>
	
	<bean name="serviceproxy" class="org.springframework.aop.framework.ProxyFactoryBean">
		<!--targetName与target二者均可  -->
		<property name="targetName" value="personService"></property>
		<!-- <property name="target" ref="personService"></property> -->
		
		<!-- 方式一 使用字符串数组定义多个通知-->
		<property name="interceptorNames" value="beforeAdvice,afterAdvice"></property>
		<!-- 方式二 使用array定义多个通知 -->
		<!-- <property name="interceptorNames">
			<array>
				<value>beforeAdvice</value>
				<value>afterAdvice</value>
			</array>
		</property> -->
	</bean>

测试方法
	public static void main(String[] args) {
		String resouce = "aop/springaop/test5/applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
		PersonService workService =  (PersonService) applicationContext.getBean("serviceproxy");
		workService.eat();
		System.out.println("=====分割线=====");
		workService.work();
		System.out.println("=====分割线=====");
		workService.sleep();
		
	}

运行结果

(2)基于自动代理器实现AOP
常用的自动代理器有两种:DefaultAdvisorAutoProxyCreatorBeanNameAutoProxyCreator
	<!-- 多个目标对象 -->
 	<bean name="personService" class="aop.springaop.test10.PersonServiceImpl"/>
 	<bean name="personService2" class="aop.springaop.test10.PersonServiceImpl"/>
 	
	<!-- 注册切面通知 -->
	<bean name="beforeAdvice" class="aop.springaop.test10.MyMethodBeforeAdvice"/>
	<!-- 注册切面顾问 -->
 	<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
 		<property name="advice" ref="beforeAdvice"></property>
 		<property name="mappedName" value="work"></property>
 	</bean>
 	
	<bean class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator">
	</bean>
第二种用BeanNameAutoProxyCreator 相对前者有更多优点,可以更加精细
	<!-- 多个目标对象 -->
 	<bean name="personService" class="aop.springaop.test11.PersonServiceImpl"/>
 	<bean name="personService2" class="aop.springaop.test11.PersonServiceImpl"/>
 	
	<!-- 注册切面通知 -->
	<bean name="beforeAdvice" class="aop.springaop.test11.MyMethodBeforeAdvice"/>
	<!-- 注册切面顾问 -->
 	<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
 		<property name="advice" ref="beforeAdvice"></property>
 		<property name="mappedName" value="work"></property>
 	</bean>
 	
 	<bean id="myAdvisor2" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
 		<property name="advice" ref="beforeAdvice"></property>
 		<property name="mappedName" value="sleep"></property>
 	</bean>
 	
	<bean class="org.springframework.aop.framework.autoproxy.BeanNameAutoProxyCreator">
		<property name="beanNames" value="personService"></property>
		<property name="interceptorNames" value="myAdvisor"></property>	
	</bean>
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {

	@Override
	public void before(Method method, Object[] args, Object target)
			throws Throwable {
		
		System.out.println("前置通知====实现梦想");

	}

}


我们来看看都织入前置通知,二者自动代理器差别
	public static void main(String[] args) {
		String resouce = "aop/springaop/test10/applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
		PersonService workService =  (PersonService) applicationContext.getBean("personService");
		System.out.println("-----目标对象1---------");
		workService.eat();
		System.out.println("=====分割线=====");
		workService.work();
		System.out.println("=====分割线=====");
		workService.sleep();
		
		
		System.out.println("-----目标对象2---------");
		PersonService workService2 =  (PersonService) applicationContext.getBean("personService2");
		workService2.eat();
		System.out.println("=====分割线=====");
		workService2.work();
		System.out.println("=====分割线=====");
		workService2.sleep();
	}
前者结果,在切入点work()方法都进行增强了

后者可以适用于Advisor 前者不可以,而且还可以指定到某个具体的目标对象方法




(3)基于AspectJ注解实现AOP
@Aspect			//@Aspect注解表示当前类为切面
public class MyAspectJ {
	
	@Before("execution(* *..eat(..) )")
	public void before(){
		System.out.println("AspectJ:====执行前置通知");
	}
	
	@AfterReturning(value="execution(* *..work(..))" ,returning="res")
	public void afterReturning(Object res) {
		res = res.toString().toUpperCase();
		System.out.println("AspectJ:====执行后置通知  返回值:"+res);
	}
	
	@Around("execution(* *..PersonServiceImpl.sleep(..))")
	public Object around(ProceedingJoinPoint procee) throws Throwable{
		System.out.println("AspectJ:====执行环绕通知之前");
		
		Object res = procee.proceed();
		res = res.toString().toUpperCase();
		System.out.println("AspectJ:====执行环绕通知之后"+res);
		
		return res;
	}
	
	@After("execution(* *..PersonServiceImpl.eat(..))")
	public void after(JoinPoint jp){
		System.out.println("AspectJ:====执行最终通知"+jp);
	}
	
	@AfterThrowing(value="execution(* *..PersonServiceImpl.dowrong(..))",throwing="ex")
	public void throwing(Exception ex){
		System.out.println("AspectJ:====执行异常通知"+ex.getMessage());
	}
	
}

配置文件,很简单
	<bean id="myAspectJ" class="aop.aspectj.test1.MyAspectJ"></bean>

	<bean id="personService" class="aop.aspectj.test1.PersonServiceImpl"/>
	<!--启用注解-->
	<aop:aspectj-autoproxy />
测试方法
	public static void main(String[] args) {
		String resouce = "aop/aspectj/test1/applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
		PersonService workService =  (PersonService) applicationContext.getBean("personService");
		System.out.println("-----目标对象1---------");
		workService.eat();
		System.out.println("=====分割线=====");
		workService.work();
		System.out.println("=====分割线=====");
		workService.sleep();
	}
测试结果


(4)基于AspectJ使用XML配置实现
public class MyAspectJ {
	
	public void before(){
		System.out.println("AspectJ:====执行前置通知");
	}
	
	public void before(JoinPoint jp){
		System.out.println("AspectJ:====执行前置通知"+jp);
	}
	
	public void afterReturning(Object res) {
		res = res.toString().toUpperCase();
		System.out.println("AspectJ:====执行后置通知  返回值:"+res);
	}
	
	public Object around(ProceedingJoinPoint procee) throws Throwable{
		System.out.println("AspectJ:====执行环绕通知之前");
		
		Object res = procee.proceed();
		res = res.toString().toUpperCase();
		System.out.println("AspectJ:====执行环绕通知之后"+res);
		
		return res;
	}
	
	public void after(JoinPoint jp){
		System.out.println("AspectJ:====执行最终通知"+jp);
	}
	
	public void throwing(Exception ex){
		System.out.println("AspectJ:====执行异常通知"+ex.getMessage());
	}
	
}
XML配置文件
	<bean id="myAspectJ" class="aop.aspectj.test3.MyAspectJ"></bean>

	<bean id="personService" class="aop.aspectj.test3.PersonServiceImpl"/>
	
	<!--  -->
	<aop:config>
		<!-- 定义切入点 -->
		<aop:pointcut expression="execution(* *..eat(..) )" id="pointCutEat"/>
		<aop:pointcut expression="execution(* *..work(..) )" id="pointCutWork"/>
		<aop:pointcut expression="execution(* *..sleep(..) )" id="pointCutSleep"/>
		<aop:pointcut expression="execution(* *..dowrong(..) )" id="pointCutDowrong"/>
		
		<aop:aspect ref="myAspectJ">
			<aop:before method="before" pointcut-ref="pointCutEat"/>
			<aop:before method="before(org.aspectj.lang.JoinPoint)" pointcut-ref="pointCutEat"/>
			
			<aop:after-returning method="afterReturning(java.lang.Object)" pointcut-ref="pointCutWork" returning="res"/>
			
			<aop:around method="around(org.aspectj.lang.ProceedingJoinPoint)" pointcut-ref="pointCutSleep"/>
			
			<aop:after method="after" pointcut-ref="pointCutEat"/>
			
			<aop:after-throwing method="throwing(java.lang.Exception)" pointcut-ref="pointCutDowrong" throwing="ex"/>
		</aop:aspect>
		
		
	</aop:config>
测试方法
	public static void main(String[] args) {
		String resouce = "aop/aspectj/test3/applicationContext.xml";
		ApplicationContext applicationContext = new ClassPathXmlApplicationContext(resouce);
		PersonService workService =  (PersonService) applicationContext.getBean("personService");
		System.out.println("-----目标对象1---------");
		workService.eat();
		System.out.println("=====分割线=====");
		workService.work();
		System.out.println("=====分割线=====");
		workService.sleep();
	}
测试结果







评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值