javascript
Spring-AOP 通过配置文件实现 引介增强
- 概述
- 實例
概述
引介增強是一種比較特殊的增強類型,它不是在目標方法周圍織入增強,而是為目標創建新的方法和屬性,所以它的連接點是類級別的而非方法級別的。
通過引介增強我們可以為目標類添加一個接口的實現即原來目標類未實現某個接口,那么通過引介增強可以為目標類創建實現某接口的代理。
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 通过配置文件实现 引介增强的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Spring-AOP 通过配置文件实现
- 下一篇: gradle idea java ssm