ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

Spring AOP 详解以及 Spring 使用 XML 配置 AOP

2019-09-11 20:36:33  阅读:287  来源: 互联网

标签:XML lemon cn Spring void AOP import public


一、概述

1、AOP

  • 全称是 Aspect Oriented Programming 即:面向切面编程
  • AOP 就是把我们程序重复的代码抽取出来,在需要执行的时候,使用动态代理的技术,在不修改源码的基础上,对我们的已有方法进行增强。
  • AOP:面向切面编程,aop就是在某一个类或方法执行前后打个标记,声明在执行到这里之前要先执行什么,执行完这里之后要接着执行什么,插入新的执行方法。在Spring中,它是以JVM的动态代理技术为基础,然后设计一系列AOP横切实现,比如前置通知、返回通知、异常通知等,同时Pointcut接口来匹配切入点,可以使用现有切入点来设计横切面,也可以扩展相关方法根据需求进行切入。

2、作用:

  • 在程序运行期间,不修改源码对已有方法进行增强。

3、优势:

  • 减少重复代码
  • 提高开发效率
  • 维护方便

4、AOP 的实现方式

  • 使用动态代理技术
    关于动态代理请点击

二、AOP(面向切面编程)

1、AOP 相关术语

  • Joinpoint(连接点) : 是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的连接点。
  • Pointcut(切入点) : 是指我们要对哪些 Joinpoint 进行拦截的定义。
  • Advice(通知/增强) : 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。
    通知的类型 :前置通知,后置通知,异常通知,最终通知,环绕通知
  • Introduction(引介) : 是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方法或 Field。
  • Target(目标对象) : 代理的目标对象。
  • Weaving(织入) : 是指把增强应用到目标对象来创建新的代理对象的过程。
    spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
  • Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类。
  • Aspect(切面) : 是切入点和通知(引介)的结合。

2、spring 中的 AOP 要明确的事

a、开发阶段(程序员做的)

  • 编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。
  • 把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP 编程人员来做。
  • 在配置文件中,声明切入点与通知间的关系,即切面。:AOP 编程人员来做。

b、运行阶段(Spring 框架完成的)

  • Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

三、XML 配置 AOP 步骤

第一步:配置要搜索的包

<context:component-scan base-package="cn.lemon"></context:component-scan>

第二步:使用 aop:config 声明 aop 配置

  • 作用:用于声明开始 aop 的配置
<!--aop 配置
     # proxy-target-class="true":使用CGLib代理,默认是 接口代理(JDK代理)
-->
<aop:config proxy-target-class="true">
        <!--配置的代码都写在此处-->
</aop:config>

第三步:使用 aop:aspect 配置切面

  • 作用:用于配置切面。
  • 属性:id:给切面提供一个唯一标识。ref:引用配置好的通知类 bean 的 id。
<aop:aspect ref="loggerAdvice">
     <!--配置通知的类型要写在此处-->
</aop:aspect>

第四步:使用 aop:pointcut 配置切入点表达式

  • 作用:用于配置切入点表达式。就是指定对哪些类的哪些方法进行增强。
  • 属性:expression:用于定义切入点表达式。id:用于给切入点表达式提供一个唯一标识
<!--切入点表达式:定义那些方法织入增强-->
<aop:pointcut id="serviceMethod" expression="execution(* cn.lemon.service.impl.*.*(..))"></aop:pointcut><!--切入点-->

切入点表达式说明
表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))
全匹配方式:

public void cn.lemon.service.impl.AccountServiceImpl.addAccount(cn.lemon.domain.Account)

访问修饰符可以省略

void cn.lemon.service.impl.AccountServiceImpl.addAccount(cn.lemon.domain.Account)

返回值可以使用*号,表示任意返回值

* cn.lemon.service.impl.AccountServiceImpl.addAccount(cn.lemon.domain.Account)

包名可以使用*号,表示任意包,但是有几级包,需要写几个*

 * *.*.*.*.AccountServiceImpl.addAccount(cn.lemon.domain.Account)

使用..来表示当前包,及其子包

 * cn..AccountServiceImpl.addAccount(cn.lemon.domain.Account)

类名可以使用*号,表示任意类

 * cn..*.addAccount(cn.lemon.domain.Account)

方法名可以使用*号,表示任意方法:

 * cn..*.*( cn.lemon.domain.Account)

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

 * com..*.*(*)

参数列表可以使用..表示有无参数均可,有参数可以是任意类型:

 * com..*.*(..)

全通配方式:

 * *..*.*(..)

注意:
通常情况下,我们都是对业务层的方法进行增强,所以切入点表达式都是切到业务层实现类。

execution(* com.lxs.service.impl.*.*(..))

第五步:使用 aop:xxx 配置对应的通知类型

<aop:before method="before" pointcut-ref="serviceMethod"></aop:before><!--织入前置增强-->
<aop:after-returning method="afterReturning" pointcut-ref="serviceMethod" returning="result"></aop:after-returning><!--后置增强-->
<aop:around method="around" pointcut-ref="serviceMethod"></aop:around><!--环绕增强-->
<aop:after-throwing method="exception" pointcut-ref="serviceMethod" <aop:after method="after" pointcut-ref="serviceMethod"></aop:after><!--最终增强-->

在这里插入图片描述

四、Spring 使用 XML 配置 AOP

1、新建持久层(dao),接口以及实现类

package cn.lemon.dao;

public interface IAccountDao {
    void in(Double money);

    void out(Double money);
}
package cn.lemon.dao.impl;

import cn.lemon.dao.IAccountDao;
import org.springframework.stereotype.Repository;

@Repository
public class AccountDaoImpl implements IAccountDao {
    @Override
    public void in(Double money) {
        System.out.println("成功转入" + money + "元钱");
    }

    @Override
    public void out(Double money) {
        System.out.println("成功转出" + money + "元钱");
    }
}

2、新建业务层(service),接口以及实现类

package cn.lemon.service;

public interface IAccountService {
    void transfer(Double money);
}
package cn.lemon.service.impl;

import cn.lemon.dao.IAccountDao;
import cn.lemon.service.IAccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class AccountServcieImpl implements IAccountService {
    @Autowired
    private IAccountDao iAccountDao;

    @Override
    public void transfer(Double money) {
        iAccountDao.in(money);
        iAccountDao.out(money);
    }
}

3、增强类

package cn.lemon.advice;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.springframework.stereotype.Component;

@Component
public class LoggerAdvice {
    /**
     *
     * @param joinPoint 得到业务方法的信息
     *                  getSignature() 表示签名
     */
    public void before(JoinPoint joinPoint){
        System.out.println("开启事务:前置增强,方法名为:" + joinPoint.getSignature().getName());
    }
    public void afterReturning(JoinPoint joinPoint,Object result){
        System.out.println("提交事务:后置增强,方法名为:" + joinPoint.getSignature().getName() + "返回值为:" + result);
    }

    public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        System.out.println("环绕前置增强.......");
        //执行业务方法
        Object result = proceedingJoinPoint.proceed();
        System.out.println("环绕后置增强。。。。。。");
        return result;
    }

    public void exception(JoinPoint joinPoint,Exception e){
        System.out.println("异常增强,异常信息为:" + e.getMessage());
    }

    public void after(JoinPoint joinPoint){
        System.out.println("最终增强,方法名为;" + joinPoint.getSignature().getName());
    }
}

4、AOP 的 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: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/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">
    <context:component-scan base-package="cn.lemon"></context:component-scan>

    <!--aop 配置
     # proxy-target-class="true":使用CGLib代理,默认是 接口代理(JDK代理)
    -->
    <aop:config proxy-target-class="true">
        <!--切入点表达式:定义那些方法织入增强-->
        <aop:pointcut id="serviceMethod" expression="execution(* cn.lemon.service.impl.*.*(..))"></aop:pointcut><!--切入点-->
        <aop:aspect ref="loggerAdvice">
            <aop:before method="before" pointcut-ref="serviceMethod"></aop:before><!--织入前置增强-->
            <aop:after-returning method="afterReturning" pointcut-ref="serviceMethod" returning="result"></aop:after-returning><!--后置增强-->
            <aop:around method="around" pointcut-ref="serviceMethod"></aop:around><!--环绕增强-->
            <aop:after-throwing method="exception" pointcut-ref="serviceMethod" throwing="e"></aop:after-throwing><!--异常增强-->
            <aop:after method="after" pointcut-ref="serviceMethod"></aop:after><!--最终增强-->
        </aop:aspect>
    </aop:config>
</beans>

5、测试类

package cn.lemon.service.impl;

import cn.lemon.service.IAccountService;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = "classpath:/applicationContext.xml")
public class AccountServcieImplTest {
    @Autowired
    private IAccountService iAccountService;

    @Test
    public void transfer() {
        iAccountService.transfer(1000d);
    }
}

五、Spring 使用注解&XML 配置 AOP

标签:XML,lemon,cn,Spring,void,AOP,import,public
来源: https://blog.csdn.net/weixin_43860260/article/details/100524269

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有