开源框架spring AOP的深刻理解

来源:互联网 发布:sql 查询数据库大小 编辑:程序博客网 时间:2024/06/05 01:18

AOP的理解

1、AOP的概述

AOP是一种不同于OOP(面向对象编程)的编程模式,它不是OOP的替代,而是对OOP的一种有益补充。

2、spring AOP的原理

3、spring AOP的实现

在spring2.5中,常用的AOP实现方式有两种。第一种是基于xml配置文件方式的实现,第二种是基于注解方式的实现。

接下来,以具体的是理智讲解这两种方式的使用。

Java代码

    package com.zxf.service;                 /**         * 业务逻辑接口         * @author z_xiaofei168         */        public interface AccountService {             public void save(String loginname, String password);         }                 它的实现类                 package com.zxf.service;         import com.zxf.dao.AccountDao;                 /**         * AccountService的实现类         * @author z_xiaofei168         */        public class AccountServiceImpl implements AccountService {             private  AccountDao accountDao;                          public AccountServiceImpl() {}                          /** 带参数的构造方法 */            public AccountServiceImpl(AccountDao accountDao){                 this.accountDao = accountDao;             }                          public void save(String loginname, String password) {                 accountDao.save(loginname, password);                 throw new RuntimeException("故意抛出一个异常。。。。");             }                          /** set方法 */            public void setAccountDao(AccountDao accountDao) {                 this.accountDao = accountDao;             }         }  

对于业务系统来说,AccountServiceImpl类就是目标实现类,它的业务方法,如save()方法的前后或代码会出现异常的地方都是AOP的连接点。

下面是日志服务类的代码:

Java代码

    package com.zxf.aspect;                 import org.aspectj.lang.JoinPoint;         import org.aspectj.lang.ProceedingJoinPoint;                 /**         * 日志切面类         * @author z_xiaofei168         */        public class LogAspect {                     //任何通知方法都可以将第一个参数定义为 org.aspectj.lang.JoinPoint类型              public void before(JoinPoint call) {                 //获取目标对象对应的类名                 String className = call.getTarget().getClass().getName();                 //获取目标对象上正在执行的方法名                 String methodName = call.getSignature().getName();                                  System.out.println("前置通知:" + className + "类的" + methodName + "方法开始了");             }                          public void afterReturn() {                 System.out.println("后置通知:方法正常结束了");             }                          public void after(){                 System.out.println("最终通知:不管方法有没有正常执行完成,一定会返回的");             }                          public void afterThrowing() {                 System.out.println("异常抛出后通知:方法执行时出异常了");             }                          //用来做环绕通知的方法可以第一个参数定义为org.aspectj.lang.ProceedingJoinPoint类型             public Object doAround(ProceedingJoinPoint call) throws Throwable {                 Object result = null;                 this.before(call);//相当于前置通知                 try {                     result = call.proceed();                     this.afterReturn(); //相当于后置通知                 } catch (Throwable e) {                             this.afterThrowing();  //相当于异常抛出后通知                     throw e;                 }finally{                     this.after();  //相当于最终通知                 }                                  return result;             }         }   

这个类属于业务服务类,如果用AOP的术语来说,它就是一个切面类,它定义了许多通知。Before()、afterReturn()、after()和afterThrowing()这些方法都是通知。

<1>.基于xml配置文件的AOP实现

这种方式在实现AOP时,有4个步骤。

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:aop="http://www.springframework.org/schema/aop"            xsi:schemaLocation="                 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd>            <bean id="accountDaoImpl" class="com.zxf.dao.AccountDaoImpl"/>                 <bean id="accountService" class="com.zxf.service.AccountServiceImpl">            <property name=" accountDaoImpl " ref=" accountDaoImpl "/>        bean>                    <bean id="logAspectBean" class="com.zxf.aspect.LogAspect"/>                         <aop:config>                        <aop:aspect id="logAspect" ref="logAspectBean">                                <aop:pointcut id="allMethod"                      expression="execution(* com.zxf.service.*.*(..))"/>                                                     <aop:before method="before" pointcut-ref="allMethod" />                                <aop:after-returning method="afterReturn" pointcut-ref="allMethod"/>                                <aop:after method="after" pointcut-ref="allMethod"/>                                <aop:after-throwing method="afterThrowing" pointcut-ref="allMethod"/>                                                             aop:aspect>        aop:config>    <beans>    

上述配置针对切入点应用了前置、后置、最终,以及抛出异常后通知。这样在测试执行AccountServiceImpl类的save()方法时,控制台会有如下结果输出。

前置通知:com.zxf.service.AccountServiceImpl类的save方法开始了。

针对MySQL的AccountDao实现中的save()方法。

后置通知:方法正常结束了。

最终通知:不管方法有没有正常执行完成,一定会返回的。

<2>基于注解的AOP的实现

首先创建一个用来作为切面的类LogAnnotationAspect,同时把这个类配置在spring的配置文件中。

在spring2.0以后引入了JDK5.0的注解Annotation的支持,提供了对AspectJ基于注解的切面的支持,从而 更进一步地简化AOP的配置。具体的步骤有两步。

Spring的配置文件是如下的配置:

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:aop="http://www.springframework.org/schema/aop"            xsi:schemaLocation="                 http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.5.xsd                 http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd>            <bean id="accountDao" class="com.zxf.dao.AccountDaoImpl"/>        <bean id="accountService" class="com.zxf.service.AccountServiceImpl">            <property name="accountDao" ref="accountDao"/>        bean>                <bean id="logAspectBean" class="com.zxf.aspect.LogAnnotationAspect"/>                <aop:aspectj-autoproxy/>    <beans>   

这是那个切面的类LogAnnotationAspect

Java代码

    package com.zxf.aspect;                 import org.aspectj.lang.JoinPoint;         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.Aspect;         import org.aspectj.lang.annotation.Before;         import org.aspectj.lang.annotation.Pointcut;                 /**         * 日志切面类         */        @Aspect  //定义切面类         public class LogAnnotationAspect {             @SuppressWarnings("unused")             //定义切入点             @Pointcut("execution(* com.zxf.service.*.*(..))")             private void allMethod(){}                          //针对指定的切入点表达式选择的切入点应用前置通知             @Before("execution(* com. zxf.service.*.*(..))")             public void before(JoinPoint call) {                                  String className = call.getTarget().getClass().getName();                 String methodName = call.getSignature().getName();                                  System.out.println("【注解-前置通知】:" + className + "类的"                          + methodName + "方法开始了");             }             //访问命名切入点来应用后置通知             @AfterReturning("allMethod()")             public void afterReturn() {                 System.out.println("【注解-后置通知】:方法正常结束了");             }                          //应用最终通知             @After("allMethod()")             public void after(){                 System.out.println("【注解-最终通知】:不管方法有没有正常执行完成,"                          + "一定会返回的");             }                          //应用异常抛出后通知             @AfterThrowing("allMethod()")             public void afterThrowing() {                 System.out.println("【注解-异常抛出后通知】:方法执行时出异常了");             }                          //应用周围通知             //@Around("allMethod()")             public Object doAround(ProceedingJoinPoint call) throws Throwable{                 Object result = null;                 this.before(call);//相当于前置通知                 try {                     result = call.proceed();                     this.afterReturn(); //相当于后置通知                 } catch (Throwable e) {                     this.afterThrowing();  //相当于异常抛出后通知                     throw e;                 }finally{                     this.after();  //相当于最终通知                 }                                  return result;             }         }    






0 0