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包)









    
    
    
    
    
    
    
    
    
    
        
    
    



测试类

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()方法进行了增强

你可能感兴趣的:(Spring框架基础学习(三))