AOP基于xml配置方式实现

Spring基于xml开发AOP

  •     定义目标类(接口及实现类)
 /**
* 目标类
*/
public interface UserService {
//业务方法
public void getById();
public void add();
public void delete();
public String update();
public void batch();
}
 public class UserServiceImpl implements UserService {
@Override
public void getById() {
System.out.println("UserServiceImpl类的getById方法被调用...");
//抛出异常
System.out.println(1/0);
}
@Override
public void add() {
System.out.println("UserServiceImpl类的add方法被调用...");
}
@Override
public void delete() {
System.out.println("UserServiceImpl类的delete方法被调用...");
// System.out.println(1/0);
}
@Override
public String update() {
System.out.println("UserServiceImpl类的update方法被调用...");
// System.out.println(1/0);
return "update的返回值";
}
@Override
public void batch() {
System.out.println("UserServiceImpl类的batch方法被调用...");
}
}
  •     定义切面类
 /**
* 切面
*/
public class UserAspect {
//前置通知
public void beforeAdvice(JoinPoint jp){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("前置通知切入点的方法的名称:"+name);
System.out.println("前置通知");
} //后置通知
public void afterAdvice(JoinPoint jp){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("后置通知切入点的方法的名称:"+name);
System.out.println("后置通知");
} //返回通知
//可以获取object类型的返回值
//注意:result名称必须和配置文件中的returning的名称保持一致
public void afterReturningAdvice(JoinPoint jp,Object result){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("返回通知切入点的方法的名称:"+name);
//打印返回值
System.out.println(result);
System.out.println("返回通知");
} //异常通知
public void exceptionAdvice(JoinPoint jp,Exception ex){
//获取切入点的方法的名称
String name = jp.getSignature().getName();
System.out.println("异常通知切入点的方法的名称:"+name);
//打印异常信息
System.out.println(ex.getMessage());
System.out.println("异常通知");
} //环绕通知
//必须有一个参数:ProceedingJoinPoint
//有返回值:Object
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知前");
//执行业务逻辑方法
Object result = pjp.proceed();
//获取切入点的方法的名称
String name = pjp.getSignature().getName();
System.out.println("环绕通知切入点的方法的名称:"+name);
System.out.println("环绕通知后");
return result;
}
}
  •     配置spring核心配置文件
<?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:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<!-- 把切面和业务对象放到容器中 -->
<bean id="userAspect" class="spring.aop.xml.UserAspect"></bean>
<bean id="userServiceImpl" class="spring.aop.xml.UserServiceImpl"></bean> <!-- 配置aop的实现 -->
<aop:config>
<!--
切入点的配置
expression(切入点表达式):指定切哪个方法
-->
<aop:pointcut expression="execution(* *.add*(..))" id="pointCut01"/>
<aop:pointcut expression="execution(* *.delete*(..))" id="pointCut02"/>
<aop:pointcut expression="execution(* *.update*(..))" id="pointCut03"/>
<aop:pointcut expression="execution(* *.getById*(..))" id="pointCut04"/>
<aop:pointcut expression="execution(* *.batch*(..))" id="pointCut05"/> <!-- 切面的配置 -->
<aop:aspect ref="userAspect">
<!--
前置通知的配置:在pointCut01切入点的位置添加beforeAdvice的通知
-->
<aop:before method="beforeAdvice" pointcut-ref="pointCut01"/> <!--
后置通知的配置:在pointCut02切入点的位置添加afterAdvice的通知
-->
<aop:after method="afterAdvice" pointcut-ref="pointCut02"/> <!--
返回通知的配置:在pointCut03切入点的位置添加afterReturningAdvice的通知
returning:返回值的参数名称
-->
<aop:after-returning method="afterReturningAdvice" pointcut-ref="pointCut03" returning="result"/> <!--
异常通知的配置:在pointCut04切入点的位置添加exceptionAdvice的通知
throwing:抛出异常的名称,必须和通知上的形参名称一致
-->
<aop:after-throwing method="exceptionAdvice" pointcut-ref="pointCut04" throwing="ex"/> <!--
环绕通知的配置:在pointCut05切入点的位置添加aroundAdvice的通知
-->
<aop:around method="aroundAdvice" pointcut-ref="pointCut05"/>
</aop:aspect>
</aop:config>
</beans>
  •     测试
 //使用xml方式配置AOP
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop-xml.xml")
public class XmlAopTest {
//注入业务对象
@Autowired
private UserService userService; //测试AOP,对切入点进行增强
@Test
public void test(){
//前置通知的测试
// userService.add(); //后置通知的测试(无论有没有异常都会执行)
// userService.delete(); //返回通知的测试(只有业务方法正常执行时,才会执行的通知)
// userService.update(); //异常通知的测试
// userService.getById(); //环绕通知的测试
userService.batch();
}
}

    

AOP的切入点表达式execution

    表达式的写法:修饰关键词   返回值类型   包名.类名.方法名(..)

修饰关键词:protected ,  public  ,  private ….一般都省略不写

返回值类型:一般返回值类型用 * 号代替,表示任意的返回值都可以

方法名中的两个点:表示所带的参数的个数。

        举例如下:

  任意以public修饰的方法都可以

execution(public * *(..))

  任何以set开头的方法都可以

execution(* set*(..))

  任何在AccountService 这个接口下面的方法都可以

execution(* com.xyz.service.AccountService.*(..))

  任何在com.xyz.service 这个包下面的所有类的所有方法都可以

execution(* com.xyz.service.*.*(..))

  任何在com.xyz.service 这个包以及整个包下面的所有子包的所有类的所有方法都可以

execution(* com.xyz.service..*.*(..))

  ..代表这个包及这个包下面的所有子包

Spring中的5种通知类型及参数

      •   前置通知:在目标方法开始之前进行执行的通知

            参数:JoinPoint

      •   后置通知:在目标方法执行之后,无论是否发生异常,都进行执行的通知

            参数:JoinPoint

      •   返回通知:在目标方法正常结束时,才执行的通知

            参数:JoinPoint,Object

      •   异常通知:在目标方法出现异常时才会进行执行的通知

            参数:JoinPoint,Exception

      •   环绕通知:在目标方法执行之前、 之后都会执行的通知

            参数:ProceedingJoinPoint(必须有)



AOP基于注解方式的实现

xml配置中开启spring注解扫描及开启aop注解的自动代理

    

<?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:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-4.2.xsd">
<!-- 开启spring的注解驱动 -->
<context:component-scan base-package="spring.aop.annotation"></context:component-scan> <!-- 开启aop的自动代理:使用注解实现AOP,这个必须配置 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

    定义接口及接口实现类

    

 此处省略,同xml配置方式相同

    通过注解的方式定义切面类

 /**
* 切面
*/
@Component
@Aspect
public class UserAspect {
//前置通知
@Before(value = "execution(* *.add*(..))")
public void beforeAdvice(JoinPoint jp){
String name = jp.getSignature().getName();
System.out.println("前置通知的切入点的方法名:" + name);
System.out.println("前置通知...");
} //后置通知
@After(value = "execution(* *.delete*(..))")
public void afterAdvice(JoinPoint jp){
String name = jp.getSignature().getName();
System.out.println("后置通知的切入点的方法名:" + name);
System.out.println("后置通知...");
} //返回通知
@AfterReturning(value = "execution(* *.update*(..))",returning="result")
public void afterReturningAdvice(JoinPoint jp,Object result){
String name = jp.getSignature().getName();
System.out.println("返回通知的切入点的方法名:" + name);
System.out.println(result);
System.out.println("返回通知...");
} //异常通知
@AfterThrowing(value = "execution(* *.getById*(..))",throwing="ex")
public void exceptionAdvice(JoinPoint jp,Exception ex){
String name = jp.getSignature().getName();
System.out.println("异常通知的切入点的方法名:" + name);
System.out.println(ex.getMessage());
System.out.println("异常通知...");
} //环绕通知
@Around(value = "execution(* *.batch*(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("环绕通知前...");
Object result = pjp.proceed();
String name = pjp.getSignature().getName();
System.out.println("环绕通知的切入点的方法名:" + name);
System.out.println("环绕通知后...");
return result;
}
}

    测试

 /**
* 注解形式的AOP的单元测试类
*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext-aop-annotation.xml")
public class AnnotationAopTest {
@Autowired
private UserService userService; @Test
public void test(){
//注解:前置通知的测试
// userService.add(); //后置通知的测试
// userService.delete(); //返回通知
// userService.update(); //异常通知
// userService.getById(); //环绕通知
userService.batch();
}
}


最新文章

  1. hdu 1272 小希的迷宫
  2. JSON-SCHEMA
  3. 《javascript高级程序设计》第四章 Variables,scope,and memory
  4. PHP数组的操作
  5. HDU4763 - Theme Section(KMP)
  6. IOS开发之UINavigationBar
  7. Silverlight 图表下载到Excel文件中
  8. httpClient download file(爬虫)
  9. 双11电商剁手节,最全的H5互动营销案例合集
  10. linux系统光盘开机自动挂载-配置本地yum源
  11. ethereum/EIPs-191 Signed Data Standard
  12. CentOS7 搭建LVS+keepalived负载均衡
  13. Kubernetes学习之路(二十三)之资源指标和集群监控
  14. 移动option标签
  15. sam9260 adc module
  16. python nose测试框架全面介绍三
  17. codeforces 782B - The Meeting Place Cannot Be Changed
  18. HDU--4768
  19. type=&quot;submit&quot;表单提交理解
  20. 程序入口函数和glibc及C++全局构造和析构

热门文章

  1. P2257 YY的GCD (莫比乌斯反演)
  2. 更改npm默认路径
  3. 什么是javascript的中间件?
  4. hdu2588 GCD
  5. 什么是RFID? 射频识别技术的特点及工作原理!
  6. 如何写一个简单的webserver(一):最简实现
  7. linux 登陆失败处理
  8. 代码重构----使用java有限状态机来消除太多的if else判断
  9. The Java serialization algorithm revealed---reference
  10. jgrid 选择器 C#控件