Spring AOP切面编程

动态代理设计

package cn.mldn.service.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ServiceProxy implements InvocationHandler {
	private Object realObject; // 被代理的真实对象
	/**
	 * 进行真实对象的绑定处理,返回一个动态生成的接口类对象
	 * @param realObject 真实主题类
	 * @return 代理类对象
	 */
	public Object bind(Object realObject) {
		this.realObject = realObject;
		return Proxy.newProxyInstance(realObject.getClass().getClassLoader(), realObject.getClass().getInterfaces(),this);
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		if (this.checkTransactionMethod(method.getName())) {	// 执行的业务方法应该是更新处理
			// 开启数据库事务处理
		}
		Object backResult = method.invoke(this.realObject, args) ;	// 调用真实业务 
		try {
			if (this.checkTransactionMethod(method.getName())) {	// 执行的业务方法应该是更新处理
				// 【COMMIT】数据库事务提交
			}
		} catch (Exception e) {
			// 【ROLLBACK】数据库事务回滚
			throw e ;
		}
		return backResult ;
	}
	/**
	 * 检测当前的方法是否需要开启事务控制处理
	 * @param methodName 方法名称
	 * @return 如果需要开启返回true,如果不需要返回false
	 */
	private boolean checkTransactionMethod(String methodName) {
		return methodName.startsWith("add") || methodName.startsWith("edit") || methodName.startsWith("delete") ;
	}
}

AOP基础实现

业务类(切点执行前后的方法都放在这个类里面)

package cn.mldn.mldnspring.advice;

public class ServiceAdvice {		// 该类不需要继承任何父类,独立存在
	public void handleBefore() { 	// 处理前置通知
		System.out.println("【### ServiceAdvice-handleBefore ###】进行业务的前置处理操作。");
	}
	public void handleAfter() { 	// 处理后置操作通知
		System.out.println("【### ServiceAdvice-handleAfter ###】进行业务的后置处理操作。");
	}
}

切点类

package cn.mldn.mldnspring.service.impl;

import org.springframework.stereotype.Service;

import cn.mldn.mldnspring.service.IMessageService;
@Service
public class MessageServiceImpl implements IMessageService {
	@Override
	public String echo(String str) {
		System.out.println("【MessageServiceImpl业务层实现】接收到消息内容:" + str);
		return "【ECHO】msg = " + str;
	}
}

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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<context:component-scan base-package="cn.mldn.mldnspring" />	<!-- 此包下的所有注解自动生效 -->
	<bean id="serviceAdvice" class="cn.mldn.mldnspring.advice.ServiceAdvice"/>	<!-- 通知处理类 -->
	<aop:config>				<!-- 进行AOP的配置处理 -->
		<!-- 配置切入点AspectJ表达式,这个表达式直接决定了最终到底在那里去执行代理操作 -->
		<aop:pointcut id="myPointcut" expression="execution(public * cn.mldn..service..*.*(..))" />
		<aop:aspect ref="serviceAdvice">		<!-- 切入处理操作方法定义,设置程序类名称 -->
			<aop:before method="handleBefore" pointcut-ref="myPointcut"/>	<!-- 引入切入点,该方法在切点执行前执行 -->
			<aop:after method="handleAfter" pointcut-ref="myPointcut"/>		<!-- 引入切入点,该方法在切点执行后执行-->
		</aop:aspect>
	</aop:config>
</beans>

前置通知接收参数
// 前置通知得到的参数和切点类参数一致,共享同一个参数
业务类

package cn.mldn.mldnspring.advice;

public class ServiceAdvice {		// 该类不需要继承任何父类,独立存在
	public void handleBefore(String tempMsg) { 	/****  处理前置通知:: 带参数 *********/
		System.out.println("【### ServiceAdvice-handleBefore ###】进行业务的前置处理操作,参数:" + tempMsg);
	}
	public void handleAfter() { 	// 处理后置操作通知
		System.out.println("【### ServiceAdvice-handleAfter ###】进行业务的后置处理操作。");
	}
}

切点类

package cn.mldn.mldnspring.service.impl;

import org.springframework.stereotype.Service;

import cn.mldn.mldnspring.service.IMessageService;
@Service
public class MessageServiceImpl implements IMessageService {
	@Override
	public String echo(String str) {
		System.out.println("【MessageServiceImpl业务层实现】接收到消息内容:" + str);
		return "【ECHO】msg = " + str;
	}
}

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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<context:component-scan base-package="cn.mldn.mldnspring" />	<!-- 此包下的所有注解自动生效 -->
	<bean id="serviceAdvice" class="cn.mldn.mldnspring.advice.ServiceAdvice"/>	<!-- 通知处理类 -->
	<aop:config>				<!-- 进行AOP的配置处理 -->
		<!-- 配置切入点AspectJ表达式,这个表达式直接决定了最终到底在那里去执行代理操作 -->
		<aop:pointcut id="myPointcut" expression="execution(public * cn.mldn..service..*.*(..))" />
		<aop:aspect ref="serviceAdvice">		<!-- 切入处理操作方法定义,设置程序类名称 -->
			<aop:before method="handleBefore" 
				pointcut="execution(public * cn.mldn..service..*.*(..)) and args(msg)" 
				arg-names="msg"/>				<!-- 定义新的切入点 -->
			<aop:after method="handleAfter" pointcut-ref="myPointcut"/>		<!-- 引入切入点 -->
		</aop:aspect>
	</aop:config>
</beans>

后置通知
后置通知有三种:

  • 后置最终通知
  • 后置返回通知
  • 后置异常通知

// 通知的参数和切点类参数是同一个,共享同一个参数

package cn.mldn.mldnspring.advice;

public class ServiceAdvice {		// 该类不需要继承任何父类,独立存在
	public void handleBefore(String tempMsg) { 	// 处理前置通知
		System.out.println("【### ServiceAdvice-handleBefore ###】进行业务的前置处理操作,参数:" + tempMsg);
	}
	public void handleAfter() { 	// 处理后置操作通知
		System.out.println("【### ServiceAdvice-handleAfter ###】进行业务的后置处理操作。");
	}
	public void handleReturn(String retMsg) { 	// 处理后置操作通知
		System.out.println("【### ServiceAdvice-handleReturn ###】业务方法执行完毕:" + retMsg);
	}
	public void handleThrow(Exception exp) { // 异常处理通知
		System.out.println("【### ServiceAdvice-handleThrow ###】方法执行产生了异常:" + exp);
	}
}

切点类

package cn.mldn.mldnspring.service.impl;

import org.springframework.stereotype.Service;

import cn.mldn.mldnspring.service.IMessageService;
@Service
public class MessageServiceImpl implements IMessageService {
	@Override
	public String echo(String str) {
		if (str == null) {
			throw new RuntimeException("空消息,无法处理!") ;
		}
		System.out.println("【MessageServiceImpl业务层实现】接收到消息内容:" + str);
		return "【ECHO】msg = " + str;
	}
}

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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<context:component-scan base-package="cn.mldn.mldnspring" />	<!-- 此包下的所有注解自动生效 -->
	<bean id="serviceAdvice" class="cn.mldn.mldnspring.advice.ServiceAdvice"/>	<!-- 通知处理类 -->
	<aop:config>				<!-- 进行AOP的配置处理 -->
		<!-- 配置切入点AspectJ表达式,这个表达式直接决定了最终到底在那里去执行代理操作 -->
		<aop:pointcut id="myPointcut" expression="execution(public * cn.mldn..service..*.*(..))" />
		<aop:aspect ref="serviceAdvice">		<!-- 切入处理操作方法定义,设置程序类名称 -->
			<aop:before method="handleBefore" 
				pointcut="execution(public * cn.mldn..service..*.*(..)) and args(msg)" 
				arg-names="msg"/>				<!-- 定义新的切入点 -->
			<aop:after method="handleAfter" pointcut-ref="myPointcut"/>		<!-- 引入切入点 -->
			<!-- 定义后置返回通知,需要将方法的返回数据传递到方法之中 -->
			<aop:after-returning method="handleReturn" pointcut-ref="myPointcut" returning="val" arg-names="val"/>
			<!-- 定义后置异常通知,需要将产生的异常对象传递到方法之中 -->
			<aop:after-throwing method="handleThrow" pointcut-ref="myPointcut" throwing="e" arg-names="e"/>
		</aop:aspect>
	</aop:config>
</beans>

环绕通知
业务类

package cn.mldn.mldnspring.advice;
import java.util.Arrays;
import org.aspectj.lang.ProceedingJoinPoint;

public class ServiceAdvice {		// 该类不需要继承任何父类,独立存在
	public Object handleRound(ProceedingJoinPoint point) throws Throwable {	// 定义一个环绕处理通知
		System.out.println("【A、环绕通知 - handleRound】业务方法调用前。参数:" + Arrays.toString(point.getArgs())) ;
		Object returnValue = null ;	// 表示的是进行方法返回值的接收处理
		try {
			returnValue = point.proceed(new Object[] {"在环绕通知方法中修改了真实参数,现在的参数是假的"}) ;	// 修改了真实的传递参数
		} catch (Exception e) {	// 异常向上继续抛出
			System.out.print("【C、环绕通知 - handleRound】产生异常。异常:" + e) ;
			throw e ;
		}
		System.out.println("【B、环绕通知 - handleRound】业务方法执行完毕。返回值:" + returnValue) ;
		return returnValue ;
	}
}

切点类

package cn.mldn.mldnspring.service.impl;

import org.springframework.stereotype.Service;

import cn.mldn.mldnspring.service.IMessageService;
@Service
public class MessageServiceImpl implements IMessageService {
	@Override
	public String echo(String str) {
		if (str == null) {
			throw new RuntimeException("空消息,无法处理!") ;
		}
		System.out.println("【MessageServiceImpl业务层实现】接收到消息内容:" + str);
		return "【ECHO】msg = " + str;
	}
}

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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<context:component-scan base-package="cn.mldn.mldnspring" />	<!-- 此包下的所有注解自动生效 -->
	<bean id="serviceAdvice" class="cn.mldn.mldnspring.advice.ServiceAdvice"/>	<!-- 通知处理类 -->
	<aop:config>				<!-- 进行AOP的配置处理 -->
		<!-- 配置切入点AspectJ表达式,这个表达式直接决定了最终到底在那里去执行代理操作 -->
		<aop:pointcut id="myPointcut" expression="execution(public * cn.mldn..service..*.*(..))" />
		<aop:aspect ref="serviceAdvice">		<!-- 切入处理操作方法定义,设置程序类名称 -->
			<aop:around method="handleRound" pointcut-ref="myPointcut"/>	<!-- 环绕通知 -->
		</aop:aspect>
	</aop:config>
</beans>

基于Annotation的AOP配置(注解配置)
业务类

package cn.mldn.mldnspring.advice;

import java.util.Arrays;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Component		// Bean注解配置
@Aspect			// 该类为AOP处理类
public class ServiceAdvice {		// 该类不需要继承任何父类,独立存在
	@Before(value="execution(public * cn.mldn..service..*.*(..)) and args(msg)",argNames="msg")
	public void handleBefore(String tempMsg) { 	// 处理前置通知
		System.out.println("前置通知 【### ServiceAdvice-handleBefore ###】进行业务的前置处理操作,参数:" + tempMsg);
	}

	@After(value="execution(public * cn.mldn..service..*.*(..))")
	public void handleAfter() { 	// 处理后置操作通知
		System.out.println("【### ServiceAdvice-handleAfter ###】进行业务的后置处理操作。");
	}

	@AfterReturning(value="execution(public * cn.mldn..service..*.*(..))",argNames="r",returning="r")
	public void handleReturn(String retMsg) { 	// 处理后置操作通知
		System.out.println("后置返回通知  【### ServiceAdvice-handleReturn ###】业务方法执行完毕:" + retMsg);
	}

	@AfterThrowing(value="execution(public * cn.mldn..service..*.*(..))",throwing="e",argNames="e")
	public void handleThrow(Exception exp) { // 异常处理通知
		System.out.println("【### ServiceAdvice-handleThrow ###】方法执行产生了异常:" + exp);
	}

	@Around("execution(public * cn.mldn..service..*.*(..))")
	public Object handleRound(ProceedingJoinPoint point) throws Throwable {	// 定义一个环绕处理通知
		System.out.println("【A、环绕通知 - handleRound】业务方法调用前。参数:" + Arrays.toString(point.getArgs())) ;
		Object returnValue = null ;	// 表示的是进行方法返回值的接收处理
		try {
			returnValue = point.proceed(new Object[] {"假的参数我乐意传"}) ;	// 修改了真实的传递参数
		} catch (Exception e) {	// 异常向上继续抛出
			System.out.println("【C、环绕通知 - handleRound】产生异常。异常:" + e) ;
			throw e ;
		}
		System.out.println("【B、环绕通知 - handleRound】业务方法执行完毕。返回值:" + returnValue) ;
		return returnValue ;
	}
}

切点类

package cn.mldn.mldnspring.service.impl;

import org.springframework.stereotype.Service;

import cn.mldn.mldnspring.service.IMessageService;
@Service
public class MessageServiceImpl implements IMessageService {
	@Override
	public String echo(String str) {
		if (str == null) {
			throw new RuntimeException("空消息,无法处理!") ;
		}
		System.out.println("【MessageServiceImpl业务层实现】接收到消息内容:" + str);
		return "【ECHO】msg = " + str;
	}
}

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:p="http://www.springframework.org/schema/p"
	xmlns:context="http://www.springframework.org/schema/context"
	xmlns:task="http://www.springframework.org/schema/task"
	xmlns:aop="http://www.springframework.org/schema/aop"
	xsi:schemaLocation="http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.3.xsd
		http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
		http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.3.xsd
		http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.3.xsd">
	<context:component-scan base-package="cn.mldn.mldnspring"/>
	<aop:aspectj-autoproxy/> 			<!-- 启用AOP的Annotation支持 -->
</beans>

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值