对于aop的配置方式 我在网上搜了好多 自己整理了一下 (不对请指正 )
aop的两种配置方式
第一种:通过定义aspectj切面类实现
第二种:通过通知器Advisor实现
这两种方式都能实现aop功能, 但是 advisor通常是实现Spring的声明式事务(我不知道怎么通过apectJ来实现aop事务!!)
aspectJ是实现aop开发的 (有些人把aop分为两种方式 一种是基于XML配置的AspectJ 一种是基于注解版的AspectJ 我不理解 我感觉Advisor通知器也应该算aop的一种实现方式)
aspectJ和Advisor的异同点:aspectJ把切面直接封装到了一个类中 而Advisor是通过组装拼接的方式形成的切面
aspectJ的通知是方法 但是 Advisor的通知是类 (通知类实现了相应的Method*Advice接口的实现)
废话不多说 直接代码演示吧!!!!!
第一种是基于Advisor实现Spring的AOP配置
--(关于AspectJ的事务配置不太了解)
<!-- 事务控制器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="*" propagation="REQUIRED" isolation="DEFAULT" read-only="false"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="pointPut" expression="execution(* com.xc.service.*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pointPut"/>
</aop:config>
<tx:method>属性值
#isolation:用于指定事务的隔离级别。默认值是DEFAULT,表示使用数据库的默认隔离级别。
#propagation:用于指定事务的传播行为。默认值是REQUIRED,表示一定会有事务,增删改的选择。查询方法可以选择SUPPORTS。
#read-only:用于指定事务是否只读。只有查询方法才能设置为true。默认值是false,表示读写。
#timeout:用于指定事务的超时时间,默认值是-1,表示永不超时。如果指定了数值,以秒为单位。
#rollback-for:用于指定一个异常,当产生该异常时,事务回滚,产生其他异常时,事务不回滚。没有默认值。表示任何异常都回滚。
#no-rollback-for:用于指定一个异常,当产生该异常时,事务不回滚,产生其他异常时事务回滚。没有默认值。表示任何异常都回滚
代码测试 测试Spring框架对事务的支持
无AOP事务
数据库初始值
在未开启aop事务时执行转账操作
转账业务
程序报错 (除0错误) 查看数据库数据,无事务 ,数据出错
有AOP事务
还原数据库数据
放开AOP事务配置
执行程序,程序报错 查看数据库 (数据库数据没有发生变化 )
第二种基于Advisor实现AOP
# 第一步:需要注册通知类 通知类必须实现Method**Advice接口 我测试采用MethodBeforeAdvice接口
@Component
public class Before implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
System.out.println("哈哈哈哈");
}
}
#第二步:在xml配置文件中组装AOP的通知器 (我用过自动扫描加载Before对象,不过没设置自动扫描 请用bean标签注册before类)
<!--基于advisor通知其实现AOP功能-->
<aop:config>
<aop:pointcut id="pc1" expression="execution(* com.xc.service.impl.*.*(..))"/>
<aop:advisor advice-ref="before" pointcut-ref="pc1"/>
</aop:config>
代码测试:
首先注释掉AOP配置信息
测试程序跑完 无AOP功能
放开AOP配置
测试显示 AOP功能实现(哈哈哈哈就是对功能增强 通过advisor配置也可以实现前置通知 后置通知 环绕通知 只不过需要多注册几个通知类 实现不同的接口)
3:基于AspectJ的AOP配置
--除了环绕通知需要参数ProceedingJoinPoint pjp 别的通知可加可不加 JoinPoint是切入点
1 第一步 需要配置切面类 AspectJ
public class MyAspect {
/**
* 前置通知:目标方法调用之前执行的代码
* @param jp
*/
public void doBefore(JoinPoint jp){
System.out.println("===========执行前置通知============");
}
/**
* 后置返回通知:目标方法正常结束后执行的代码
* 返回通知是可以访问到目标方法的返回值的
* @param jp
* @param result
*/
public void doAfterReturning(JoinPoint jp,String result){
System.out.println("===========执行后置通知============");
System.out.println("返回值result==================="+result);
}
/**
* 最终通知:目标方法调用之后执行的代码(无论目标方法是否出现异常均执行)
* 因为方法可能会出现异常,所以不能返回方法的返回值
* @param jp
*/
public void doAfter(JoinPoint jp){
System.out.println("===========执行最终通知============");
}
/**
*
* 异常通知:目标方法抛出异常时执行的代码
* 可以访问到异常对象
* @param jp
* @param ex
*/
public void doAfterThrowing(JoinPoint jp,Exception ex){
System.out.println("===========执行异常通知============");
}
/**
* 环绕通知:目标方法调用前后执行的代码,可以在方法调用前后完成自定义的行为。
* 包围一个连接点(join point)的通知。它会在切入点方法执行前执行同时方法结束也会执行对应的部分。
* 主要是调用proceed()方法来执行切入点方法,来作为环绕通知前后方法的分水岭。
*
* 环绕通知类似于动态代理的全过程:ProceedingJoinPoint类型的参数可以决定是否执行目标方法。
* 而且环绕通知必须有返回值,返回值即为目标方法的返回值
* @param pjp
* @return
* @throws Throwable
*/
public Object doAround(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("======执行环绕通知开始=========");
// 调用方法的参数
Object[] args = pjp.getArgs();
// 调用的方法名
String method = pjp.getSignature().getName();
// 获取目标对象
Object target = pjp.getTarget();
// 执行完方法的返回值
// 调用proceed()方法,就会触发切入点方法执行
Object result=pjp.proceed();
System.out.println("输出,方法名:" + method + ";目标对象:" + target + ";返回值:" + result);
System.out.println("======执行环绕通知结束=========");
return result;
}
}
第二步:在spring配置文件配置
<!--基于XML配置的AspectJ的AOP -->
<bean id="myAspect" class="com.xc.aspect.MyAspect"></bean>
<aop:config>
<aop:aspect ref="myAspect">
<aop:pointcut id="pointcut" expression="execution(* com.xc.service.impl.*.*(..))"/>
<aop:before method="doBefore" pointcut-ref="pointcut"/>
<aop:after-returning method="doAfterReturning" pointcut-ref="pointcut" returning="result"/>
<aop:after method="doAfter" pointcut-ref="pointcut" />
<aop:around method="doAround" pointcut-ref="pointcut"/>
<aop:after-throwing method="doAfterThrowing" pointcut-ref="pointcut" throwing="ex"/>
</aop:aspect>
</aop:config>
代码测试
首先注释掉AOP的配置信息
测试显示 无AOP功能
放开AOP
测试显示 AOP功能实现
第四种 AspectJ注解实现AOP
第一步:定义AnnotationAspectJ类 (通过注解配置)
@Aspect
public class AnnotationAspectJ {
/**
* 必须为final String类型的,注解里要使用的变量只能是静态常量类型的
*/
public static final String EDP = "execution(* com.xc.service.impl.*.*(..))";
/**
* 切面的前置方法 即方法执行前拦截到的方法
* 在目标方法执行之前的通知
*
* @param jp
*/
@Before(EDP)
public void doBefore(JoinPoint jp) {
System.out.println("=========执行前置通知==========");
}
/**
* 在方法正常执行通过之后执行的通知叫做返回通知
* 可以返回到方法的返回值 在注解后加入returning
*
* @param jp
* @param result
*/
@AfterReturning(value = EDP, returning = "result")
public void doAfterReturning(JoinPoint jp, String result) {
System.out.println("===========执行后置通知============");
}
/**
* 最终通知:目标方法调用之后执行的通知(无论目标方法是否出现异常均执行)
*
* @param jp
*/
@After(value = EDP)
public void doAfter(JoinPoint jp) {
System.out.println("===========执行最终通知============");
}
/**
* 环绕通知:目标方法调用前后执行的通知,可以在方法调用前后完成自定义的行为。
*
* @param pjp
* @return
* @throws Throwable
*/
@Around(EDP)
public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("======执行环绕通知开始=========");
// 调用方法的参数
Object[] args = pjp.getArgs();
// 调用的方法名
String method = pjp.getSignature().getName();
// 获取目标对象
Object target = pjp.getTarget();
// 执行完方法的返回值
// 调用proceed()方法,就会触发切入点方法执行
Object result = pjp.proceed();
System.out.println("输出,方法名:" + method + ";目标对象:" + target + ";返回值:" + result);
System.out.println("======执行环绕通知结束=========");
return result;
}
/**
* 在目标方法非正常执行完成, 抛出异常的时候会走此方法
*
* @param jp
* @param ex
*/
@AfterThrowing(value = EDP, throwing = "ex")
public void doAfterThrowing(JoinPoint jp, Exception ex) {
System.out.println("===========执行异常通知============");
}
}
第二步 :spring配置文件
<!--基于注解版的AspectJ 实现AOP-->
<!--开启spring对AspectJ的AOP注解支持 -->
<aop:aspectj-autoproxy/>
<!--注册Aspectj对象 -->
<bean class="com.xc.aspect.AnnotationAspectJ"/>
代码测试
干掉配置文件AOP配置
代码测试 无AOP功能
放开Spring配置
测试代码 测试结果如下