Spring框架之AOP简析

面向切面编程(AOP)是一种设计思想,是把应用软件分成两个部分:核心关注点和横切关注点

在没有使用到AOP框架的时候我们经常会产生大量的重复的代码,尤其是在事务处理、日志记录等方面。由于这些经常是相同并且重复使用的代码,我们可以使用AOP框架将技术问题实现代码和业务处理(如日志)的实现代码分离,降低了两种代码的耦合性,利于代码的维护和重用。

我们大致上可以这样理解AOP:面向对象编程(OOP)的思想主要处理的是对象间从上到下的关系,那么AOP就是一种从左到右横切的一种关系。比如说,我们现在有好几种业务流程从上到下,但是每种流程都包含了部分的日志处理,那么我们就可以将日志处理看做是一个切面,一个横切所有流程的切面,因为在每个流程的执行过程中,遇到需要进行日志记录的部分都会转去进行日志处理,这就是一个切面。

首先看一下这样几个概念:

  • 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象
  • 连接点(Joinpoint):程序执行过程中的某个特定的点
  • 通知(Advice):在切面的某个特定的连接点上执行的动作
  • 切入点(Pointcut):匹配连接点的断言,在AOP中通知和一个切入点表达式关联
  • 引入(Introduction):在不修改类代码的前提下,为类添加新的属性和方法
  • 目标对象(Target Object):被一个或者多个切面所通知的对象
  • AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(aspect contract)(包括通知方法执行等功能)
  • 织入(Weaving):把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象,分为:编译时织入,类加载时织入,执行时织入

这里通过一个小的例子实现AOP的工作过程,以日志记录为例,模仿数据库的操作,同时生成日志。具体如下:

首先是业务逻辑接口IStudentDao:

public interface IStudentDao {
    public boolean save(String stuNumber, String stuName);
    public boolean update(String stuNumber, String stuName);
    public boolean delete(String stuNumber);
}

业务逻辑实现类StudentDaoImp:

public class StudentDaoImpl implements IStudentDao {

    public boolean delete(String stuNumber) {
        System.out.println("执行delete!");
        System.out.println("delete" + stuNumber + " 完成");
        return true;
    }

    public boolean save(String stuNumber, String stuName) {
        System.out.println("执行save!");
        System.out.println("save" + stuNumber + ", save" + stuName);
        return true;
    }

    public boolean update(String stuNumber, String stuName) {
        System.out.println("ִupdate!");
        System.out.println("update" + stuNumber + ", " + stuName);
        return true;
    }

}

创建日志功能类,在实际被调用的方法执行完成之后,执行该类的方法LogAfterReturningAdvice.java:

import java.lang.reflect.Method;
import java.text.DateFormat;
import java.util.Date;

import org.springframework.aop.AfterReturningAdvice;

public class LogAfterReturningAdvice implements AfterReturningAdvice {

    public void afterReturning(Object returnValue, Method targetMethod, Object[] methodArgs,
            Object targetClass) throws Throwable {
        boolean success = ((Boolean)returnValue).booleanValue();
        if(success){
            String className = targetClass.getClass().getName();
            String methodName = targetMethod.getName();
            Date date = new Date();
            String curTime = DateFormat.getDateTimeInstance().format(date);

            String logInfo = "[" + curTime + "]" + className + "." + methodName + "() 方法被调用";
            System.out.println(logInfo + "LogAfterReturningAdvice");
        }
    }
}

然后创建配置文件,将业务代码和日志功能代码组装在一起aop-config.xml

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE beans PUBLIC  "-//SPRING//DTD BEAN//EN"
          "http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
    <bean id="studentPointcut" class="com.chinasei.spring.aop.StudentDaoImpl" />
    <bean id="logAfterReturningAdvice" class="com.chinasei.spring.aop.LogAfterReturningAdvice" />
     <bean id="studentAdvisor" class="org.springframework.aop.framework.ProxyFactoryBean">
        <property name="proxyInterfaces">
            <value>com.chinasei.spring.aop.IStudentDao</value>
        </property>

        <property name="interceptorNames">
            <list><value>regexAdvisor</value></list>
        </property>

        <property name="target" ref="studentPointcut" />

    </bean>
</beans>

对于上面的配置文件前面的两个bean用来定义业务处理逻辑和日志功能,其中id=studentPointcut的Bean是要代理的目标类。最后一个Bean是用来组装业务处理代码和日志功能代码的bean是使用ProxyFactoryBean类的实例(创建代理类的类)。

然后创建一个测试类SpringAOPTest

package com.chinasei.spring.aop;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringAOPTest {
    public static void main(String[] args){
        ApplicationContext context = new ClassPathXmlApplicationContext("aop-config.xml");
        IStudentDao student = (IStudentDao)context.getBean("studentAdvisor");
        student.save("1234561", "张三");
        student.update("1234561", "李四");
        student.delete("1234561");
    }
}

执行结果如下:
执行结果

发现在每次执行完成逻辑操作之后都会进行日志的处理。

上面的整个流程可以这样解释,首先通过ClassPathXmlApplicationContext类加载配置文件,生成上下文应用关系,然后通过applicationContext获取Bean,获取的Bean的id指向为studentAdvisor,这时,ProxyFactoryBean就会根据子元素的属性创建代理类,子元素中包含了3个标签,分别是proxyInterfaces,是要代理的类的接口,interceptorNames是要完成日志功能的类,即就是一系列的拦截器,可以认为是要通知执行的方法,最后一个子元素属性为target是实现业务处理的类。

代理类创建完成之后就如同在studentDaoImpl类中的方法上,添加了通知,在该类中的方法执行完成返回之后就会执行logAfterReturningAdvice类中的方法。

这一篇只是简单通过一个例子大致将AOP的流程串起来,具体的知识还有好多,比如Advice、Pointcut和Advisor,以及使用ProxyFactoryBean创建AOP代理,这些部分都包含了很多的内容,还需要更加深入的学习!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值