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

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

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;     
    }     
}  
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

 

对于业务系统来说,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;     
    }     
}   
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.

 

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

#p#

<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>    
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.

 

 

 

上述配置针对切入点应用了前置、后置、最终,以及抛出异常后通知。这样在测试执行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>   
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.

 

 

这是那个切面的类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;     
    }     
}    
  • 1.
  • 2.
  • 3.
  • 4.
  • 5.
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
  • 11.
  • 12.
  • 13.
  • 14.
  • 15.
  • 16.
  • 17.
  • 18.
  • 19.
  • 20.
  • 21.
  • 22.
  • 23.
  • 24.
  • 25.
  • 26.
  • 27.
  • 28.
  • 29.
  • 30.
  • 31.
  • 32.
  • 33.
  • 34.
  • 35.
  • 36.
  • 37.
  • 38.
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46.
  • 47.
  • 48.
  • 49.
  • 50.
  • 51.
  • 52.
  • 53.
  • 54.
  • 55.
  • 56.
  • 57.
  • 58.
  • 59.
  • 60.
  • 61.
  • 62.
  • 63.
  • 64.
  • 65.
  • 66.
  • 67.
  • 68.

 

备注:输出结果和前面的一样。

【编辑推荐】

  1. Spring Hibernate简单讨论
  2. OSGi与Spring:设置Spring DM开发环境
  3. 使用Spring DM创建Hello World,以及OSGi服务
  4. Spring MVC总结:善用注解,生活更轻松
  5. 概括spring hibernate集成

责任编辑:金贺 来源: ITEYE博客
相关推荐

2017-01-13 08:52:46

HDFS机制Then

2024-06-24 08:31:42

2012-12-31 14:59:58

Android开发Layout_weig

2024-05-21 08:44:43

MySQLB+Tree内存

2011-04-18 19:36:10

HSRP协议

2011-03-14 13:11:07

Oracle数据库

2020-09-20 22:14:14

编程PythonJava

2010-08-02 10:11:51

DB2数据库编目

2016-11-03 08:57:02

javascriptjquerynode.js

2022-12-04 09:19:25

JAVA并发有序性

2012-06-21 10:00:25

团队合作程序员

2022-06-07 07:58:45

SpringSpring AOP

2009-09-29 10:00:40

Spring AOP框

2022-06-08 08:04:28

Springservicerepository

2021-05-06 18:17:52

SpringAOP理解

2011-09-15 10:15:30

Spring

2022-04-26 08:41:54

JDK动态代理方法

2023-07-03 07:39:43

Spring框架设计模式

2019-05-10 10:50:04

Spring AOPJDK动态代理CGLIB动态代理

2015-05-06 10:05:22

javajava框架spring aop
点赞
收藏

51CTO技术栈公众号