面向切面编程(三)

来源:互联网 发布:php写入mysql数据库 编辑:程序博客网 时间:2024/05/23 21:59

本方法与面向切面编程(一)和(二)的实现结果是一样的,但是实现方法不一样。

再介绍一遍spring AOP中的专业术语(其中连接点、切入点、切面很重要):

       1.通知(Advice):通知定义了切面是什么以及何时使用。描述了切面要完成的工作和何时需要执行这个工作。
       2.连接点(Joinpoint):程序能够应用通知的一个“时机”,这些“时机”就是连接点,例如方法被调用时、异常被抛出时等等。
       3.切入点(Pointcut):通知定义了切面要发生的“故事”和时间,那么切入点就定义了“故事”发生的地点,例如某个类或方法的名称,spring中允许我们方便的用正则表达式来指定
       4.切面(Aspect):
通知和切入点共同组成了切面:时间、地点和要发生的“故事”
       
5.引入(Introduction):引入允许我们向现有的类添加新的方法和属性(Spring提供了一个方法注入的功能)
       
6.目标(Target):即被通知的对象,如果没有AOP,那么它的逻辑将要交叉别的事务逻辑,有了AOP之后它可以只关注自己要做的事(AOP让他做爱做的事)
       
7.代理(proxy):应用通知的对象,详细内容参见设计模式里面的代理模式
       
8.织入(Weaving):把切面应用到目标对象来创建新的代理对象的过程,织入一般发生在如下几个时机:

(1)编译时:当一个类文件被编译时进行织入,这需要特殊的编译器才可以做的到,例如AspectJ的织入编译器
(2)类加载时:使用特殊的ClassLoader在目标类被加载到程序之前增强类的字节代码
(3)运行时:切面在运行的某个时刻被织入,SpringAOP就是以这种方式织入切面的,原理应该是使用了JDK的动态代理技术

示例代码:

BizImpl.java(实现类的接口):

    /*     * 时间:2016年9月28日20:41:10     * 程序功能:实现类的接口     * */    package com.sc.biz;    public interface BizImpl {        public void buy(String username,String bookname,double price);        public void pinlun(String username,String pinlunleirong);    }

BookBizImpl.java(实现类):

    /*     * 时间:2016年9月28日20:41:35     * 程序功能:实现类,继承接口并实现方法     * */    package com.sc.biz;    public class BookBizImpl implements BizImpl {        public void buy(String username, String bookname, double price) {            System.out.println("用户名:"+username);            System.out.println("书名:"+bookname);            System.out.println("价格"+price);             }        public void pinlun(String username, String pinlunleirong) {            System.out.println("评论人:"+username);            System.out.println("评论类容:"+pinlunleirong);        }    }

DaiLiLei1.java(使用xml配置的代理类):

    /*     * 时间:2016年9月28日20:42:12     * 程序功能:代理类     * */    package com.sc.daililei;    import java.util.Arrays;    import java.util.Date;    import org.aspectj.lang.JoinPoint;    import org.aspectj.lang.ProceedingJoinPoint;    public class DaiLiLei1 {        // 后置通知,jp.getSignature().getName()可以获取当前执行的方法名        // Arrays.toString(jp.getArgs())获取属性名        public void logBefore(JoinPoint jp) {            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 开始执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));        }        public void logAfter(JoinPoint jp) {            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 结束执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));        }        public void logAround(ProceedingJoinPoint jp) throws Throwable {            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 结束执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));            Object obj = jp.proceed();            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 结束执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));        }    }
DaiLiLei.java(使用注解配置的代理类):

    /*     * 时间:2016年9月28日20:42:12     * 程序功能:代理类,使用注解方配置     * */    package com.sc.daililei;    import java.util.Arrays;    import java.util.Date;    import org.aspectj.lang.JoinPoint;    import org.aspectj.lang.ProceedingJoinPoint;    import org.aspectj.lang.annotation.After;    import org.aspectj.lang.annotation.Around;    import org.aspectj.lang.annotation.Aspect;    import org.aspectj.lang.annotation.Before;    import org.aspectj.lang.annotation.Pointcut;    @Aspect    public class DaiLiLei {        // 该方法相当于在这个位置定义一个切点,以下方法都使用这个切点        @Pointcut("execution(* com.sc.biz.BookBizImpl .*(..))")        public void heHe() {        }        // 后置通知,jp.getSignature().getName()可以获取当前执行的方法名        // Arrays.toString(jp.getArgs())获取属性名        @Before("heHe()")        public void logBefore(JoinPoint jp) {            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 开始执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));        }        @After("heHe()")        public void logAfter(JoinPoint jp) {            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 结束执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));        }        @Around("heHe()")        public void logAround(ProceedingJoinPoint jp) throws Throwable {            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 结束执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));            Object obj = jp.proceed();   //此处为前置通知和后置通知的分界点            System.out.println("[系统日志][" + new Date().toLocaleString() + "] 结束执行:"            + jp.getSignature().getName() + "参数是:"            + Arrays.toString(jp.getArgs()));        }    }

applicationContext.xml(Spring配置文件):

<?xml version="1.0" encoding="UTF-8"?><beansxmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:p="http://www.springframework.org/schema/p"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beans ;http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://www.springframework.org/schema/aop ;http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">            <!-- 使用xml配置 -->    <!-- <bean id="bookBizImpl" class="com.sc.biz.BookBizImpl"></bean>    <bean id="daiLiLei" class="com.sc.daililei.DaiLiLei1"></bean>    <aop:config>       <aop:aspect id="dai" ref="daiLiLei">         <aop:pointcut expression="execution(* com.sc.biz.BookBizImpl .*(..))" id="p"/>         <aop:before method="logBefore" pointcut-ref="p"/>         <aop:after method="logAfter" pointcut-ref="p"/>         <aop:around method="logAround" pointcut-ref="p"/>       </aop:aspect>    </aop:config> -->        <!-- 使用注解配置 -->    <bean id="bookBizImpl" class="com.sc.biz.BookBizImpl"></bean>    <bean id="daiLiLei" class="com.sc.daililei.DaiLiLei"></bean>    <aop:aspectj-autoproxy></aop:aspectj-autoproxy></beans>

切面其实是一个普通的类,然后在配置文件中将它声明称切面

关于在配置文件中声明切面:
<aop:pointcut expression="execution(* com.sc.biz.BookBizImpl .*(..))" id="p"/> 
 
expression里面的值设置方法:
1、任意公共方法的执行:
      expression(public * *(..))
 2、任意一个以set开始的方法的执行:
      
expression(* set* (..))
 
3、AccountService接口定义的任何方法的执行:
      
expression(* com.sc.service.AccountService.*(..))     
 4、在service包中定义的任何方法的执行:
       
expression(* com.sc.service.*.*(..))

 5、在service包或其子包中定义的任一方法的执行:
       expression(* com.sc.service..*.*(..)) 

在配置文件中使用切面:
例如:<aop:before method="logBefore" pointcut-ref="p"/>
声明通知:
常用:<aop:before/>
          <aop:after/>
          <aop:around/>