6.spring AOP

6.1 aop的概念

       6.1.1
    aop里面切面、切点的定义什么的我就不说,网上多如牛毛,我就记录一下自己对aop概念和流程的理解吧。
    spring里的切面编程,浅显的讲就是你在调用某个方法的时候,程序会自动先执行某个方法,执行完你调用的方法之后再又自动的执行某个方法。
这样就完成了一次切面编程,其实过程很简单。
    假设我们调用了A类里面的方法a,这时候程序会在执行a之前去调用B类里面的方法b,执行完a之后会去调用B类里面的d,我们用这个例子来看看aop里面的概念。这里的方法a就是一个pointcut(切入点),而b和d就是连个advice(通知),a是前置通知,b是后置通知。还有一个很重要的aspect(切面概念)是什么呢,我觉得是切入点和通知的整体,如下图,这整个是一个aspect 。

    6.1.2 前后置的advice
    现在的网站都能够统计在线的人数,这个是怎么做的呢?真实的项目中是怎么做的我不知道,但是我觉得用spring-aop可以很好的做到这个功能。
    首先需要一个登陆的类(里面有登陆和登出的方法,先只用登陆的):
public interface ILogin {
    void login(User user);
    void logout(User user);
}
    实现类:
public class Login implements ILogin{
    public void login(User user){
        System.out.println(user.getName()+"登陆");
    }
    public void logout(User user){
        System.out.println(user.getName()+"登出");
    }
}
    还需要一个用来做切面的类,number用来统计登陆人数。
public class Count {
    static int number = 0;
    public void beforeuserlogin(){
        number++;
        System.out.println("当前在线人数:"+number);
    }
    public void afteruserlogin(){
        System.out.println("login end");
    }
}
    配置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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="login" class="com.example.aop.Login"/>
        <bean id="count" class="com.example.aop.Count"/>

        <aop:config>
            <aop:aspect id="logaspect" ref="count"> <!-- 我把这个ref理解为切面的制造者,就是拥有advice的类 -->
                <aop:pointcut id="loginpointcut" expression="execution(* com.example.aop.ILogin.login(..))"/>
                <aop:before method="beforeuserlogin" pointcut-ref="loginpointcut"/>
                <aop:after method="afteruserlogin" pointcut-ref="loginpointcut"/>
            </aop:aspect>
        </aop:config>

</beans>
    这个配置文件的意思如下图:

一旦调用login方法,就会执行前后置的advice,就能完成人数统计了。

测试代码:

ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
ILogin login = (ILogin) app.getBean("login");
User user = new User();
user.setName("mj");
login.login(user);
User user1 = new User();
user1.setName("lili");
login.login(user1);
    结果:
当前在线人数:1
mj登陆
login end
当前在线人数:2
lili登陆
login end
    6.1.3 around advice
    能统计登陆的人数,当然还得能统计登出的人数了,不然人数不是一直在增长了。现在使用一种新的advice-----around advice
    使用这个advice可以同时实现前后置advice。
    我们在Count里面增加方法aroundlogout作为around advice。(这里的ProceedingJoinPoint指的就是定义的切入点,
joinPoint.proceed()这个就是执行切入点函数)
public Object aroundlogout(ProceedingJoinPoint joinPoint){
    System.out.println("logout start");
    Object object = null;
    try {
        object = joinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    number--;
    System.out.println("logout end");
    System.out.println("当前在线人数:"+number);
    return object;
}
    修改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/aop http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/beans
         http://www.springframework.org/schema/beans/spring-beans.xsd">
        <bean id="login" class="com.example.aop.Login"/>
        <bean id="count" class="com.example.aop.Count"/>

        <aop:config>
            <aop:aspect id="logaspect" ref="count"> <!-- 我把这个ref理解为切面的制造者,就是拥有advice的类 -->
                <aop:pointcut id="loginpointcut" expression="execution(* com.example.aop.ILogin.login(..))"/>
                <aop:before method="beforeuserlogin" pointcut-ref="loginpointcut"/>
                <aop:after method="afteruserlogin" pointcut-ref="loginpointcut"/>
                <aop:around method="aroundlogout" pointcut="execution(* com.example.aop.ILogin.logout(..))"/>
                <!-- 上面这一句等于下面这两句的综合 -->
                <!--<aop:pointcut id="logoutpointcut" expression="execution(* com.example.aop.ILogin.logout(..))"/>-->
                <!--<aop:around method="aroundlogout" pointcut-ref="logoutpointcut"/>-->
            </aop:aspect>
        </aop:config>
</beans>
    测试代码:
ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
ILogin login = (ILogin) app.getBean("login");
User user = new User();
user.setName("mj");
login.login(user);
User user1 = new User();
user1.setName("lili");
login.login(user1);
login.logout(user);
    结果:
当前在线人数:1
mj登陆
login end
当前在线人数:2
lili登陆
login end
logout start
mj登出
logout end
当前在线人数:1
    6.1.4   afterreturn advice
    这个advice是在切入点函数执行完之后执行,它可以获取到切入点函数的返回值,用来对返回值进行一定的格式化等,afterreturn advice在after advice之后执行。为了看看它的效果,修改logout接口,让它返回一个StringBuffer(本来想用String来演示的,但是发现String演示不了,如果logout函数返回一个String的话,不能被afterreturn advice改变,我想这个和String变量在java中的特殊性有关):
public class Login implements ILogin{
    public void login(User user){
        System.out.println(user.getName()+"登陆");
    }
    public StringBuffer logout(User user){
        System.out.println(user.getName()+"登出");
        return new StringBuffer("logout");
    }
}
    修改Count,增加一个方法,它会接收切入点返回的值,然后修改:
public void afterReturn(StringBuffer s){
    s.append(" after return");
}
    xml文件,就是加入了一个after-returning的配置(returning后面跟afterReturn函数的入参名称):
<aop:config>
    <aop:aspect id="logaspect" ref="count"> <!-- 我把这个ref理解为切面的制造者,就是拥有advice的类 -->
        <aop:pointcut id="loginpointcut" expression="execution(* com.example.aop.ILogin.login(..))"/>
        <aop:before method="beforeuserlogin" pointcut-ref="loginpointcut"/>
        <aop:after method="afteruserlogin" pointcut-ref="loginpointcut"/>
        <aop:around method="aroundlogout" pointcut="execution(* com.example.aop.ILogin.logout(..))"/>
        <!-- 上面这一句等于下面这两句的综合 -->
        <!--<aop:pointcut id="logoutpointcut" expression="execution(* com.example.aop.ILogin.logout(..))"/>-->
        <!--<aop:around method="aroundlogout" pointcut-ref="logoutpointcut"/>-->
        <aop:after-returning method="afterReturn" returning="s" pointcut="execution(* com.example.aop.ILogin.logout(..))"/>
    </aop:aspect>
</aop:config>
    测试代码:
ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
ILogin login = (ILogin) app.getBean("login");
User user = new User();
user.setName("mj");
login.login(user);
User user1 = new User();
user1.setName("lili");
login.login(user1);
System.out.println(login.logout(user));
    从代码上看最后一行是不是应该输出 logout ?
结果:
当前在线人数:1
mj登陆
login end
当前在线人数:2
lili登陆
login end
logout start
mj登出
logout end
当前在线人数:1
logout after return
    6.2 在通知函数里面获取参数
        注意,这里的参数似乎只能是切入点函数的参数或者切入点所在的那个类
        6.2.1  利用JoinPoint类进行传参
            在上面的例子中我们用到了ProceedingJoinPoint这个类,这是个JoinPoint的子类,利用它我们就可以获取切入点相关的信息,我们修改aroundlogout这个函数,在里面获取切入点的信息(其它都不变)
public Object aroundlogout(ProceedingJoinPoint joinPoint){
    System.out.println("logout start");
    System.out.println("获取切入点的信息,切入点所在类:"+joinPoint.getThis());
    Object object = null;
    try {
        object = joinPoint.proceed();
    } catch (Throwable throwable) {
        throwable.printStackTrace();
    }
    number--;
    System.out.println("logout end");
    System.out.println("当前在线人数:"+number);
    return object;
}
    结果:
当前在线人数:1
mj登陆
login end
当前在线人数:2
lili登陆
login end
logout start
获取切入点的信息,切入点所在类:[email protected]470f1802
mj登出
logout end
当前在线人数:1
logout after return
    我们如果想要用JoinPoint进行传参的话,只要把advice函数的第一个参数设置为JoinPoint就可以了,必须是第一个参数!
比如我们修改beforelogin:
public void beforeuserlogin(JoinPoint joinPoint){
    number++;
    System.out.println("获取切入点的信息,切入点所在类:"+joinPoint.getThis());
    System.out.println("当前在线人数:"+number);
}

修改测试代码:

ApplicationContext app = new ClassPathXmlApplicationContext("spring-main.xml");
ILogin login = (ILogin) app.getBean("login");
User user = new User();
user.setName("mj");
login.login(user);

结果:

获取切入点的信息,切入点所在类:com.example.aop.Login@470f1802
当前在线人数:1
mj登陆
login end
JoinPoint还提供了很多方法,可以自己试验一下。
    6.2.2  利用配置文件传参
        假设我们在afteruserlogin这个函数里面要用到切入点login的参数user,我们可以用joinpoint提供的getArgs方法,也可以利用配置文件单独的将user传入到afteruserlogin。
   修改afteruserlogin:
public void afteruserlogin(User user){
    System.out.println(user.getName()+"  login end");
}
    修改xml:
<aop:after method="afteruserlogin" pointcut="execution(* com.example.aop.ILogin.login(..)) and args(user)"/>
    运行6.2.1中的测试代码:
获取切入点的信息,切入点所在类:com.example.aop.Login@3e92efc3
当前在线人数:1
mj登陆
mj  login end
    (如果参数很多也没问题,在args里面用“,”隔开就行了。)
end:
    spring还提供了AspectJ 形式的切面编程,用的都是注解的形式,还提供了一种名为Introductions的切面编程(可以把一个类做一个切面,向里面添加接口),这些以后慢慢来吧。
时间: 2024-10-10 16:26:40

6.spring AOP的相关文章

Spring框架之Spring AOP

一.基于注解管理的AOP 1.Spring配置文件 <!-- 配置自动扫描包,自动扫描Bean组件,切面类 --> <context:component-scan base-package="com.zhoujian.spring.anno,com.zhoujian.spring.test"> <!-- <context:include-filter type="annotation" expression="org.a

Spring AOP中pointcut expression表达式解析 及匹配多个条件

Pointcut 是指那些方法需要被执行"AOP",是由"Pointcut Expression"来描述的. Pointcut可以有下列方式来定义或者通过&& || 和!的方式进行组合. args() @args() execution() this() target() @target() within() @within() @annotation 其中 execution 是用的最多的,其格式为: execution(modifiers-pat

spring aop 原理

http://blog.csdn.net/moreevan/article/details/11977115 Spring AOP 实现原理 2013-09-24 15:23 79554人阅读 评论(11) 收藏 举报  分类: spring(2)  版权声明:本文为博主原创文章,未经博主允许不得转载. 目录(?)[+] 什么是AOP AOP(Aspect-OrientedProgramming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)

Spring AOP进行日志记录

在java开发中日志的管理有很多种.我一般会使用过滤器,或者是Spring的拦截器进行日志的处理.如果是用过滤器比较简单,只要对所有的.do提交进行拦截,然后获取action的提交路径就可以获取对每个方法的调用.然后进行日志记录.使用过滤器的好处是可以自己选择性的对某一些方法进行过滤,记录日志.但是实现起来有点麻烦. 另外一种就是使用Spring的AOP了.这种方式实现起来非常简单,只要配置一下配置文件就可以了.可是这种方式会拦截下所有的对action的每个操作.使得效率比较低.不过想做详细日志

spring AOP和通知

1.  spring的通知 1.1.  AOP的概念 切面(Aspect):一个关注点的模块化,这个关注点可能会横切多个对象.事务管理是J2EE应用中一个关于横切关注点的很好的例子.在Spring AOP中,切面可以使用基于模式或者基于注解的方式来实现. 连接点(Joinpoint):在程序执行过程中某个特定的点,比如某方法调用的时候或者处理异常的时候.在Spring AOP中,一个连接点总是表示一个方法的执行. 通知(Advice):在切面的某个特定的连接点上执行的动作.其中包括了"aroun

spring aop 整理

aop常见概念 1.切面 事务.日志.安全性框架.权限等都是切面(就是类,事务有事务类,日志有日志类,权限有权限类) 2.通知 切面中的方法就是通知(类中针对目标方法所要插入的方法,即事务类中执行事务的方法,日志类中执行日志操作的方法) 3.目标类 (你想要侵入修改的方法所在的类,诸如我们想在查询存款时加入一些其他操作,存款管理类就是目标类) 4.切入点 只有符合切入点,才能让通知和目标方法结合在一起 (就是你想要加强的方法,就是查看工资的方法showSalary()) 5.织入: 形成代理对象

JavaEE学习之Spring aop

一.基本概念 AOP——Aspect-Oriented Programming,面向切面编程,它是spring框架的一个重要组成部分.一般的业务逻辑都有先后关系,我们可以理解为纵向关系,而AOP关注的是横向关系,每一个关注点可以理解为一个横切面.例如我们的大部分代码都会涉及到日志记录,很多的数据库操作都会涉及到事务的创建和提交.那么从横向关注这些逻辑,他们都一个个的切面. AOP技术的具体实现,可以通过动态代理技术或者是在程序编译期间进行静态的"织入"方式.AOP经常使用的场景包括:日

Spring AOP详解(转载)

此前对于AOP的使用仅限于声明式事务,除此之外在实际开发中也没有遇到过与之相关的问题.最近项目中遇到了以下几点需求,仔细思考之后,觉得采用AOP 来解决.一方面是为了以更加灵活的方式来解决问题,另一方面是借此机会深入学习Spring AOP相关的内容.本文是权当本人的自己AOP学习笔记,以下需求不用AOP肯定也能解决,至于是否牵强附会,仁者见仁智者见智. 对部分函数的调用进行日志记录,用于观察特定问题在运行过程中的函数调用情况 监控部分重要函数,若抛出指定的异常,需要以短信或邮件方式通知相关人员

Spring AOP 之 通知、连接点、切点、切面。

1:知识背景 软件系统可以看成是由一组关注点组成的,其中,直接的业务关注点,是直切关注点.而为直切关注点提供服务的,就是横切关注点. 2:面向切面的基本原理 什么是面向切面编程 横切关注点:影响应用多处的功能(安全.事务.日志) 切面: 横切关注点被模块化为特殊的类,这些类称为切面 优点: 每个关注点现在都集中于一处,而不是分散到多处代码中 服务模块更简洁,服务模块只需关注核心代码. AOP 术语 通知: 定义:切面也需要完成工作.在 AOP 术语中,切面的工作被称为通知. 工作内容:通知定义了

深入理解Spring AOP之基本概念

深入理解Spring AOP之基本概念 AOP到底是什么 Spring AOP和IOC是听到的关于Spring最频繁的两个词了.现在来重点关注AOP这个词,IOC先放一边,下面这段话摘自Spring优势中关于面向切面的介绍: 面向切面--Spring提供了面向切面编程的丰富支持,允许通过分离应用的业务逻辑与系统级服务(例如审计(auditing)和事务(transaction)管理)进行内聚性的开发.应用对象只实现它们应该做的--完成业务逻辑--仅此而已.它们并不负责(甚至是意识)其它的系统级关