AOP とは
#AOP (アスペクト指向プログラミング) はアスペクト指向プログラミングであり、プリコンパイルと実行時の動的プロキシを通じてプログラム機能を実現する、伝統的に維持されているテクノロジです。 AOP の機能と利点機能: プログラムの実行中に、ソース コードを変更せずに一部のメソッドを機能拡張できます利点: 重複コードを削減します。開発効率の向上とメンテナンスの容易化一般的なダイナミック プロキシ テクノロジjdk プロキシ: インターフェイス ベースのダイナミック プロキシ テクノロジ- リスト項目 - ターゲット (ターゲット オブジェクト): プロキシ ターゲット オブジェクト
- Proxy (プロキシ): AOP による拡張機能にクラスが組み込まれた後、結果として得られるプロキシ クラス
- Joinpoint (接続ポイント): 接続ポイントはインターセプトされたポイントです。 Spring では、Spring はメソッド タイプの接続ポイントのみをサポートするため、これらのポイントはメソッドを参照します (拡張できるメソッドは接続ポイントと呼ばれます)
- PointCut (ポイントカット): ポイントカットどのジョインポイントをインターセプトするかの定義 #アドバイス (通知/拡張): 通知とは、ジョインポイントをインターセプトした後に行う必要があることを指します。通知
-
#ウィービング (ウィービング): ターゲット オブジェクトに拡張機能を適用して、新しいプロキシ オブジェクトを作成するプロセス。 Spring は動的プロキシ ウィービングを使用しますが、AspectJ はコンパイラ ウィービングとクラス ローダー ウィービングを使用します。
実装
ここではアノテーション ベースの AOP 開発を使用します。
開発手順
依存関係の追加
<!--引入AOP依赖--> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <!--AOP--> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjrt</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency> <dependency> <groupId>cglib</groupId> <artifactId>cglib</artifactId> <version>3.2.12</version> </dependency>
ターゲット インターフェイスとターゲット クラスの作成 (内部カット ポイントあり)
アスペクト クラスの作成 (内部拡張あり)メソッド)
ターゲット クラスとアスペクト クラスのオブジェクト作成権限を Spirng に任せる
アノテーションを使用してアスペクト クラスのウィービング関係を構成する
コンポーネント スキャンと AOP を有効にする構成ファイル内 自動プロキシ
#私のプロジェクトは SpringBoot Web プロジェクトであるため、ここで注釈を有効にするだけです。次のコードは、使用されるアトミック カウンティング クラスです。
import java.util.concurrent.atomic.AtomicInteger; public class AtomicCounter { private static final AtomicCounter atomicCounter = new AtomicCounter(); /** * 单例,不允许外界主动实例化 */ private AtomicCounter() { } public static AtomicCounter getInstance() { return atomicCounter; } private static AtomicInteger counter = new AtomicInteger(); public int getValue() { return counter.get(); } public int increase() { return counter.incrementAndGet(); } public int decrease() { return counter.decrementAndGet(); } // 清零 public void toZero(){ counter.set(0); } }
次のコードは、実装されたグローバル インターフェイス監視です。
プロジェクト内のキャッシュに Redis を使用しているだけで、Redis 関連の操作がすべて表示されます。
@Before を使用して事前通知を構成します。拡張メソッドがポイントカット メソッドの前に実行されるように指定します。
@ @AfterReturning を使用して投稿通知を構成します。拡張メソッドがポイントカット メソッドの後に実行されるように指定します。
@ @AfterThrowing を使用して、例外スロー通知を構成します。例外が発生したときに拡張メソッドが実行されるように指定します。
@Component @Aspect public class GlobalActuator { private static final Logger log = LoggerFactory.getLogger(GlobalActuator.class); @Resource private StringRedisTemplate stringRedisTemplate; ThreadLocal<Long> startTime = new ThreadLocal<>(); ConcurrentHashMap<Object, Object> countMap = new ConcurrentHashMap<Object, Object>(); /** * 匹配控制层层通知 这里监控controller下的所有接口 */ @Pointcut("execution(* com.sf.controller.*Controller.*(..))") private void controllerPt() { } /** * 在接口原有的方法执行前,将会首先执行此处的代码 */ @Before("com.sf.actuator.GlobalActuator.controllerPt()") public void doBefore(JoinPoint joinPoint) throws Throwable { startTime.set(System.currentTimeMillis()); //获取传入目标方法的参数 Object[] args = joinPoint.getArgs(); } /** * 只有正常返回才会执行此方法 * 如果程序执行失败,则不执行此方法 */ @AfterReturning(returning = "returnVal", pointcut = "com.sf.actuator.GlobalActuator.controllerPt()") public void doAfterReturning(JoinPoint joinPoint, Object returnVal) throws Throwable { Signature signature = joinPoint.getSignature(); String declaringName = signature.getDeclaringTypeName(); String methodName = signature.getName(); String mapKey = declaringName + methodName; // 执行成功则计数加一 int increase = AtomicCounter.getInstance().increase(); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); synchronized (this) { //在项目启动时,需要在Redis中读取原有的接口请求次数 if (countMap.size() == 0) { JSONObject jsonObject = RedisUtils.objFromRedis(StringConst.INTERFACE_ACTUATOR); if (jsonObject != null) { Set<String> strings = jsonObject.keySet(); for (String string : strings) { Object o = jsonObject.get(string); countMap.putIfAbsent(string, o); } } } } // 如果此次访问的接口不在countMap,放入countMap countMap.putIfAbsent(mapKey, 0); countMap.compute(mapKey, (key, value) -> (Integer) value + 1); synchronized (this) { // 内存计数达到30 更新redis if (increase == 30) { RedisUtils.objToRedis(StringConst.INTERFACE_ACTUATOR, countMap, Constants.AVA_REDIS_TIMEOUT); //删除过期时间 stringRedisTemplate.persist(StringConst.INTERFACE_ACTUATOR); //计数器置为0 AtomicCounter.getInstance().toZero(); } } //log.info("方法执行次数:" + mapKey + "------>" + countMap.get(mapKey)); //log.info("URI:[{}], 耗费时间:[{}] ms", request.getRequestURI(), System.currentTimeMillis() - startTime.get()); } /** * 当接口报错时执行此方法 */ @AfterThrowing(pointcut = "com.sf.actuator.GlobalActuator.controllerPt()") public void doAfterThrowing(JoinPoint joinPoint) { HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest(); log.info("接口访问失败,URI:[{}], 耗费时间:[{}] ms", request.getRequestURI(), System.currentTimeMillis() - startTime.get()); } }
コントローラ層のコードをここに示します。
@GetMapping("/interface/{intCount}") @ApiOperation(value = "查找接口成功访问次数(默认倒序)") public Result<List<InterfaceDto>> findInterfaceCount( @ApiParam(name = "intCount", value = "需要的接口数") @PathVariable Integer intCount ) { HashMap<String, Integer> hashMap = new HashMap<>(); JSONObject jsonObject = RedisUtils.objFromRedis(StringConst.INTERFACE_ACTUATOR); if (jsonObject != null) { Set<String> strings = jsonObject.keySet(); for (String string : strings) { Integer o = (Integer) jsonObject.get(string); hashMap.putIfAbsent(string, o); } } //根据value倒序 Map<String, Integer> sortedMap = hashMap.entrySet().stream().sorted(Collections.reverseOrder(Map.Entry.comparingByValue())) .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (e1, e2) -> e1, LinkedHashMap::new)); //返回列表 List<InterfaceDto> resultList = new ArrayList<>(); //排序后中的map中所有的key Object[] objects = sortedMap.keySet().toArray(); for (int i = 0; i < intCount; i++) { InterfaceDto interfaceDto = new InterfaceDto(); interfaceDto.setName((String) objects[i]); interfaceDto.setCount(sortedMap.get((String) objects[i])); resultList.add(interfaceDto); } return Result.success(resultList); }
プロジェクトが一定期間実行されると、Redis のインターフェイスに対するリクエストの数を確認できます。
Web の最終的なレンダリングは次のとおりです:以上がSpringBoot が AOP を使用してグローバル インターフェイスの訪問数をカウントする方法の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SecLists
SecLists は、セキュリティ テスターの究極の相棒です。これは、セキュリティ評価中に頻繁に使用されるさまざまな種類のリストを 1 か所にまとめたものです。 SecLists は、セキュリティ テスターが必要とする可能性のあるすべてのリストを便利に提供することで、セキュリティ テストをより効率的かつ生産的にするのに役立ちます。リストの種類には、ユーザー名、パスワード、URL、ファジング ペイロード、機密データ パターン、Web シェルなどが含まれます。テスターはこのリポジトリを新しいテスト マシンにプルするだけで、必要なあらゆる種類のリストにアクセスできるようになります。

PhpStorm Mac バージョン
最新(2018.2.1)のプロフェッショナル向けPHP統合開発ツール

AtomエディタMac版ダウンロード
最も人気のあるオープンソースエディター

ZendStudio 13.5.1 Mac
強力な PHP 統合開発環境
