资讯专栏INFORMATION COLUMN

Spring AOP 入门

CodeSheep / 3263人阅读

摘要:一以及术语是的简称,被译为面向切面编程。切面由切点和增强组成,他包括了连接点定义和横切逻辑代码的定义,就是负责实施切面的框架。五使用来定义纯粹的切面使用方法也非常简单,使用的标签。采用动态代理和动态代理技术在运行期间织入。

引言

AOP是软件开发思想发展到一定阶段的产物,AOP的出现并不是为了代替OOP,仅作为OOP的有益补充,在下面的例子中这个概念将会得到印证。AOP的应用场合是受限制的,一般适用于那些具有横切逻辑的应用场合,例如性能监测,访问控制,事务管理,日志记录。在平常的应用开发中AOP很难被使用到,但是AOP是Spring的亮点之一,有必要一看。

一 AOP以及术语

AOP是Aspect Oriented Programing的简称,被译为面向切面编程。AOP希望将散落在业务逻辑函数中的相同代码抽取到一个独立的模块中。举个例子:

class A{
    public void run()
    {
        doSomething();
        doAthings();
        doOtherthing();
    }
}
 
class B{
    public void run()
    {
         doSomething();
         doBthings();
         doOtherthing();
    }
}
 
class C{
    public void run()
    {
        doSomething();
        doCthings();
        doOtherthing();
        doMorethings();
    }
}

例如上述三个类中的run方法,都有doSomething和doOtherthing代码,AOP就是要把这些代码抽取出来。我们知道,抽取代码很容易,但是如何将这些独立的逻辑代码再融合到业务类中完成和原来一样的业务操作,这才是AOP要解决的问题。

术语

Joinpoint连接点:程序执行的某个特定位置,例如类初始化前,类初始化后,方法执行前,方法执行后等,Spring只支持方法的连接点,即方法执行前,方法执行后,方法抛出异常时。
Pointcut切点:每个类中都拥有多个连接点,如拥有两个方法的类,这两个方法都是连接点,切点可以在连接点中定位一个或多个连接点。

Advice增强(通知):增强是织入目标类连接点上的一段程序代码,即当程序到达一个执行点后会执行相对应的一段代码,Spring提供的Advice都带有接入点方位,例如BeforeAdvice,AftereturningAdvice,ThrowsAdvice等。只有结合切点和通知才能确定特定的连接点并执行对应代码。
Target目标对象:被嵌入代码的类。
Introductiony引介:可以为类添加属性和方法。
Weaving织入:AOP就像一台织布机,将Advice代码嵌入到对应的类中。
Proxy代理:一个类被AOP织入后,就会产生一个代理对象,他融合了原有类代码和Advice代码。
Aspect切面:由切点和增强组成,他包括了连接点定义和横切逻辑代码的定义,SpringAOP就是负责实施切面的框架。

AOP有三种织入方式:

编译期织入:这要求是用特殊的Java编译器

类装载期织入:要求使用特殊的类装载器
动态代理织入:在运行时期为目标对象生成代理对象的方式实现织入

Spring采用动态代理织入,AspectJ采用编译期织入和类装载织入。
二 Advice增强(通知)
Spring使用Advice类定义横切逻辑,Advice类还包括了在方法的哪一点加入代码的信息。

Advice类型:

前置增强:在方法执行前实施增强org.apringframework.aop.MethodBeforeAdvice
后置增强:在方法返回后实施增强org.springframework.aop.AfterReturningAdvice
异常抛出增强:在目标方法抛出异常后实施增强org.springframework.aop.ThrowsAdvice
环绕增强:在方法执行前和执行后实施增强org.aopaliance.intercept.MethodInterceptor
引介增强:在目标类中加入新的方法和属性org.springframework.aop.IntroductionInterceptor

这是典型的基于代理的AOP,使用方法如下

1 创建一个接口,并且实现它

2 创建Advice,实现上述任意接口
3 使用ProxyFactory来生成代理

接下来,我以简单的示例解释前四种Advice

//Dog.java
//定义狗的接口
package test.aop;
/**
 * Created by gavin on 15-7-18.
 */
public interface Dog {
    public void shout(String name);
    public void sleep(String name);
}
 
//ChinaDog.java
//设计中华田园犬
package test.aop;
/**
 * Created by gavin on 15-7-18.
 */
public class ChinaDog implements Dog {
    @Override
    public void shout(String name) {
        System.out.println("中华田园犬"+name+" 叫了一声");
    }
    @Override
    public void sleep(String name) {
        System.out.println("中华田园犬"+name+" 睡着了");
    }
    public void error() throws Exception {
        throw new Exception("shout exception");
    }
}
 
//BeforeAdvice.java
//前置增强类
package test.aop;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
/**
 * Created by gavin on 15-7-18.
 */
public class BeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        String name = (String)objects[0];    //参数获取
        System.out.println("中华田园犬"+name+" 前置增强");
    }
}
 
//AfterReturnAdvice.java
//后置增强类
package test.aop;
import org.springframework.aop.AfterReturningAdvice;
import java.lang.reflect.Method;
/**
 * Created by gavin on 15-7-18.
 */
public class AfterReturnAdvice implements AfterReturningAdvice {
    @Override
    public void afterReturning(Object o, Method method, Object[] objects, Object o1) throws Throwable {
        String name = (String)objects[0];
        System.out.println("中华田园犬"+name+" 后置增强");
    }
}
 
//SurroundAdvice.java
//环绕增强类
package test.aop;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
/**
 * Created by gavin on 15-7-18.
 */
public class SurroundAdvice implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        Object[] objects = methodInvocation.getArguments();
        String name = (String)objects[0];
        System.out.println("环绕增强----前"+name);
 
        Object object = methodInvocation.proceed();    //此处执行的是原有函数
 
        System.out.println("环绕增强----后"+name);
 
        return object;
    }
}
 
//ThrowAdvice.java
//异常抛出增强类
package test.aop;
import org.springframework.aop.ThrowsAdvice;
import java.lang.reflect.Method;
/**
 * Created by gavin on 15-7-18.
 */
public class ThrowAdvice implements ThrowsAdvice {
    @Override
    public void afterThrowing(Method method,Object[] args, Object obj ,Exception ex)throws Throwable
    {
        System.out.println("------------------------");
        System.out.println("------异常抛出增强");
        System.out.println("------method "+method.getName());
        System.out.println("------exception "+ex.getMessage());
        System.out.println("------------------------");
    }
}
 
//AopTest.java
//AOP测试类
package test.aop;
import org.aopalliance.aop.Advice;
import org.springframework.aop.framework.ProxyFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.FileSystemXmlApplicationContext;
import org.testng.annotations.BeforeTest;
import org.testng.annotations.Test;
/**
 * Created by gavin on 15-7-18.
 */
public class AopTest {
    private Dog dog;
    private Advice advice;
    private ProxyFactory pf;
 
 
    @BeforeTest
    public void init()
    {
        dog = new ChinaDog();
        pf = new ProxyFactory();
        pf.setTarget(dog);
    }
 
    @Test
    public void beforeAdvice()
    {
        advice = new BeforeAdvice();
        pf.addAdvice(advice);
        Dog dog = (Dog)pf.getProxy();
        dog.shout("jim");
        dog.sleep("tom");
    }
 
    @Test
    public void afterReturndvice()
    {
        advice = new AfterReturnAdvice();
        pf.addAdvice(advice);
        Dog dog = (Dog)pf.getProxy();
        dog.shout("jim");
        dog.sleep("tom");
    }
 
    @Test
    public void arroundAdvice()
    {
        SurroundAdvice advice = new SurroundAdvice();
        pf.addAdvice(advice);
        Dog dog = (Dog)pf.getProxy();
        dog.shout("jim");
        dog.sleep("tom");
    }
 
    @Test
    public void throwAdvice()
    {
        advice = new ThrowAdvice();
        pf.addAdvice(advice);
        ChinaDog dog = (ChinaDog)pf.getProxy();
        try {
            dog.error();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

分别对前四种增强方式进行测试,得到以下结果:
前置增强

后置增强

环绕增强

异常抛出增强

三 创建切面

Spring通过org.springframework.aop.Pointcut接口描述切点,通过这个接口的ClassFilter定位到特定的类,通过MethodMatcher定位到特定的方法。

切面的创建方法

1 添加目标对象
2 添加Advice
3 定义切点Pointcut
4 定义Advisor
5 设置代理对象

在第二节的基础上,在applicationContext.xml中设置如下




 








 


       



       
       



       
       
              
                     
                     test.aop.Dog
              
       
       
       
              
                     sleepHelperAdvisor
              
       
       
       

在AopTest.java中调用进行测试:

public static void main(String[] args)
{
    //PropertyConfigurator.configure("web/WEB-INF/log4j.properties");
    ApplicationContext ac = new FileSystemXmlApplicationContext("web/WEB-INF/applicationContext.xml");
    Dog dog = (Dog)ac.getBean("proxyFactoryBean");//注意这里,调用的是代理bean,返回的是Dog的代理对象
    dog.shout("jim");
    dog.sleep("tom");
}

结果为:

至于前置Advice为什么出现了三次我也不懂,如果有人了解的话,请赐教。
四 基于@AspectJ配置切面

我们先用@AspectJ定义一个切面:

package test.aop;
 
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
 
/**
 * Created by gavin on 15-7-18.
 */
@Aspect
public class PreAspect {
    @Before("execution(* shout(..))")//意思是返回值任意 参数任意
    public void beforeShout()
    {
        System.out.println("准备叫");
    }
}

在applicationContext.xml中设置:


 



加入的内容有:
xmlns:aop="http://www.springframework.org/schema/aop

http://www.springframework.or... http://www.springframework.org/schema/aop/spring-aop-3.1.xsd

在AopTest.java中进行测试,代码如下:

public static void main(String[] args)
{
    ApplicationContext ac = new FileSystemXmlApplicationContext("web/WEB-INF/applicationContext.xml");
    Dog dog = (Dog)ac.getBean("chinaDog");    //注意这里调用的是chinaDog
    dog.shout("jim");
    dog.sleep("tom");
}

结果为:

只有shout方法前调用了beforeShout方法,与我们设想的相同。

五 使用Spring来定义纯粹的POJO切面

使用方法也非常简单,使用spring的aop标签。xml如下:





       
              
       

java代码如下

public static void main(String[] args)
{
    ApplicationContext ac = new FileSystemXmlApplicationContext("web/WEB-INF/applicationContext.xml");
    Dog dog = (Dog)ac.getBean("chinaDog");//注意这里调用的是chinaDog
    dog.shout("jim");
    dog.sleep("tom");
}

最终效果和@AspectJ相同

总结

AOP是OOP的有益补充,他为程序开发提供了一个新的思考角度,可以将重复性的横切逻辑抽取到统一的模块中。只有通过OOP的纵向抽象和AOP的横向抽取,程序才可以真正的解决重复性代码问题。

Spring采用JDK动态代理和CGLib动态代理技术在运行期间织入Advice。所以用户不用装备特殊的编译器或类装载器。要使用JDK动态代理,目标对象必须实现接口,而CGLib不对目标类采取限制。

JDK创建代理对象效率比CGLib高,而CGLib创建的代理对象运行效率比JDK的要高。

Spring实现AOP的三种方式:
经典代理@AspectJPOJO

更多文章:http://blog.gavinzh.com

文章版权归作者所有,未经允许请勿转载,若此文章存在违规行为,您可以联系管理员删除。

转载请注明本文地址:https://www.ucloud.cn/yun/64411.html

相关文章

  • 慕课网_《Spring入门篇》学习总结

    摘要:入门篇学习总结时间年月日星期三说明本文部分内容均来自慕课网。主要的功能是日志记录,性能统计,安全控制,事务处理,异常处理等等。 《Spring入门篇》学习总结 时间:2017年1月18日星期三说明:本文部分内容均来自慕课网。@慕课网:http://www.imooc.com教学示例源码:https://github.com/zccodere/s...个人学习源码:https://git...

    Ververica 评论0 收藏0
  • Spring入门IOC和AOP学习笔记

    摘要:入门和学习笔记概述框架的核心有两个容器作为超级大工厂,负责管理创建所有的对象,这些对象被称为。中的一些术语切面切面组织多个,放在切面中定义。 Spring入门IOC和AOP学习笔记 概述 Spring框架的核心有两个: Spring容器作为超级大工厂,负责管理、创建所有的Java对象,这些Java对象被称为Bean。 Spring容器管理容器中Bean之间的依赖关系,使用一种叫做依赖...

    wenyiweb 评论0 收藏0
  • spring 入门 2 自动装配和aop

    摘要:使用注解配置一步骤为主配置文件引入新的命名空间约束导入约束开启使用注解代理配置文件在中指定扫描包下所有类的注解扫描时会扫描指定包下的所有子孙包在类中使用注解完成配置等二将对象注册到容器将注册到容器中,相当于层层层三修改对象的作用范 使用注解配置spring 一、步骤 1.为主配置文件引入新的命名空间(约束) 导入spring-context-4.2.xsd schema约束 show...

    JasinYip 评论0 收藏0
  • spring 入门 3 整合JDBC和AOP事务

    摘要:整合提供了很多模板整合技术持久化技术模板类中提供了一个可以操作数据库的对象对象封装了技术模板对象与中的非常相似准备连接池创建模板对象书写并执行步骤导包基础包类库新增连接池驱动包包事务包准备数据库本地数据库和表书写使用模板实现增删改查 spring整合JDBC spring提供了很多模板整合Dao技术 ORM持久化技术 模板类 JDBC o...

    CHENGKANG 评论0 收藏0
  • Spring笔记03_AOP

    摘要:介绍什么是在软件业,为的缩写,意为面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。切面是切入点和通知引介的结合。切面类权限校验。。。 1. AOP 1.1 AOP介绍 1.1.1 什么是AOP 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术...

    blair 评论0 收藏0

发表评论

0条评论

CodeSheep

|高级讲师

TA的文章

阅读更多
最新活动
阅读需要支付1元查看
<