软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
移动开发 架构设计 编程语言 Web前端 互联网
开发杂谈 系统运维 研发管理 数据库 云计算 Android开发资料
  软件世界网 -> 架构设计 -> 6.springAOP -> 正文阅读

[架构设计]6.springAOP


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>
    这个配置文件的意思如下图:

[img]http://img.blog.csdn.net/20160331164935402
一旦调用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
获取切入点的信息,切入点所在类:com.example.aop.Login@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的切面编程(可以把一个类做一个切面,向里面添加接口),这些以后慢慢来吧。

......显示全文...
    点击查看全文


上一篇文章      下一篇文章      查看所有文章
2016-04-01 16:50:07  
架构设计 最新文章
Opengl教程之读取obj并绘制在picturecontro
读《企业应用架构模式》第五章并发
StepbyStepintoSpring(IOC)
设计模式(2)用例图之一
使用实体组件系统(ECS)开发”吃方块”游戏实
编程学习之简单工厂模式与策略模式
Invalidprojectdescription.
基于Redis实现分布式消息队列(2)
《开源框架那点事儿15》:借船下海还是造船
原型模式——浅复制和深复制
360图书馆 软件开发资料 文字转语音 购物精选 软件下载 美食菜谱 新闻资讯 电影视频 小游戏 Chinese Culture 股票 租车
生肖星座 三丰软件 视频 开发 短信 中国文化 网文精选 搜图网 美图 阅读网 多播 租车 短信 看图 日历 万年历 2018年1日历
2018-1-16 21:08:46
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --