开源框架spring详解-----AOP的深刻理解

开源框架spring详解-----AOP的深刻理解

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"/>  
      
    <!-- 第1步: AOP的配置 -->  
    <aop:config>  
        <!-- 第2步:配置一个切面 -->  
        <aop:aspect id="logAspect" ref="logAspectBean">  
            <!-- 第3步:定义切入点,指定切入点表达式 -->  
            <aop:pointcut id="allMethod"   
                expression="execution(* com.zxf.service.*.*(..))"/>  
                  
            <!-- 第4步:应用前置通知 -->  
            <aop:before method="before" pointcut-ref="allMethod" />  
            <!-- 第4步:应用后置通知 -->  
            <aop:after-returning method="afterReturn" pointcut-ref="allMethod"/>  
            <!-- 第4步:应用最终通知 -->  
            <aop:after method="after" pointcut-ref="allMethod"/>  
            <!-- 第4步:应用抛出异常后通知 -->  
            <aop:after-throwing method="afterThrowing" pointcut-ref="allMethod"/>  
              
            <!-- 第4步:应用环绕通知 -->  
            <!--  
            <aop:around method="doAround" 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>  
    <!-- 把切面类交由Spring容器来管理 -->  
    <bean id="logAspectBean" class="com.zxf.aspect.LogAnnotationAspect"/>  
    <!-- 启用spring对AspectJ注解的支持 -->  
    <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;  
    }  
}  

猜你喜欢

转载自xiaoshanjnby.iteye.com/blog/1919336