• 概述
  • 实例

概述

引介增强是一种比较特殊的增强类型,它不是在目标方法周围织入增强,而是为目标创建新的方法和属性,所以它的连接点是类级别的而非方法级别的。

通过引介增强我们可以为目标类添加一个接口的实现即原来目标类未实现某个接口,那么通过引介增强可以为目标类创建实现某接口的代理。

Spring定义了引介增强接口IntroductionInterceptor,该接口没有定义任何方法

Spring为该接口提供了DelegatingIntroductionInterceptor实现类,一般情况下,通过扩展该实现类定义自己的引介增强类。


实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster

我们一直使用的性能检测的例子。 开启监控会影响业务系统的性能,我们可以设置是否启用性能监视为可控的,那我们改如何使用引介增强实现这一个诱人的功能呢?

我们创建一个示例来演示下,步骤如下:
创建接口类:Monitorable.java
创建业务类:PerformanceMonitor.java
创建增强类:ControllablePerformanceMonitor.java
创建配置文件:conf-advice.xml
创建增强测试类:DelegatingTest.java

接口类:Monitorable.java

package com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor;public interface Monitorable {void setMonitorActive(boolean active);
}

该接扣仅包含一个setMonitorActive方法,我们希望通过该接口方法控制业务类性能监视功能的激活和关闭状态

接下来创建业务类

package com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor;public class PerformanceMonitor {private static ThreadLocal<MethodPerformace> performaceRecord = new ThreadLocal<MethodPerformace>();public static void begin(String method) {System.out.println("begin monitor...");MethodPerformace mp = performaceRecord.get();if (mp == null) {mp = new MethodPerformace(method);performaceRecord.set(mp);} else {mp.reset(method);}}public static void end() {System.out.println("end monitor...");MethodPerformace mp = performaceRecord.get();mp.printPerformace();}
}

接下来创建增强类ControllablePerformanceMonitor

package com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor;import org.aopalliance.intercept.MethodInvocation;
import org.springframework.aop.support.DelegatingIntroductionInterceptor;public class ControllablePerformaceMonitor extendsDelegatingIntroductionInterceptor implements Monitorable {private static final long serialVersionUID = 1L;// 定义ThreadLocal类型的变量,用于保存性能监视开关状态。 为了解决单实例线程安全的问题,通过ThreadLocal// 让每个线程单独使用一个状态private ThreadLocal<Boolean> MonitorStatusMap = new ThreadLocal<Boolean>();@Overridepublic void setMonitorActive(boolean active) {MonitorStatusMap.set(active);}/*** 拦截方法*/@Overridepublic Object invoke(MethodInvocation mi) throws Throwable {Object obj = null;// 对于支持新跟那个监视可控代理,通过判断其状态决定是否开启性能监控功能// Java5.0的自动拆包功能,get方法返回的Boolean被自动拆包为boolean类型的值if (MonitorStatusMap.get() != null && MonitorStatusMap.get()) {PerformanceMonitor.begin(mi.getClass().getName() + "."+ mi.getMethod().getName());obj = super.invoke(mi);PerformanceMonitor.end();} else {obj = super.invoke(mi);}return obj;}}

接下来创建所要增强的方法类

package com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor;public class ForumService {public void removeTopic(int topicId) {System.out.println("模拟删除Topic记录:" + topicId);try {Thread.currentThread().sleep((long) (Math.random() * 1000 * 20));} catch (Exception e) {throw new RuntimeException(e);}}public void removeForum(int forumId) {System.out.println("模拟删除Forum记录:" + forumId);try {Thread.currentThread().sleep((long) (Math.random() * 1000 * 20));} catch (Exception e) {throw new RuntimeException(e);}}
}
package com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor;public class MethodPerformace {private long begin;private long end;private String serviceMethod;public MethodPerformace(String serviceMethod) {reset(serviceMethod);}public void printPerformace() {end = System.currentTimeMillis();long elapse = end - begin;System.out.println(serviceMethod + "花费" + elapse + "毫秒。");}public void reset(String serviceMethod) {this.serviceMethod = serviceMethod;this.begin = System.currentTimeMillis();}
}

创建配置文件来将所设置的代码组合起来

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd"><bean id="pmonitor"class="com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor.ControllablePerformaceMonitor" /><bean id="forumServiceTarget" class="com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor.ForumService" /><bean id="forumService" class="org.springframework.aop.framework.ProxyFactoryBean"p:interfaces="com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor.Monitorable"p:target-ref="forumServiceTarget" p:interceptorNames="pmonitor"p:proxyTargetClass="true" /></beans>

引介增强的配置和一般配置有较大的区别,

  • 首先需要指定引介增强所实现的接口 ,如 p:interfaces ,这里的引介增强实现了Monitorable接口。
  • 其次,由于只能通过为目标类创建子类的方式生成引介增强的代理,所以必须将 p:proxyTargetClass=”true”

如果没有对ControllablePerformaceMonitor进行线程安全的处理,就必须将singleton属性设置为false, 让ProxyFactoryBean产生prototype的作用域类型的代理。 这里就带来了一个严重的性能问题,因为cglib动态创建代理的性能很低,而每次getBean方法从容器中获取作用域为prototype的Bean时都将返回一个新的代理实例,所以这种影响是巨大的,这也是为什么通过ThreadLocal对ControllablePerformaceMonitor的开关进行线程安全化处理的原因。 通过线程安全处理后,就可以使用默认的singleton Bean作用域,这样创建代理的动作仅发生一次。

创建对应的测试类

package com.xgj.aop.spring.advice.DelegatingIntroductionInterceptor;import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class DelegatingTest {@Testpublic void test() {ApplicationContext ctx = new ClassPathXmlApplicationContext("classpath:com/xgj/aop/spring/advice/DelegatingIntroductionInterceptor/conf-advice.xml");ForumService forumService = (ForumService) ctx.getBean("forumService");forumService.removeForum(10);forumService.removeTopic(1022);Monitorable moniterable = (Monitorable) forumService;moniterable.setMonitorActive(true);forumService.removeForum(10);forumService.removeTopic(1022);}
}

运行结果


Spring-AOP 通过配置文件实现 引介增强相关推荐

  1. android aop静态方法,spring aop 不能对静态方法进行增强解决

    想要通过aop的方式记录HttpUtils发出的post请求日志,但是 aop 不能对静态方法进行增强.只能对实例方法进行增强.. 如果一定要增强静态方法,我们可以对目标类使用单例模式,然后通过调用实 ...

  2. Spring AOP 标签形式及Around增强处理

    上一篇文章介绍了下Spring中的AOP xml配置方式.想了解的同学可以点击这里查看. 这次写一下标签形式. <aop:aspectj-autoproxy /> 首先要在spring配置 ...

  3. spring aop代码的增强

    这篇博客,主要会分析spring aop是如何实现代码增强的. 从上一篇博客 我们大概知道,spring能在不改变代码的前提下,往一个方法的之前和之后添加代码. 想下,java中有哪种技术可以帮我们实 ...

  4. Spring AOP源码解析——AOP动态代理原理和实现方式

    2019独角兽企业重金招聘Python工程师标准>>> Spring介绍 Spring(http://spring.io/)是一个轻量级的Java 开发框架,同时也是轻量级的IoC和 ...

  5. Spring AOP 切点 Pointcut 表达式介绍与使用

    一.前言 面向切面编程 AOP 是一种常见的编程思想,是面向对象编程的一种补充,AOP 框架通过修改源代码,将处理逻辑编织到指定的业务模块中 常见的处理比如:在方执行法前进行校验,在方法执行后进行日志 ...

  6. java aop管理权限_基于spring aop 权限管理系统原型 - andyj2ee - BlogJava

    此权限管理系统把待访问的业务层方法做为权限管理中的资源,通过spring aop 对接口方法进行拦截,来实现权限的管理,可以实现细粒度的权限控制. 在上文体验了spring aop 一些特性,aop ...

  7. Spring AOP中是如何注册Advisor的?

    前置博文: Spring AOP中如何为Bean创建代理? Spring AOP中是如何注册Advisor的? Spring AOP如何为目标方法创建拦截器链? Spring AOP拦截器调用的实现 ...

  8. 跟着小马哥学系列之 Spring AOP(基于 XML 定义 Advice 源码解析)

    学好路更宽,钱多少加班. --小马哥 简介 大家好,我是小马哥成千上万粉丝中的一员!2019年8月有幸在叩丁狼教育举办的猿圈活动中知道有这么一位大咖,从此结下了不解之缘!此系列在多次学习极客时间< ...

  9. Spring AOP增强(Advice)

    Sring AOP通过PointCut来指定在那些类的那些方法上织入横切逻辑,通过Advice来指定在切点上具体做什么事情.如方法前做什么,方法后做什么,抛出异常做什么. 再来看一下图 定义Point ...

最新文章

  1. selenium+python自动化84-chrome手机wap模式
  2. Pytorch-使用Bert预训练模型微调中文文本分类
  3. 用 Gearman 分发 PHP 应用程序的工作负载
  4. 横屏展示 fragment 监听面积并非全屏,部分面积监听失效
  5. [原创]K8_C段旁注工具6.0 新增SMB漏洞扫描
  6. 撤销前进快捷键_电脑win7系统的快捷键大全
  7. 管理感悟:就事不论事
  8. 58同城推荐系统设计与实现
  9. matlab2007教学,MATLABR2007 matlab基础教程 - 下载 - 搜珍网
  10. AD采样SPS和计算能采的频率
  11. 力扣HOT100题代码
  12. 黑苹果,Win7,Win10,Xp 各个系统镜像文件下载地址(备用)
  13. 产品经理相关学习资料
  14. 破解/忘记Win7密码
  15. nio中的Files类常用方法
  16. 爱奇艺播放技术——300ms背后的故事
  17. VI 之快速查找定位
  18. vue : 无法加载文件 C:\Users\lenovo\AppData\Roaming\npm\vue.ps1,因为在此系统上禁止运行脚本。解决方法
  19. K8S kube-scheduler-master CreateContainerError 问题解决及思路
  20. 不负春光不负卿,听康大厨讲讲OpenStack重要组件的那些事儿

热门文章

  1. 未来已来 -只是尚未流行
  2. Linux下CMake简明教程(一)简单入门
  3. 重温强化学习之强化学习简介
  4. 强化学习(三)---马尔科夫决策过程
  5. MAS 714 笔记20:规约和SAT
  6. MATLAB从入门到精通:MATLAB矩阵操作
  7. 经典!MATLAB线性等分linspace()函数,精确等分点数
  8. Tableau必知必会之学做一个实用的热图日历
  9. RIPPER算法原理
  10. 抽取样本java实验报告_一个自定义classloader的函数抽取壳样本