AOP概述

AOP概述

AOP(Aspect Orient Programming),面向切面编程。面向切面编程时从动态角度考虑程序运行过程。
AOP底层,就是采用动态代理模式实现的,采用了两种代理:JDK的动态代理,与CGLIB的动态代理。

AOP为Aspect OrientProgramming的缩写,意为:面向切面编程,可通过运行期动态代理实现程序功能的统一维护的一种技术。AOP是Spring框架中的一个重要内容。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发效率。

面向切面编程,就是将交叉业务逻辑封装成切面,利用AOP容器的共嗯那个将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的,与主页午逻辑无关的代码,如安全检查、事务、日志、缓存等。

若不使用AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑编程混杂不清。

例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但,它们的代码量占比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余”代码,还大大干扰了主业务逻辑----转账

AOP(Aspect Orient Programming)面向切面编程

Aspect:切面,给你的目标类增加的功能,就是切面。像上面用的日志,事务都是切面。
Orient:面向,对着
Programming:编程

OOP:面向对象编程

怎么理解面向切面编程?

(1)需要在分析项目功能时,找出切面。
(2)合理的安排切面的执行时间(在目标方法前,还是目标方法后)
(3)合理的安全切面执行的位置,在哪个类,哪个方法增加增强功能

术语:

(1)Aspect:切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面是通知(Advice)。实际就是对主业务逻辑的一种增强。
(2)JoinPoint:连接点。指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。
(3)Pointcut:切入点。指声明的一个或多个连接点的集合。通过切入点指定一组方法。被标记为final的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。
(4)目标对象:给哪个类的方法增加功能,这个类就是目标对象
(5)Advice:通知,通知表示切面功能执行的时间

aop的实现

aop是一个规范,时动态的一个规范化,一个标准 aop的技术实现框架

1.spring

1.spring在内部实现了aop规范,能做aop的工作
2.spring主要在事务处理时使用aop
3.我们项目开发中很少使用spring的aop实现。因为spring的aop比较笨重

2.aspectj:一个开源的专门做aop的框架,spring框架中集成了aspectj框架,通过spring就能使用aspectj的功能

aspectj框架实现aop有两种方式:
1.使用xml的配置文件:配置全局事务
2.使用注解,我们在项目中要做aop功能,一般都使用注解,aspectj有5个注解

aspectj框架的使用

1.切面的执行时间,也叫切面的通知(Advice)类型

在aspectj框架中使用注解表示的,也可以使用xml配置文件中的标签
1)@Before :切入点前执行的代码
2)@AfterReturning:后置通知
3)@Around:环绕通知
4)@AfterThrowing:抛出异常后进行异常处理的代码
5)@After:切入点后执行的代码
以上5个表示切面的执行时间

2.切面的执行位置,使用的是切入点表达式

Aspectj定义了专门的表达式用于指定切入点。表达式的原型是:
execution(modifier-pattern? ret-type-pattern
declaring-type-pattern?name-pattern(param-pattern)
throw-pattern?)
解释:
modifier-pattern: 访问权限类型
ret-type-pattern:返回值类型
declaring-type-pattern?name-pattern(param-pattern):类路径+方法名(参数类型和参数个数)
throw-pattern:抛出异常类型
?:表示可选的部分
以上表达式共4个部分
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
红色字体为必须要有的对象
切入点表达式要匹配的对象就是目标方法的方法名。所以,execution表达式中明显就是方法的签名。注意:表达式中黑色文字表示可省略部分,各部分间用空格分开。在其中可以使用以下符号:

符号      意义
 *    0至多个任意字符
 ..   用在方法参数中,表示任意多个参数
		 用在包名后,表示当前包及其子包路径
 +    用在类名后,表示当前类及其字类
		 用在接口后,表示当前接口及其实现类
	

举例:
exection(public * (…)) :指定切入点为:任意公共方法
exection(
set*(…)):指定切入点为:任意一个以“set”开始的方法
exection(* com.itcast.service..(…)):指定切入点为:包名为service下任意类的任意方法

3.使用aspectj实现aop的基本步骤:

1.新建maven项目
2.加入依赖
(1)spring依赖
(2)asceptj依赖
(3)junit单元测试
3.创建目标类:接口和它的实现类。要做的是给类中的方法增加功能
4.创建切面类:普通类
(1)在类的上面加入@Aspect
(2)在类中定义方法,方法就是切面要执行的功能代码
在方法的上面加入aapectj中的通知注解,例如@Before,需要指定切点表达式execution()
5.创建spring的配置文件:声明对象,把对象交给容器统一管理
声明对象你可以使用注解,或xml配置文件<bean>
(1)声明目标对象
(2)声明切面类对象
(3)声明aspectj框架中的自动代理生成器标签
自动代理生成器:用来完成代理对象的自动创建功能的。
6.创建测试类,从spring容器中获取目标对象(实际就是代理对象)。
通过代理执行方法,实现aop的功能的增强。

4.关于切面类的介绍

在类的上面加入@Aspect
@Aspect:是aspectj框架中的注解
作用:表示当前类是切面类
切面类:是用来给业务方法增加功能的类,在这个类中有切面的功能代码
位置:在类定义的上面

5.关于方法上面使用注解的介绍

(1)@Before:前置通知注解
属性:value,是切入点表达式,表示切面的功能执行的位置。
位置:在方法的上面
特点:
1.在目标方法之前先执行
2.不会改变目标方法的执行结果
3.不会影响目标方法的执行

(2)@AfterReturning:后置通知
属性:returning,用于指定接收方法返回值的变量名
value,是切入点表达式,表示切面的功能执行的位置。
位置:在方法的上面
特点:
1.由于是目标方法之后执行,所以可以获取到目标方法的返回值
2.该注解的returning属性就是用于指定接收方法返回值的变量名的。所以,被注解为后置通知的方法,除了可以包含JoinPoint参数外,还可以包含用于接收返回值的变量。该变量最好为Object类型,因为目标方法的返回值可能是任何类型

(3)@Around:环绕通知
属性:value切入点表达式
位置:在方法的定义什么
特点:
1.它是功能最强的通知
2.在目标方法的前和后都能增强功能
3.控制目标方法是否被调用执行
4.修改原来的目标方法的执行结果。影响最后的调用结果
环绕通知,等同于jdk动态代理的InvocationHandler接口
参数:ProceedingJoinPoint就等同于Method
作用:执行目标方法的
返回值:就是目标方法的执行结果,可以被修改

环绕通知方法的定义格式
1.public
2.必须有一个返回值,推荐使用Object
3.方法名称自定义
4.方法有参数,固定的参数ProceedingJoinPoint

@Aspect
public class Aspect6 {
    /**@Around
     * 1.它是功能最强的通知
     * 2.在目标方法的前和后都能增强功能
     * 3.控制目标方法是否被调用执行
     * 4.修改原来的目标方法的执行结果。影响最后的调用结果
     *
     * 环绕通知,等同于jdk动态代理的InvocationHandler接口
     * 参数:ProceedingJoinPoint:等同于Method
     *      作用:执行目标方法的
     * 返回值:就是目标方法的执行结果,可以被修改。
     *
     * 环绕通知:经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务
     * @param point
     * @return
     * @throws Throwable
     */
    @Around(value = "execution(* com.itcast.aop6.HumanImpl.getUp(..))")
    public Object Aspect6(ProceedingJoinPoint point) throws Throwable {
        System.out.println("前置环绕执行。。。");
        Object[] args = point.getArgs();
        if (args!=null && args.length>1){
            if (args[0].equals("zhangsan")){
                Object proceed = point.proceed();
            }
        }
        System.out.println("后置环绕执行。。。");
        return null;
    }
}

环绕通知:经常做事务,在目标方法之前开启事务,执行目标方法,在目标方法之后提交事务
事务概念(Transaction),一般是指要做的或所做的事情。在计算机术语中是指访问并可能更新数据库中各种数据项的一个程序执行单元(unit)。事务通常由高级数据库操纵语言或编程语言(如SQL,C++或Java)书写的用户程序的执行所引起,并用形如begin transaction和end transaction语句(或函数调用)来界定。事务由事务开始(begin transaction)和事务结束(end transaction)之间执行的全体操作组成。

(4) @AfterThrowing:异常通知
属性:1.value切入点表达式
2.throwing自定义的变量,表示目标方法抛出的异常对象
变量名必须和方法的参数名一样
特点:
1.在目标方法抛出异常时执行的
2.可以做异常的监控程序,监控目标方法执行时是不是有异常。
如果有异常,可以发送邮件,短信进行通知

/**
 * 声明切面类
 */
@Aspect
public class Aspect7 {

    //出异常时,方法执行
    @AfterThrowing(value = "execution(* com.itcast.aop7.HumanImpl.byZeroException())",throwing = "e")
    public void testEx(Exception e){
        System.out.println("除数出错"+e.getMessage());
    }
}

(5)@After:最终通知
属性:value切入点表达式
位置:在方法的上面
特点:
1.总是会执行
2.在目标方法之后执行的,一般做资源清除工作的。

@Aspect
public class Aspect8 {

    /**
     * 最终通知方法的定义格式
     * 1.public
     * 2.没有返回值
     * 3.方法名称自定义
     * 4.方法没有参数,如果有就是JoinPoint
     */
    
    /**
     * @After:最终通知。一般做资源清除工作的
     * 属性:value切入点表达式
     * 位置:在犯法的上面
     * 特点:
     * 1.总是会执行
     * 2.在目标方法之后执行的
     */
    @After(value = "execution(* com.itcast.aop8.HumanImpl.byAfter())")
    public void byAfter(){
        System.out.println("执行最终通知,最终都会执行的代码");
    }
}

(6)@Pointcut:定义和管理切入点
如果你的项目中有多个切入点表达式是重复的,可以复用的。可以使用@Pointcut
属性:value切入带你表达式
位置:在自定义的方法上面
特点:
当使用@Pointcut定义在一个方法的上面,此时这个方法的名称就是切入带你表达式的别名。
其他的通知中,value属性就可以使用这个方法名称,代替切入带你表达式了

@Aspect
public class Aspect9 {
    @Before(value = "mypt()")
    public void myBefore(){
        System.out.println("前置通知执行。。。。");
    }

    @After(value = "mypt()")
    public void myAfter(){
        System.out.println("后置通知执行。。。。");
    }

    @Pointcut(value = "execution(* com.itcast.aop9.HumanImpl.myTarget())")
    public void mypt(){
        System.out.println("前置通知执行。。。。");
    }
}

JoinPoint:指定通知方法中的参数
位置:在切面方法中
JoinPoint:业务方法,要加入切面功能的业务方法
作用:可以通知方法中获取方法执行时的信息,例如方法名称,方法的实参
如果你的切面功能中需要用到方法的信息,就加入JoinPoint
这个JoinPoint参数的值是由框架赋予,必须是一个位置的参数

6.关于spring配置文件的介绍

<-- 声明目标对象 -->
<bean id="humanImpl" class="com.itcast.aop3.HumanImpl"></bean>

<-- 声明切面对象 -->
<bean id="aspect3" class="com.itcast.aop3.Aspect3"></bean>

<-- 声明自动代理生成器:使用aspect框架的内部的功能,创建目标对象的代理对象。创建代理对象是在内存中实现的,修改目标对象的内存中的结构。创建为代理对象,所以目标对象就是被修改后的代理对象
aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象
 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

7.关于测试切面类的介绍

public class Test3 {
    @Test
    public void test01(){
    	//加载spring配置文件,获取spring容器
        ApplicationContext ac = new ClassPathXmlApplicationContext("aop3/ApplicationContext.xml");
        //从容器中获取目标对象
        Human humanImpl = (Human)ac.getBean("humanImpl");
        //通过代理对象执行方法,实现目标方法执行时,增强功能
        humanImpl.getUp();
        humanImpl.makeMoney(300);
        humanImpl.shopping(20);
        humanImpl.sleep();
    }
}

以上代码的执行:spring加载配置文件,通过spring配置文件读取到有两个<bean>标签的对象并放入到spring容器中,走到aspectj-autoproxy:会把spring容器中的所有的目标对象,一次性都生成代理对象。接下来通过<bean>标签中的class为目标类的id值来获取代理目标类对象,然后执行方法 . . . 实现增强。

8.什么时候考虑使用aop技术

(1)当要给一个系统中存在的类修改功能,但是原有类的功能不完善,但是还有源代码,使用aop就能增强功能
(2)要给项目中的多个类,增加一个相同的功能,使用aop
(3)给业务方法增加事务,日志输出

9.关于JDK代理和CGLIB的动态代理

jdk代理目标的类是继承接口的类 CGLIB的动态代理,可以继承接口和不继承几口两种
1.不继承接口的类实现的AOP属于CGLIB的动态代理
2.使用接口继承的类实现CGLIB的动态代理,需要在配置文件中添加以下配置proxy-target-class=“true”

<--   如果你期望目标类有接口,使用cglib代理
proxy-target-class=“true”:告诉框架,要使用cglib动态代理-->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值