Spring框架基础学习(三)

AOP

Spring框架具有两个十分重要的思想,即IOC(控制反转)与AOP(面向切面编程) .在此文中对AOP思想做一个简要介绍.
AOP(Aspect Oriented Programming),面向切面编程,与垂直业务功能,实现程序功能的统一维护。(纵向重复,横向抽取)
如在我们之前学习的过滤器就体现了AOP思想


image.png

主要功能
主要功能:日志记录,性能统计,安全控制,事物处理,异常处理等等。(事务处理:任何操作数据库的方法,尤其是增删改,需要事物的处理,使用AOP时,执行到某种类型的方法,或者某一层的类,自动开启事务和获取连接、提交事务、关闭事务的步骤,简化了操作)

AOP实现方式:
1、预编译方式。(AspectJ) 2、运行期动态代理。(JDK动态代理、CGLib动态代理)(SpringAOP、JbossAOP)

切面的理解:
例如系统中有产品管理、订单管理、服务管理等等模块(子功能),任一模块(子功能),都需要记录它的日志,控制它的事务,以及做一些安全验证的功能。但是如果在每一个模块(子功能)中去设计日志、事务、安全验证,会带来大量工作量,尤其当项目达到一定规模时,比如修改日志记录的方式,那么则需要修改每一个模块的日志功能,通过切面方式对开发人员是不可见的,当执行任一模块时,通过预编译或者运行期动态代理方式,都会去记录它的日志,实现了一处写功能,处处可实现的方式,对于开发人员允许不知道有这样功能的存在,这样就简化了操作(修改日志、编写事物等),业务功能横向走,切面垂直业务功能。

AOP基本概念

切面—>织入—>目标对象—>切入点—>连接点—>通知—>引入—>AOP代理:“切面”要执行的动作,通过“织入”与所有功能模块进行联系,又通过“目标对象”找到具体功能模块,通过“切入点”将要查找某个功能的某个方法,通过“连接点”找到该功能的特定方法的开始,通过“通知”将要执行何种切面的动作,通过“引入”引入该动作用到的对象和方法,通过“AOP代理”实现该方法。
AOP相关概念:

1、切面(Aspect):一个关注点(事务),这个关注点可能会横切多个对象(产品管理、订单管理)。(通知+切入点)

2、连接点(Joinpoint):程序执行过程中的某个特定的点。(一个类中执行的某个方法的开始)也可理解为在目标对象中.哪些方法被拦截。

3、通知(Advice):在切面的某个特定的连接点上执行的动作(方法执行的时候,切面额外执行的动作,即要增强的代码.比如说方法执行时,开启事物提交功能)。

4、切入点(Pointcut):匹配连接点的断言,在AOP中通知和一个切入点表达式关联(在切面中匹配一个具体的连接点(某个功能的方法的开始))即筛选连接点,最终要增强的方法。

5、引入(Introduction):在不修改类代码的前提下,修改的是字节码文件,为类添加新的方法和属性。(类似于编译期动态的修改class文件去增加新的属性和方法,源代码中并没有这样的属性和方法),取决于使用AspectJ和SpringAOP的实现方式,使用方式不同,为类添加属性和方法的方式是有区别的。

6、目标对象(Target Object):被一个或者多个切面所通知的对象。即被代理对象(例如存在一个订单的service(对象)和一个商品的service(对象),执行该模块的功能时,切面会通知相对应的service,在执行数据库操作时,去加上事物的控制,这两个service就是目标对象)。

7、AOP代理(AOP Proxy):AOP框架创建的对象,用来实现切面契约(aspect contract),包括通知方法执行等功能(这里执行的方法指的是切面里的执行相应操作所用到的方法)开发时不知道这个对象存在的,也不清楚会创建成什么样子。即把切面的代码应用到目标对象来创建新的代理对象

8、织入(Weaving):把切面连接到其他的应用程序类型或者对象上,并创建一个被通知的对象,分为:编译时织入、类加载时织入、执行时织入。(使切面和对象(模块功能)牵连起来)即把切面的代码应用到目标对象来创建新的代理对象的过程

Advice(通知)的类型(在切面某个特定连接点执行的动作)
前置通知(Before advice):在某连接点(join point)(某个功能方法开始执行前)之前执行的通知,但不能阻止连接点前的执行(除该方法外的其他方法的执行)(除非它抛出一个异常)。

返回后通知(After returning advice):在某连接点(方法)正常完成后执行的通知(将要执行的切面功能)。

抛出异常后通知(After throwing advice):在方法抛出异常退出时执行的通知(将要执行切面的功能)。

后通知(After(finally)advice):当某连接点(方法)退出的时候执行的通知(切面将要执行的功能)(不论是正常返回还是异常退出都会执行的通知)。

环绕通知(Around Advice):包围一个连接点(join point)的通知(在整个方法的内部都有切面要执行的功能存在,不分前后)。

自定义通知程序代码如下

Spring框架中AOP的用途:

用途1:提供了声明式的企业服务(也可以是其他服务,例如互联网服务),特别是EJB(重量级框架)的替代服务的声明。

用途2:允许用户定制自己的方面(切面),以完成OOP(面向对象编程,模拟世界中行为和方式,可以理解为实现一个功能的顺序)与AOP(横切的方式,可以理解为各个功能之间横切的一种功能)的互补使用,可以实现自己横切的功能。

AOP小例子

实现delete()方法的增强
UserService接口,声明增删改查方法


public interface UserService {

    public void save();
    public void delete();
    public void update();
    public void find();
    
}

UserService实现类UserServiceImpl

package service;

public class UserServiceImpl implements UserService {

    public void save() {
        // TODO Auto-generated method stub
        System.out.println("save");
        
    }

    public void delete() {
        // TODO Auto-generated method stub
        System.out.println("delete");
        int z;
        z=1/0;
        
    }

    public void update() {
        // TODO Auto-generated method stub
        System.out.println("update");
    }

    public void find() {
        // TODO Auto-generated method stub
        System.out.println("find");
    }

}

自定义通知类


import org.aspectj.lang.ProceedingJoinPoint;

/*
 * 自定义通知类
 */
public class MyAdvice {

    //before前置通知 在目标方法前调用
    public void before(){
        System.out.println("before");
    }
    
    //after最终通知(后置通知) 在目标方法后调用
    public void after(){
        System.out.println("after");
    }
    //afterReturning成功通知(后置通知) 在目标方法执行后并且执行成功
    public void afterReturning(){
        System.out.println("afterReturning");
    }
    
    //afterThrowing异常通知(后置通知) 当目标方法出现异常时调用
    public void afterThrowing(){
        System.out.println("afterThrowing");
    }
    //around 环绕通知 需要我们手动调用目标方法,并且可以设置通知
    public Object around(ProceedingJoinPoint pjp) throws Throwable {
        System.out.println("around before");
        Object proceed=pjp.proceed();
        System.out.println("around after");
        return proceed;
        
    }
}

applicationContext.xml配置
(注:要引入Spring-AOP的jar包)

<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-3.0.xsd">

<!-- 目标对象  -->
<bean name ="userService" class="service.UserServiceImpl"></bean>
<!-- 通知对象  -->
<bean name="myAdvice" class="aop.MyAdvice"></bean>

<aop:config>
    <!-- 切入点  expression切入点表达式可以配置要增强的方法
                id为唯一标识
                public void service.UserServiceImpl.save()
                public * service.*ServiceImpl.*(..)
    -->
    <aop:pointcut expression="execution(* service.*ServiceImpl.*(..))" id="servicePC"/>
    <!-- 切面 (通知+切入点)-->
    <aop:aspect ref="myAdvice">
    <!-- 通知类型 -->
    <aop:before method="before" pointcut-ref="servicePC"/>
    <aop:after method="after" pointcut-ref="servicePC"/>
    <aop:after-returning method="afterReturning" pointcut-ref="servicePC"/>
    <aop:after-throwing method="afterThrowing" pointcut-ref="servicePC"/>
    <aop:around method="around" pointcut-ref="servicePC"/>
        
    
    </aop:aspect>
</aop:config>

</beans>

测试类

package test;


import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;



import service.UserService;
import service.UserServiceImpl;



public class AopTest {

    @Test
    public void Test2(){
        ApplicationContext ac=new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService us=(UserService) ac.getBean("userService");//得使用接口
        us.delete();
    }

}

使用JUnit4测试结果如下



可见对delete()方法进行了增强

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 160,706评论 4 366
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 68,002评论 1 301
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 110,462评论 0 250
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 44,375评论 0 216
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,763评论 3 294
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,849评论 1 224
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 32,033评论 2 317
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,768评论 0 204
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,490评论 1 246
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,734评论 2 253
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,204评论 1 264
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,566评论 3 260
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,227评论 3 241
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,137评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,934评论 0 201
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,926评论 2 283
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,774评论 2 274

推荐阅读更多精彩内容