其他分享
首页 > 其他分享> > spring aop

spring aop

作者:互联网

 

1. AOP

  aspect oriented programming,面向切面编程。通过预编译方式和运行期动态代理实现程序功能的技术。把程序重复的代码抽取出来,在需要执行的时候通过动态代理的方式,在不修改源码的情况下,对已有的方法进行增强。

 

  ①Joinpoint 连接点:

    被拦截到的点。spring中指方法(spring只支持方法类型的连接点)

  ②Pointcut 切入点:

    会被拦截并增强的连接点

  ③Advice  通知/增强:

    拦截到连接点后要做的事

    通知类型(根据和invoke方法的前后顺序区分):前置通知、后置通知、异常通知(catch里面的)、最终通知(finally里面的)、环绕通知

  ④Introduction  引介

    在不修改现有的类的情况下,向现有的类添加新属性和新方法

  ⑤Target  目标对象

    被代理对象

  ⑥Weaving  织入

    把增强部分应用到目标对象来创建新的代理的过程:①编译期织入(需要特殊的编译器,AspectJ) ②类加载期织入(需要特殊的类加载器,Aspectj 5)   ③运行期织入(运行时为目标对象动态地创建一个代理对象,在代理对象里面执行目标对象的方法)

    spring采用动态代理在运行期织入 ;  AspectJ采用编译期织入和类装载器织入

  ⑦Proxy 代理

    一个类被AOP织入增强后,产生一个代理类

  ⑧Aspect  切面

    切入点和通知的结合

 

2. spring中的aop

  spring内部会根据配置或注解创建代理工厂,我们只需要做好配置即可。

  例:增强代码为日志输出

  2.1 xml配置

  被增强接口及其实现类:

package com.xt.service;

public interface IAccountService {

    void saveAccount();

    void updateAccount(int i);

    int deleteAccount();
}

 

package com.xt.service.impl;

import com.xt.service.IAccountService;

public class AccountServiceImpl implements IAccountService {
    @Override
    public void saveAccount() {
        System.out.println("保存");
    }

    @Override
    public void updateAccount(int i) {
        System.out.println("更新");
    }

    @Override
    public int deleteAccount() {
        System.out.println("删除");
        return 10;
    }
}

 

增强类/通知类:一个打印日志的类

package com.xt.utils;

public class Logger {
    public void printLog(){
        System.out.println("---------输出日志-----------");
    }

    public void printLog2(){
        System.out.println("--------又一个日志输出---------");
    }
}

 

bean的xml也要加入aop命名空间标志:

<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
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/aop
        https://www.springframework.org/schema/aop/spring-aop.xsd">
        
</beans>

 

(1)准备一个被增强类,这里是一个普通的类

<bean id="accountService" class="com.xt.service.impl.AccountServiceImpl"></bean>

(2)将通知类/增强代码用bean配置

<bean id="logger" class="com.xt.utils.Logger"></bean>

 

(3)声明aop配置 <aop:config>

  ①配置切入点表达式 <aop:pointcut>

  对哪些类的哪些方法进行增强

    id:切入点表达式唯一标识

    expression:定义切入点表达式  execution(访问修饰符 返回值 包名.类名.方法名(参数列表))

  ②配置切面 <aop:aspect>

    id:切面唯一标识

    ref:引用配置好的通知类/增强的bean的id

  在<aop:aspect>内部配置通知类型

    <aop:before> 前置通知

    <aop:after-returning>  后置通知,和异常通知只能有一个执行

    <aop:after-throwing>  异常通知

    <aop:after>    最终通知

    <aop:around>  环绕通知

    属性:这几个属性就建立了普通类和通知类之间的关系

      method:指定通知类中的方法名称

      pointcut-ref:指定切入点表达式的引用,即<aop:pointcut>的id

      pointcut:不引用切入点表达式,直接定义切入点表达式

 

  则上面例子的bean写为:

<aop:config>
    <aop:pointcut id="pc1" expression="execution(public void com.xt.service.impl.AccountServiceImpl.updateAccount(int))" />
    <aop:aspect id="logAdvice" ref="logger">
        <aop:before method="printLog" pointcut="execution(public void com.xt.service.impl.AccountServiceImpl.saveAccount())">
        </aop:before>
        
        <aop:before method="printLog2" pointcut-ref="pc1">
        </aop:before>
    </aop:aspect>
</aop:config>

  调用测试:

ApplicationContext ac = new ClassPathXmlApplicationContext("beanaop.xml");
IAccountService accountService = ac.getBean("accountService", IAccountService.class);
accountService.updateAccount(10);
accountService.saveAccount();
System.out.println(accountService.getClass()); //class com.sun.proxy.$Proxy3   基于接口的代理

  

  两个注意的地方:

    ①如果被增强类没有接口,则spring框架自动使用基于 CGLIB的动态代理来增强代码

System.out.println(accountService.getClass()); //class com.xt.service.impl.AccountServiceImpl$$EnhancerBySpringCGLIB$$72e1fb9e

    ②配置切入点表达式的时候,原方法参数为int,如果切入点表达式里面写 Integer,则不会代理成功

 

切入点表达式:修饰符 返回值 包名.类名.方法名(参数)

  修饰符可省略

  返回值:可用 * 表示任意返回值

  包名: 可用 * 表示任意包,有多级包时要写多个 *

      可用  .. 表示当前包及其子包

  类名: 可用 * 表示任意类

  方法名: 可用 * 表示任意方法

  参数列表: 可用 * 表示任意数据类型,但必须有参数

        可用 .. 表示有无参数都可以,参数可为任意类型 

 

  2.2 注解配置

  其实xml配置里面重要的就两个:①aop:aspect关联切面类  ②aop:before等指定切入点表达式(切面类具体的方法(method属性)和被增强类方法(pointcut)的关联)

  注解:在切面类上加 @Aspect  ; 在切面类的方法上加注解 @Before("execution(xxx)")

 

  注解API:

    @Aspect 指定一个类为通知类

    @Pointcut("execution(xxx)") 指定切入点表达式,然后可用如下的注解引用

    @Before("pointcut()")  前置通知

    @After("pointcut()")     后置通知,最终通知,始终会执行

    @AfterReturning("pointcut()")     目标方法后执行,异常不执行

    @AfterThrowing("pointcut()")  异常通知

    @Around("pointcut()")  环绕通知,环绕目标方法执行

  

 

标签:spring,切入点,aop,代理,pointcut,通知,public,表达式
来源: https://www.cnblogs.com/taoXiang/p/13053851.html