AOP(Aspect Oriented Programming)
面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。AOP是OOP的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。
AOP的三种实现方式
1.基于代理的AOP
定义接口、实现类和通知类,在xml文件中进行配置
<bean id="orderServiceTargetBean" class="com.apesource.service.impl.OrderServiceImpl"/><bean id="logAdviceBean" class="com.apesource.service.advice.LogAdvice"/>
<bean id="orderServiceBean" class="org.springframework.aop.framework.ProxyFactoryBean"> <property name="proxyInterfaces">
<value> com.apesource.service.IOrderService</value> </property>
<property name="target"> <ref bean="orderServiceTargetBean"/> </property> <property name="interceptorNames">
<value>logAdviceBean</value> </property>
</bean>
<bean id="userServiceBean" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="proxyInterfaces">
<value> com.apesource.service.IUserService</value> </property>
<property name="target"> <ref bean="userServiceTargetBean"/> </property> <property name="interceptorNames"> <value>logAdviceBean</value> </property></bean>
public void afterReturning(Object result, Method method, Object[] objects, Object target) throws Throwable {
System.out.println("后置通知开始----------->");
System.out.println("返回值" + result);
System.out.println("目标对象" + target);
System.out.println("目标方法" + method.getName());
System.out.println("参数" + Arrays.toString(objects));
System.out.println("【日志】" + target + "的" + method.getName() + "方法于" + new Date() + "被执行");
System.out.println("后置通知结束<-----------");
}
2.自定义类实现AOP
<bean id="orderServiceBean" class="com.apesource.service.impl.OrderServiceImpl"/>
<bean id="logAspectBean" class="com.apesource.service.advice.LogAspect"/>
<aop:config>
<aop:aspect ref="logAspectBean">
<aop:pointcut id="serviceMethodPointcut" expression="execution(* com.apesource.service.impl..create(..) )"/>
<aop:before method="doBefore" pointcut-ref="serviceMethodPointcut"/> <aop:after-returning returning="returnVal" method="afterReturningAdvice" pointcut-ref="serviceMethodPointcut"/>
<aop:after method="afterAdvice" pointcut-ref="serviceMethodPointcut"/> <aop:after-throwing throwing="ex" method="throwingAdvice" pointcut-ref="serviceMethodPointcut"/>
<aop:around method="aroundAdvice" pointcut-ref="serviceMethodPointcut"/> </aop:aspect>
</aop:config>
public void doBefore(JoinPoint joinPoint){
System.out.println("使用【AspectJ】开始实现前置通知..."); System.out.println("目标对象" + joinPoint.getTarget());
System.out.println("目标方法" + joinPoint.getSignature().getName()); System.out.println("参数列表" + joinPoint.getArgs());
System.out.println("使用【AspectJ】实现前置通知结束..."); }
/** * 后置通知:方法正常执行后,有返回值,执行该后置通知;如果该方法执行出现异常,则不执行该后置通知 /
public void afterReturningAdvice(JoinPoint joinpoint,Object returnVal){ System.out.println("==========【使用AspectJ实现后置通知】开始=================="); System.out.println("目标对象:" + joinpoint.getTarget()); System.out.println("目标方法:" + joinpoint.getSignature().getName()); System.out.println("参数列表:" + joinpoint.getArgs()); System.out.println("返回值:" + returnVal);
System.out.println("==========【使用AspectJ实现后置通知】结束=================="); }
/* * 后置通知 /
public void afterAdvice(JoinPoint joinpoint){ System.out.println("==========【使用AspectJ实现后置通知】开始=================="); System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("参数列表:" + joinpoint.getArgs());
System.out.println("==========【使用AspectJ实现后置通知】结束=================="); }
/* * 异常通知:方法出现异常时,执行该通知 * @param joinpoint * @param ex / public void throwingAdvice(JoinPoint joinpoint,Exception ex){ System.out.println("==========【使用AspectJ实现异常通知】开始=================="); System.out.println("目标对象:" + joinpoint.getTarget()); System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("出现异常:" + ex.getMessage());
System.out.println("==========【使用AspectJ实现异常通知】结束=================="); }
/* * 环绕通知 */
public Object aroundAdvice(ProceedingJoinPoint joinpoint) throws Throwable { System.out.println("########################");
Object returnVal = joinpoint.proceed();
System.out.println("########################");
return returnVal; }}
3.使用@Aspect注解
在配置文件中配置自动扫描的包
<context:component-scan base-package="com.atguigu.spring.aop">
加入使 AspjectJ 注解起作用的配置
aop:aspectj-autoproxy/aop:aspectj-autoproxy
为匹配的类自动生成动态代理对象.
<?xml version="1.0" encoding="UTF-8"?><beans xmlns="http://www.springframework.org/schema/beans" xmlns:context="http://www.springframework.org/schema/context" xmlns:aop="http://www.springframework.org/schema/aop" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 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 http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.apesource"/>
<aop:aspectj-autoproxy/></beans>
@Component
@Aspect
public class LogAnotationAspect {
private static final String POINTCUT_EXPRESSION = "execution(* com.apesource.service.impl..create(..) )";
@Before(POINTCUT_EXPRESSION)
public void doBefore(JoinPoint joinPoint){
System.out.println("使用【AspectJ】开始实现前置通知...");
System.out.println("目标对象" + joinPoint.getTarget());
System.out.println("目标方法" + joinPoint.getSignature().getName());
System.out.println("参数列表" + joinPoint.getArgs());
System.out.println("使用【AspectJ】实现前置通知结束...");
}
/**
* 后置通知:方法正常执行后,有返回值,执行该后置通知;如果该方法执行出现异常,则不执行该后置通知
*/
@AfterReturning(value =POINTCUT_EXPRESSION,returning ="returnVal")
public void afterReturningAdvice(JoinPoint joinpoint,Object returnVal){
System.out.println("==========【使用AspectJ实现后置通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("参数列表:" + joinpoint.getArgs());
System.out.println("返回值:" + returnVal);
System.out.println("==========【使用AspectJ实现后置通知】结束==================");
}
/**
* 后置通知
*/
@After(POINTCUT_EXPRESSION)
public void afterAdvice(JoinPoint joinpoint){
System.out.println("==========【使用AspectJ实现后置通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("参数列表:" + joinpoint.getArgs());
System.out.println("==========【使用AspectJ实现后置通知】结束==================");
}
/**
* 异常通知:方法出现异常时,执行该通知
* @param joinpoint
* @param ex
*/
@AfterThrowing(value = POINTCUT_EXPRESSION,throwing = "ex")
public void throwingAdvice(JoinPoint joinpoint,Exception ex){
System.out.println("==========【使用AspectJ实现异常通知】开始==================");
System.out.println("目标对象:" + joinpoint.getTarget());
System.out.println("目标方法:" + joinpoint.getSignature().getName());
System.out.println("出现异常:" + ex.getMessage());
System.out.println("==========【使用AspectJ实现异常通知】结束==================");
}
/**
* 环绕通知
*/
@Around(POINTCUT_EXPRESSION)
public Object aroundAdvice(ProceedingJoinPoint joinpoint) throws Throwable {
System.out.println("#########$环绕通知的前置部分$###############");
Object returnVal = joinpoint.proceed();
System.out.println("#########$环绕通知的后置部分$###############");
return returnVal;
}
}