zoukankan      html  css  js  c++  java
  • spring框架学习(三)——AOP( 面向切面编程)

    AOP 即 Aspect Oriented Program 面向切面编程
      首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能
        所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务
        所谓的周边功能,比如性能统计,日志,事务管理等等

      周边功能在Spring的面向切面编程AOP思想里,即被定义为切面

      在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发
      然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP

    原理图

      1. 功能分两大类,辅助功能和核心业务功能
      2. 辅助功能和核心业务功能彼此独立进行开发
      3. 比如登陆功能,即便是没有性能统计和日志输出,也可以正常运行
      4. 如果有需要,就把"日志输出" 功能和 "登陆" 功能 编织在一起,这样登陆的时候,就可以看到日志输出了
      5. 辅助功能,又叫做切面,这种能够选择性的,低耦合的把切面和核心业务功能结合在一起的编程思想,就叫做切面编程

             

    准备业务类 ProductService

     1 package com.how2java.service;
     2  
     3 public class ProductService {
     4      
     5     public void doSomeService(){
     6          
     7         System.out.println("doSomeService");
     8          
     9     }
    10      
    11 }

    准备一个测试类 TestSpring

    package com.how2java.test;
     
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
     
    import com.how2java.service.ProductService;
     
    public class TestSpring {
     
        public static void main(String[] args) {
            ApplicationContext context = new ClassPathXmlApplicationContext(new String[] { "springconfig.xml" });
            ProductService s = (ProductService) context.getBean("s");
            s.doSomeService();
        }
    }

    准备一个日志切面LoggerAspect

    package com.how2java.aspect;
    import org.aspectj.lang.ProceedingJoinPoint;
     
    public class LoggerAspect {
     
        public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("start log:" + joinPoint.getSignature().getName());
            Object object = joinPoint.proceed();
            System.out.println("end log:" + joinPoint.getSignature().getName());
            return object;
        }
    }

    设置配置文件springconfig.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/beans 
                    http://www.springframework.org/schema/beans/spring-beans.xsd
                    http://www.springframework.org/schema/aop
                    http://www.springframework.org/schema/aop/spring-aop.xsd"> <!--声明业务对象-->
    <bean name="s" class="com.how2java.service.ProductService"/>
    <!--声明日志切面-->
    <bean id="loggerAspect" class="com.how2java.aspect.LoggerAspect"/>
       <!--aop配置过程-->
    <aop:config>
    <aop:pointcut id="loggerCutpoint"
    expression
    ="execution(* com.how2java.service.ProductService.*(..)) "/>
    <aop:aspect id="logAspect" ref="loggerAspect">
    <aop:around pointcut-ref="loggerCutpoint" method="log"/>
    </aop:aspect>
    </aop:config>
    </beans>

    aop配置过程每一步的含义解释: 

    <aop:pointcut id="loggerCutpoint" expression="execution(* com.how2java.service.ProductService.*(..)) "/> 

    这一句是声明切点,切点的 id 叫 loggerCutPoint ,用来标记这个切入点,这个expression表示:满足expression中的方法调用之后,就会去进行切面操作,类似于触发了切面:

      1. 第一个 * 代表返回任意类型:可以是void,int,string。。。。具体可根据调用的方法的返回类型决定

      2. com.how2java.service.ProductService.*(..) :表示包名为 com.how2java.service下的ProductService 类的任意方法  ( 这里的通配符 * 表示任意方法,(..)表示方法的参数是任意数量和类型 )

    简单说就是,只要com.how2java.service这个包中的ProductService类的任意一个函数被调用,不管你的返回值是什么,都会触发开关,我就会去执行切面,也就是辅助功能。针对ProductService类中只有doSomeService()一个函数方法,* com.how2java.service.ProductService.*(..)也可以写成 void com.how2java.service.ProductService.doSomeService()。但是辅助功能是什么呢,就是下面三句:

    <aop:aspect id="logAspect" ref="loggerAspect">
      <aop:around pointcut-ref="loggerCutpoint" method="log"/>
    </aop:aspect>

    这三句是定义了一个切面,上面说只要触发开关,就会去执行切面,就是指的这里的切面,所谓切面,就是一个类中的方法而已,在本案例中就是指  loggerAspect类中的log()方法,id="logAspect"  表示切面的id,ref="loggerAspect"指明切面所属的类,pointcut-ref="loggerCutpoint" 指明触发切面的切点id,method="log" 指明执行切面时所用的方法名。

    测试类运行的结果如下

    ------------------------------------------------------

    需要注意的是,一个切点也可以设置多个切面,我们重新创建了两个loggerAspect2和loggerAspect3,如下

    配置文件改为

    <?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/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
        
       <bean name="s" class="com.how2java.service.ProductService"/> <bean id="loggerAspect2" class="com.how2java.aspect.LoggerAspect2"/> <bean id="loggerAspect3" class="com.how2java.aspect.LoggerAspect3"/> <aop:config> <aop:pointcut id="loggerCutpoint" expression="execution(void com.how2java.service.ProductService.doSomeService()) "/>

         <aop:aspect id="logAspect2" ref="loggerAspect2"> <aop:before pointcut-ref="loggerCutpoint" method="log"/> </aop:aspect> <aop:aspect id="logAspect3" ref="loggerAspect3"> <aop:after pointcut-ref="loggerCutpoint" method="log"/> </aop:aspect> </aop:config> </beans>

    运行结果为

     -------------------------------------------------------------------------------------------------------------

     AOP的过程分为两步:1,在业务类中插入切点,2,将切点和切面类关联起来

     业务类就是核心类,就是网站的主要功能,切面就是辅助功能,日志,统计之类的

    通过配置,可以实现,在某个方法调用的时候,触发别的方法执行,就好像在监视目标方法,你被执行,就触发我执行。

    下面简单介绍一下通知:

      通知定义了切面要完成的工作内容和何时完成工作,就是什么时候去做辅助功能,功能具体是什么代码

      五种类型

      1. Before——在方法调用之前调用通知

      2. After——在方法完成之后调用通知,无论方法执行成功与否

      3. After-returning——在方法执行成功之后调用通知

      4. After-throwing——在方法抛出异常后进行通知

      5. Around——通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为

       前四个好理解的,最后一个around 表示切面在被监视的函数运行前后都会执行,下面是切面要执行的函数 log,log函数有一个形参 joinPoint 这个可以理解为断点,中间一句代表的就是被监视的程序运行,在被监视的程序运行时,可以替换他的形参,这个是 around 厉害的地方,如果被监视的程序,运行的时候输入的是一个haha字符串作为实参,但是经过log方法之后,这个参数就被替换为abc了

    public Object log(ProceedingJoinPoint joinPoint) throws Throwable {
            System.out.println("我在被监视程序之前。。。");
            Object object = joinPoint.proceed(new Object[]{"abc"});
            System.out.println("我在被监视程序之后。。。" );
            return object;
        }

    注:关于joinPoint的详细介绍,请点击此处查看

  • 相关阅读:
    iOS側拉栏抽屉效果Demo
    Juce源代码分析(九)应用程序基类ApplicationBase
    Android获取手机方向
    2014手机号码归属地数据库
    自译Solr in action中文版
    HUD 2031: 进制转换
    《学习opencv》笔记——矩阵和图像操作——cvConvertScale,cvConvertScaleAbs,cvCopy and cvCountNonZero
    Xcode5.1.1+ios 7.1.2 免证书真机调试
    《你不知道的JavaScript》读书笔记(二)词法作用域
    python生成word中文字体
  • 原文地址:https://www.cnblogs.com/churujianghudezai/p/11805670.html
Copyright © 2011-2022 走看看