当前位置: 首页 > news >正文

Spring框架学习07——基于传统代理类的AOP实现

在Spring中默认使用JDK动态代理实现AOP编程,使用org.springframework.aop.framework.ProxyFactoryBean创建代理是Spring AOP 实现的最基本方式。

1、通知类型

根据Spring中通知在目标类方法中的连接点位置,通知可以分为6种类型:

(1)环绕通知

环绕通知(org.aopalliance.intercept.MethodInterceptor)是在目标方法执行前和执行后实施增强,可应用于日志记录、事务处理等功能。

(2)前置通知

前置通知(org.springframework.aop.MethodBeforeAdvice)是在目标方法执行前实施增强,可应用于权限管理等功能。

(3)后置返回通知

后置返回通知(org.springframework.aop.AfterReturningAdvice)是在目标方法成功执行后实施增强,可应用于关闭流、删除临时文件等功能。

(4)后置(最终)通知

后置通知(org.springframework.aop.AfterAdvice)是在目标方法执行后实施增强,与后置返回通知不同的是,不管是否发生异常都要执行该类通知,该类通知可应用于释放资源。

(5)异常通知

异常通知(org.springframework.aop.ThrowsAdvice)是在方法抛出异常后实施增强,可应用于处理异常、记录日志等功能。

(6)引入通知

引入通知(org.springframework.aop.IntroductionInterceptor)是在目标类中添加一些新的方法和属性,可应用于修改目标类(增强类)。Spring AOP 只支持方法层面的增强,所以该类型的通知只作为了解即可。

2、切面类型

  • Advisor:代表一般切面,Advice本身就是一个切面,对目标类所有方法进行拦截
  • PointcutAdvisor:代表具有切点的切面,可以指定拦截目标类哪些方法
  • IntroductionAdvisor:代表引介切面,针对引介通知而使用切面

3、ProxyFactoryBean

ProxyFactoryBean是org.springframework.beans.factory.FactoryBean 接口的实现类,FactoryBean负责实例化一个Bean实例,ProxyFactoryBean负责为其他Bean实例创建代理实例。ProxyFactoryBean类的常用属性如下:

  • target:代理的目标对象
  • proxyInterfaces:代理需要实现的接口列表,如果是多个接口,可以使用以下格式赋值:<list> <value></value> </list>
  • InterceptorNames:需要织入目标的Advice
  • proxyTargetClass:是否对类代理而不是接口,默认为false,使用JDK动态代理;当为true时,使用CGLIB动态代理
  • singleton:返回的代理实例是否为单例,默认为true
  • optimize:当设置为true时强制使用CGLIB动态代理

4、Advisor一般切面的实现

在pom.xml中导入AOP联盟和Spring-aop的相关依赖

<!-- AOP联盟依赖 -->
<dependency>
  <groupId>aopalliance</groupId>
  <artifactId>aopalliance</artifactId>
  <version>1.0</version>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-aop</artifactId>
  <version>5.0.2.RELEASE</version>
</dependency>

创建StuDao接口和StuDaoImpl实现类,示例代码如下:
StuDao接口

public interface StuDao {
    public void save();
    public void modify();
    public void delete();
}

StuDaoImpl实现类

public class StuDaoImpl implements StuDao {
    @Override
    public void save() {
        System.out.println("保存");
    }

    @Override
    public void modify() {
        System.out.println("修改");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }
}

创建切面类MyBeforeAdvice,仅实现前置通知

import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;

public class MyBeforeAdvice implements MethodBeforeAdvice {
    @Override
    public void before(Method method, Object[] objects, Object o) throws Throwable {
        System.out.println("前置增强========");
    }
}

在applicationContext.xml中配置切面并指定代理

<!--配置目标类-->
<bean id="stuDao" class="aop.StuDaoImpl"></bean>
<!--配置前置通知类型-->
<bean id="myBeforeAdvice" class="aop.MyBeforeAdvice"></bean>
<!--Spring AOP 生成代理对象-->
<bean id="stuDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!--配置目标类-->
    <property name="target" ref="stuDao"></property>
    <!--代理实现的接口-->
    <property name="proxyInterfaces" value="aop.StuDao"></property>
    <!--采取拦截的名称-->
    <property name="interceptorNames" value="myBeforeAdvice"></property>
</bean>

创建测试类

@Test
public void demo(){
    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    StuDao stuDao = (StuDao) app.getBean("stuDaoProxy");
    stuDao.save();
    stuDao.modify();
    stuDao.delete();
}

运行结果

5、PointcutAdvisor切点切面的实现

使用普通Advice作为切面,将对目标类所有方法进行拦截,不够灵活,在实际开发中常采用带切点的切面。
常用PointcutAdvisor实现类:

  • DefaultPointcutAdvisor最常用的切面类型,它可以通过任意Pointcut和Advice组合定义切面;
  • JdkRegexpMethodPointcut构造正则表达式切点(推荐)

创建StuDao接口和StuDaoImpl实现类,示例代码如下:
StuDao接口

public interface StuDao {
    public void save();
    public void modify();
    public void delete();
}

StuDaoImpl实现类

public class StuDaoImpl implements StuDao {
    @Override
    public void save() {
        System.out.println("保存");
    }

    @Override
    public void modify() {
        System.out.println("修改");
    }

    @Override
    public void delete() {
        System.out.println("删除");
    }
}

下面创建一个实现环绕通知的切面类

import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;

public class MyAspect implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation m) throws Throwable {
        //前置增强方法
        check();
        //执行目标方法
        Object obj = m.proceed();
        //后置增强方法
        log();
        return obj;
    }

    public void check(){
        System.out.println("模拟权限控制");
    }
    public void log(){
        System.out.println("模拟日志记录");
    }
}

在applicationContext.xml中配置切面并指定代理

<!--配置目标类-->
 <bean id="stuDao" class="aop.StuDaoImpl"></bean>
 <!--配置通知-->
 <bean id="myAspect" class="aop.MyAspect"></bean>
 <!--配置带切入点的切面-->
 <bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
     <!--pattern中配置正则表达式:.表示任意字符 *表示任意次数-->
     <property name="pattern" value=".*"></property>
     <property name="advice" ref="myAspect"></property>
 </bean>
 <!--Spring AOP 生成代理对象-->
 <bean id="stuDaoProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
     <!--配置目标类-->
     <property name="target" ref="stuDao"></property>
     <!--代理实现的接口-->
     <property name="proxyInterfaces" value="aop.StuDao"></property>
     <!--采取拦截的名称-->
     <property name="interceptorNames" value="myAdvisor"></property>
 </bean>

创建测试类

@Test
public void demo(){
    ApplicationContext app = new ClassPathXmlApplicationContext("applicationContext.xml");
    StuDao stuDao = (StuDao) app.getBean("stuDaoProxy");
    stuDao.save();
    stuDao.modify();
    stuDao.delete();
}

运行结果

转载于:https://www.cnblogs.com/jpwz/p/10567481.html

相关文章:

  • html迪士尼网页实现代码
  • HDU 2159 FATE
  • es 基于match_phrase/fuzzy的模糊匹配原理及使用
  • spring_事務
  • ASP.NET Core OData now Available
  • 01背包 完全背包 算法解析
  • 解决任务计划程序未启动任务,因为相同任务的实例正在运行的问题
  • 关于oracle的一些函数(数字、字符、转换、空值)
  • 安卓开发笔记(十五):编写一款能够查看任意网站源代码的应用程序
  • Spring拓展接口之FactoryBean,我们来看看其源码实现
  • 王者荣耀刷金币小程序
  • Linux学习之文件系统权限及表示
  • js经典面试题
  • data parameter is nil 异常处理
  • 面试岗位要求
  • “Material Design”设计规范在 ComponentOne For WinForm 的全新尝试!
  • 【跃迁之路】【585天】程序员高效学习方法论探索系列(实验阶段342-2018.09.13)...
  • angular学习第一篇-----环境搭建
  • CSS实用技巧干货
  • Cumulo 的 ClojureScript 模块已经成型
  • Less 日常用法
  • MySQL Access denied for user 'root'@'localhost' 解决方法
  • Octave 入门
  • tweak 支持第三方库
  • Vue实战(四)登录/注册页的实现
  • Zepto.js源码学习之二
  • 编写高质量JavaScript代码之并发
  • 基于axios的vue插件,让http请求更简单
  • 小李飞刀:SQL题目刷起来!
  • 翻译 | The Principles of OOD 面向对象设计原则
  • ​直流电和交流电有什么区别为什么这个时候又要变成直流电呢?交流转换到直流(整流器)直流变交流(逆变器)​
  • #单片机(TB6600驱动42步进电机)
  • (0)Nginx 功能特性
  • (02)Hive SQL编译成MapReduce任务的过程
  • (02)vite环境变量配置
  • (14)目标检测_SSD训练代码基于pytorch搭建代码
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (windows2012共享文件夹和防火墙设置
  • (多级缓存)缓存同步
  • (二十三)Flask之高频面试点
  • (六)vue-router+UI组件库
  • (转)h264中avc和flv数据的解析
  • (轉貼) 2008 Altera 亞洲創新大賽 台灣學生成果傲視全球 [照片花絮] (SOC) (News)
  • (自适应手机端)响应式新闻博客知识类pbootcms网站模板 自媒体运营博客网站源码下载
  • .form文件_一篇文章学会文件上传
  • .gitignore
  • .w文件怎么转成html文件,使用pandoc进行Word与Markdown文件转化
  • @RestControllerAdvice异常统一处理类失效原因
  • [.net 面向对象程序设计进阶] (19) 异步(Asynchronous) 使用异步创建快速响应和可伸缩性的应用程序...
  • [AI]文心一言出圈的同时,NLP处理下的ChatGPT-4.5最新资讯
  • [Android Pro] listView和GridView的item设置的高度和宽度不起作用
  • [Android] Upload package to device fails #2720
  • [AX]AX2012 AIF(四):文档服务应用实例
  • [BUG] Hadoop-3.3.4集群yarn管理页面子队列不显示任务
  • [C++提高编程](三):STL初识