软件世界网 购物 网址 三丰软件 | 小说 美女秀 图库大全 游戏 笑话 | 下载 开发知识库 新闻 开发 图片素材
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
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
生肖星座 三丰软件 视频 开发 Android开发 站长 古典小说 网文精选 搜图网 美图 中国文化英文版 多播 租车 短信
2017-7-26 10:40:57
多播视频美女直播
↓电视,电影,美女直播,迅雷资源↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  软件世界网 --