动态代理设计
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>