java版云笔记(六)之AOP

今天主要是利用aop技术追加service的响应时间的计算和异常的日志记录。

AOP

  AOP(Aspect Oriented Programming),即面向切面编程,可以说是OOP(Object Oriented Programming,面向对象编程)的补充和完善。面向对象编程将程序分解成各个层次的对象,面向切面编程将程序运行过程分解成各个切面。

  AOP从程序运行角度考虑程序的结构,提取业务处理过程的切面,oop是静态的抽象,aop是动态的抽象, 是对应用执行过程中的步骤进行抽象,从而获得步骤之间的逻辑划分。

  面向切面编程(AOP)完善spring的依赖注入(DI),面向切面编程在spring中主要表现为两个方面
    1.面向切面编程提供声明式事务管理
    2.spring支持用户自定义的切面

特点:在不修改系统业务逻辑的前提下,给系统追加功能。

AOP核心概念

  • 1、横切关注点

  对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点

  • 2、切面(aspect)

  类是对物体特征的抽象,切面就是对横切关注点的抽象

  • 3、连接点(joinpoint)

  被拦截到的点,因为Spring只支持方法类型的连接点,所以在Spring中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器

  • 4、切入点(pointcut)

  对连接点进行拦截的定义

  • 5、通知(Advice):

      在切面的某个特定的连接点(Joinpoint)上执行的动作。通知有各种类

型,其中包括”around”、”before”和”after”等通知。许多AOP框架,包括Spring,都是以拦截器做通知模型, 并维护一个以连接点为中心的拦截器链。

  • 6、目标对象(Target):

  就是那些即将切入切面的对象,也就是那些被通知的对象。

  • 7、代理对象(Proxy):

  将通知应用到目标对象之后被动态创建的对象。可以简单地理解为,代理对象的功能等于目标对象的核心业务逻辑功能加上共有功能。代理对象对于使用者而言是透明的,是程序运行过程中的产物。

  • 8、织入(weave)

  将切面应用到目标对象并导致代理对象创建的过程

  • 9、引入(introduction)

  在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段

表达式:三种

AspectJ类型匹配的通配符:
   :匹配任何数量字符;
  ..:(两个点)匹配任何数量字符的重复,如在类型模式中匹配任何数量子包;而在方法参数模式中匹配任何数量参数。
  + :匹配指定类型的子类型;仅能作为后缀放在类型模式后边。

  • 方法限定表达式:execution

为某个组件的部分方法追加功能

  • execution(修饰符? 返回类型 方法名(参数) 抛出异常?)

匹配所有以add开头的方法

    execution(* add*(..))

匹配UserService组件下所有的方法

execution(* cn.tedu.service.UserService.*(..))

匹配的service下所有组件的所有方法

execution(* cn.tedu.service.*.*(..))

匹配的service包及子包中的所有方法

execution(* cn.tedu.service..*.*(..))

案例:

@Before execution(* cn.tedu.cloudnote.service..*.*(..))
  • 类级限定表达式:within

匹配UserService组件下的所有方法

within(cn.tedu.cloudnote.service.UserService)

匹配到service包下所有类的所有方法

within(cn.tedu.cloudnote.service.*)

匹配到service包及子包下的所有类的所有方法

within(cn.tedu.cloudnote.service..*)
  • bean限定表达式:bean(id名)

匹配userService组件的所有方法

bean(userService)

匹配所有以service结尾的组件的所有方法

bean(*Service)
@Bfore("bean(userController)")

通知(Advice)类型

  为了符合现实的各种需求,通知类型提供了5种,可以对目标方法进行全方位处理;

  • Before advice:在某连接点(JoinPoint)之前执行的通知,但这个通知不能阻止连接点前的执行。

  ApplicationContext中在里面使用元素进行声明。

  • After advice:当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。

  ApplicationContext中在里面使用元素进行声明。

  • After returnadvice:在某连接点正常完成后执行的通知,不包括抛出异常的情况。

  ApplicationContext中在里面使用元素进行声明。

  • Around advice:包围一个连接点的通知,类似Web中Servlet规范中的Filter的doFilter方法。可以在方法的调用前后完成自定义的
    行为,也可以选择不执行。

  ApplicationContext中在里面使用元素进行声明。

  • Afterthrowing advice:在方法抛出异常退出时执行的通知。

  ApplicationContext中在里面使用元素进行声明。

AOP 代理

OP支持2种代理,Jdk的动态代理和CGLIB实现机制。

  Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。Spring创建代理的规则为:

  •   1、默认使用Java动态代理来创建AOP代理,这样就可以为任何接口实例创建代理了
  •   2、当需要代理的类不是代理接口的时候,Spring会切换为使用CGLIB代理,也可强制使用CGLIB

二者区别:
  Jdk基于接口实现:JDK动态代理对实现了接口的类进行代理。

  CGLIB基于继承:CGLIB代理可以对类代理,主要对指定的类生成一个子类,因为是继承,所以目标类最好不要使用final声明。

  通常情况下,鼓励使用jdk代理,因为业务一般都会抽象出一个接口,而且不用引入新的东西。如果是遗留的系统,以前没有实现接口,那么只能使用CGLIB。

AOP配置

Spring AOP配置有两种风格:
  XML风格 = 采用声明形式实现Spring AOP
  AspectJ风格 = 采用注解形式实现Spring AOP

XML风格

<!-- com.tedu.cloudnote.aspect.LoggerBean为类名 -->
<bean id="loggerBean" class="com.tedu.cloudnote.aspect.LoggerBean">
    </bean>
    <aop:config>
        <!-- 通过ref关联组建类 -->
        <aop:aspect ref="loggerBean">
        <!-- 通过method指定处理方法,logController为方法名 -->
            <aop:before method="logController"
            pointcut="within(com.tedu.cloudnote.controller..*)"/>

        <!-- 方法限定类型 -->
        <aop:before method="logController"
        pointcut="execution(* com.tedu.cloudnote.service.*.*(..))" />

        <!--  bean名称限定类型-->
         <aop:before method="logController"
            pointcut="bean(userLoginController)"/>
        </aop:aspect>
    </aop:config> -->
    <bean id="helloWorldImpl1" class="com.xrq.aop.HelloWorldImpl1" />
     <bean id="helloWorldImpl2" class="com.xrq.aop.HelloWorldImpl2" />
     <bean id="timeHandler" class="com.xrq.aop.TimeHandler" />
    <aop:config>
            <aop:aspect id="time" ref="timeHandler">
                <aop:pointcut id="addAllMethod" expression="execution(* com.xrq.aop.HelloWorld.*(..))" />
                <aop:before method="printTime" pointcut-ref="addAllMethod" />
                <aop:after method="printTime" pointcut-ref="addAllMethod" />
            </aop:aspect>
        </aop:config>

AspectJ风格

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:context="http://www.springframework.org/schema/context"
    xmlns:jdbc="http://www.springframework.org/schema/jdbc" xmlns:jee="http://www.springframework.org/schema/jee"
    xmlns:tx="http://www.springframework.org/schema/tx" xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:util="http://www.springframework.org/schema/util"
    xmlns:jpa="http://www.springframework.org/schema/data/jpa"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
        http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
        http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-3.2.xsd
        http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd
        http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
        http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
        http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd
        http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
        http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd">

<!-- 注解 AOP配置 -->
    <context:component-scan
    base-package="com.tedu.cloudnote.aspect"/>
    <!-- 开启AOP注解标记的使用,例如@Aspect,@Before,@After -->
    <aop:aspectj-autoproxy />
</beans>

添加的功能,aop类

@Component   // 扫描,等价于<bean>定义
@Aspect      // 等价于<aop:aspect>定义
public class AspectJAdvice { 

    // 等价于<aop:before>定义
    // 在Controller方法执行前,先执行logController处理
    @Before("within(com.tedu.cloudnote.controller..*)")
    public void logController() {

        System.out.println("进入Controller处理请求");
    }

    @Around("within(com.tedu.cloudnote.service..*)")
    public Object test(ProceedingJoinPoint jp) throws Throwable {
        long t1 = System.currentTimeMillis();
        Object val = jp.proceed();// 目标业务方法
        long t2 = System.currentTimeMillis();
        long t = t2 - t1;

        // JoinPoint 对象可以获取目标业务方法的
        // 详细信息: 方法签名, 调用参数等
        Signature m = jp.getSignature();
        // Signature: 签名, 这里是方法签名
        System.out.println(m + "用时:" + t);
        return val;
    }

    // e就是目标组件方法抛出的异常对象
    @AfterThrowing(throwing = "e", pointcut = "within(com.tedu.cloudnote.controller..*)")
    public void execute(Exception e) {
        try {
            // 将异常信息写入文件中
            FileWriter fw = new FileWriter("D:\\note_error.log", true);
            PrintWriter pw = new PrintWriter(fw);
            // 利用pw对象写信息
            Date time = new Date();
            SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String timeStr = sdf.format(time);
            pw.println("-----------------------------------------");
            pw.println("*异常类型:*" + e);
            pw.println("*发生时间:*" + timeStr);
            pw.println("*异常详情: *");
            e.printStackTrace(pw);
            pw.close();
            fw.close();
        } catch (Exception ex) {
            System.out.println("记录异常失败");
        }
    }

}

注解配置的

@Pointcut

声明切入点

@Pointcut(value=”切入点表达式”, argNames = “参数名列表”)
public void pointcutName(……) {}

value:指定切入点表达式(在哪切);
argNames:指定命名切入点方法参数列表参数名字,可以有多个用“,”分隔,这些参数将传递给通知方法同名的参数,同时比如切入点表达式“args(param)”将匹配参数类型为命名切入点方法同名参数指定的参数类型。
pointcutName:切入点名字,可以使用该名字进行引用该切入点表达式。

@Pointcut(value="execution(* cn.javass..*.sayAdvisorBefore(..)) && args(param)", argNames = "param")
public void beforePointcut(String param) {}   

定义了一个切入点,名字为“beforePointcut”,该切入点将匹配目标方法的第一个参数类型为通知方法实现中参数名为“param”的参数类型。

@Before

前置通知

@Before(value = “切入点表达式或命名切入点”, argNames = “参数列表参数名”)

value:指定切入点表达式或命名切入点;
argNames:与Schema方式配置中的同义。

@AfterReturnin ####

后置返回通知

**@AfterReturning(value=”切入点表达式或命名切入点”,
pointcut=”切入点表达式或命名切入点”,
argNames=”参数列表参数名”,
returning=”返回值对应参数名”) **

/实例
@AfterReturning(
    value="execution(* cn.javass..*.sayBefore(..))",
    pointcut="execution(* cn.javass..*.sayAfterReturning(..))",
    argNames="retVal", returning="retVal")
public void afterReturningAdvice(Object retVal) {
    System.out.println("===========after returning advice retVal:" + retVal);    

@AfterThrowing

后置异常通知

**@AfterThrowing (
value=”切入点表达式或命名切入点”,
pointcut=”切入点表达式或命名切入点”,
argNames=”参数列表参数名”,
throwing=”异常对应参数名”)
**

@AfterThrowing(
    value="execution(* cn.javass..*.sayAfterThrowing(..))",
    argNames="exception", throwing="exception")
public void afterThrowingAdvice(Exception exception) {
    System.out.println("===========after throwing advice exception:" + exception);
}   

注:pointcut:同样是指定切入点表达式或命名切入点,如果指定了将覆盖value属性指定的,pointcut具有高优先级;

@After

后置最终通知:

**@After (
value=”切入点表达式或命名切入点”,
argNames=”参数列表参数名”)
**

@Around

环绕通知

**@Around (
value=”切入点表达式或命名切入点”,
argNames=”参数列表参数名”) **

@Around(value="execution(* cn.javass..*.sayAround(..))")
public Object aroundAdvice(ProceedingJoinPoint pjp) throws Throwable {
    System.out.println("===========around before advice");
    Object retVal = pjp.proceed(new Object[] {"replace"});
    System.out.println("===========around after advice");
    return retVal;
}   
时间: 2024-10-22 22:19:17

java版云笔记(六)之AOP的相关文章

java版云笔记(一)

云笔记项目 这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址为:http://download.csdn.net/download/liveor_die/9985846 项目简介 笔记管理系统,用户可以管理笔记信息,可以查看 其他用户分享的笔记. 主要功能如下 用户模块:登录.注册.修改密码.退出 笔记本模块:创建.删除.更新.查看 笔记模块:创建.删除.更新.查看.转移 分享和收藏模块:分享.收藏.查看.搜索分享 回收站模块:查看.彻底删除.恢复 活动模块:查

java版云笔记(九)之动态sql

SQL 首先,所谓SQL的动态和静态,是指SQL语句在何时被编译和执行,二者都是用在SQL嵌入式编程中的,这里所说的嵌入式是指将SQL语句嵌入在高级语言中,而不是针对于单片机的那种嵌入式编程. 静态SQL 静态SQL通常用于完成可以确定的任务.(即在编译阶段就可以确定数据库要做什么事情.) select * from t1 where c1>5 对于上述类似的DML语句在第一次运行时进行编译,而后续再次调用,则不再编译该过程.即一次编译,多次调用,使用的相同的执行计划.此种方式被称之为使用的是静

java版云笔记(七)之事务管理

事务管理 事务:程序为了保证业务处理的完整性,执行的一条或多条SQL语句. 事务管理:对事务中的SQL语句进行提交或者回滚. 事物管理对于企业应用来说是至关重要的,好使出现异常情况,它也可以保证数据的一致性,不出现脏数据. Spring Framework对事务管理提供了一致的抽象,其特点如下: 为不同的事务API提供一致的编程模型,比如JTA(Java Transaction API), JDBC, Hibernate, JPA(Java Persistence API和JDO(Java Da

java版云笔记(二)

云笔记 基本的环境搭建好了,今天做些什么呢,第一是链接数据库(即搭建Spring-Batistas环境),第二是登录预注册. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址为:http://download.csdn.net/download/liveor_die/9985846 搭建Spring-Batistas环境 搭建Spring-Batistas环境的基本流程如下图 jar包和配置文件上节课已经添加好了,所一下来我们要配置spring配置文件. 配

java版云笔记(八)之关联映射

Mybatis关联映射 通过数据库对象之间的关联关系,反映到到实体对象之间的引用. 加载多个表中的关联数据,封装到我们的实体对象中. 当业务对数据库进行关联查询. 关联 <association property="author" column="blog_author_id" javaType="Author"> <id property="id" column="author_id"/

java版云笔记(三)

登录与注册写好了下来就是主页,今天写的是主页加载时笔记本列表的显示,ajax是固定的就不重点说了.主要说一下jQuery.data() 函数和jQuery.on() 函数. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址为:http://download.csdn.net/download/liveor_die/9985846 笔记列表显示 发送Ajax请求 - 发送事件:笔记本li元素的单击 - 请求参数:笔记本ID - 请求地址:/note/loadn

java版云笔记(四)

页面的笔记本加载完成了,接下来就是点击笔记本显示将笔记显示,同时把笔记在右边的编辑器中,同时把编辑后的笔记更新. 注:这个项目的sql文件,需求文档,需要的html文件,jar包都可以去下载,下载地址为:http://download.csdn.net/download/liveor_die/9985846 笔记列表显示 前面我们把bookId通过下面的jq代码绑定在li上(笔记本的列表id=note_ul) $li.data("bookId",bookId);//将值与jQuery对

简易java版淘客程序上线

问题描述 简易java版淘客程序上线100%返利http://ahzhouhui.appspot.com/ 解决方案 解决方案二:确实够简易的..解决方案三:楼主的淘宝网很接近大自然啊--解决方案四:哇,不错.页面相当的"简洁"!嘿嘿!解决方案五:很好很强大解决方案六:分页明显有问题.解决方案七:虽然简易,还是要支持楼主的.解决方案八:第一感觉页面极不美观马上就关了解决方案九:顶LZ不过真的好简易啊解决方案十: 解决方案十一:lz是自己在淘宝上找商品连接?图片自己加?想问问lz想怎么盈

[开源]java版QQ机器人集成小黄鸡功能

      项目采用开源程序IQQ.内置webQQ协议.并且使用十分方便.直接调用即可.      项目采用webService接口调用可以不用重新登录QQ即可实现项目的修改.测试期间 多次登录QQ导致QQ被检测到异常还得手机解封.实现功能:一:实现天气预报的功能 用于输入#天气+你所在城市 目前只支持市区级查询.  二:实现QQ号码吉凶查询 输入#QQ+你的号码.  三:实现聊天功能.调用小黄鸡接口实现java版小黄鸡.  四:用户可以随意修改源码if判断加入自己的message.  五:其他