実践的な AOP 責任チェーンの実装
AOP の簡単な紹介
Spring の 2 つの重要な機能のうちの 1 つである AOP は、アスペクト指向プログラミングです。
その機能は単に、クラス自体のコードを変更することなく、プロキシ クラスを通じてデカップリングを実現し、機能強化を実現できるということです。これで何ができるかを理解することで、実装方法を考えることができます。ここには、責任の連鎖モデルが含まれます (詳細はこちら)後で)。
単純な AOP を実装するには、少なくとも次のことを行う必要があります。
- ターゲットクラスがある
- 動的プロキシのターゲットクラス
- カスタム通知方法
AOP を実装する前に、デモで予期しないバグが発生しないように、前提条件の知識を簡単に確認し、確認する前に使用されている依存関係とバージョンを確認する必要があります。
Javaバージョン:1.8
Maven バージョン: 3.6.x
頼る
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.6.RELEASE</version>
</dependency>
ダイナミックプロキシ(プロキシターゲットクラス)
エージェントを理解するには、エージェントに関する知識を復習する必要があります。
現在、エージェントには 2 種類あり、静的エージェントと動的エージェントは言葉で簡単に説明できます。
- 静的プロキシはプロキシを実装できますが、抽象クラスに限定されており、抽象クラス以外のオブジェクトをプロキシすることはできません。
- 動的プロキシは、リフレクション メカニズムに依存して、任意のクラスのプロキシを実装します。
ターゲットクラスの作成
Userservice
プロキシターゲットクラスとして使用します
public class UserService {
public Object insert ()
{
System.out.println("==插入用户成功==");
return "user insert ok";
}
}
プロキシファクトリーを作成する
ここではダイナミック プロキシとして cglib を使用していますが、実際にはダイナミック プロキシのサポート クラスを実装することで、簡単な AOP 拡張を実現できます。
コード例
public class ProxyFactory implements MethodInterceptor {
private Object target;
public UserService getProxy(Object target){
//被代理对象
this.target = target;
//cglib 生成代理对象
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置回调
enhancer.setCallback(this);
//设置类加载器
enhancer.setClassLoader(target.getClass().getClassLoader());
//生成代理对象
return (UserService)enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//执行目标方法
Object result = null;
try {
//前置通知
System.out.println("前置通知");
result = method.invoke(target, objects);
// 返回通知
System.out.println("返回通知");
} catch (Throwable e) {
//异常通知
System.out.println("异常通知");
throw new RuntimeException(e);
} finally {
// 后置通知
System.out.println("后置通知");
}
return result;
}
}
テスト
public class Run {
public static void main(String[] args) {
UserService userService = new UserService();
userService.insert();
UserService userService1 = new ProxyFactory().getProxy(userService);
userService1.insert();
}
}
コメントでマークされた場所にコードを追加する限り、それは単純なアスペクト拡張ですか? この時点で、考慮する必要がある問題があります。ラベル付けの場合に、Spring で使用する AOP について考えてください。アスペクトとアノテーションの強化。Spring はアスペクトの強化を実現するのに役立ちます。
これはほんの始まりにすぎません。AOP を使用するときの分離の目的は何ですか? 上記のケースをこのように書きたい場合、他の人を騙すことになるのではないでしょうか? このクラスはエージェント ファクトリを分離し、結合度が高くなります。では全く効果が得られませんので、次はこの問題を解決していきます
- 柔軟性を提供する
- デカップリング
- デザインパターンを使用して問題を解決できるでしょうか?
責任連鎖モデル
私たちは、デザイン パターンを使用して、独自のデモ AOP の柔軟性を高めたいと考えています。ここでは、責任連鎖モデルについて簡単に紹介します。
リクエスト送信者が複数のリクエスト ハンドラと結合されるのを避けるために、すべてのリクエスト ハンドラは、前のオブジェクトから次のオブジェクトへの参照を記憶することによってチェーンで接続されます。リクエストが発生すると、このチェーンに沿ってリクエストをリンクできます。オブジェクトが処理するまで渡されます。
PS: 再帰
それでは、責任連鎖モデルの実装の構造はどのようなものでしょうか?
ここでは、責任連鎖モデルを開始するというアイデアを示すために事前拡張を実装します。
責任の連鎖
再帰を使用して通知を継続的に呼び出します
public class Chian {
//记录index下标
private int index= -1;
private List<BaseAdvice> adviceList;
public Chian(List<BaseAdvice> adviceList) {
this.adviceList = adviceList;
}
public Object proeccd() throws Throwable{
if(index == adviceList.size()-1){
System.out.println("==执行目标方法==");
return null;
}
return adviceList.get(++index).execute(this);
}
}
拡張された通知基本クラス
public abstract class BaseAdvice {
public abstract Object execute(Chian chian) throws Throwable;
}
強化前クラス
public class BeforeAdvice extends BaseAdvice{
@Override
public Object execute(Chian chian) throws Throwable {
/*
* 只做逻辑增强
* 如果还有继续调用链的下一个通知
* */
System.out.println("前置通知");
//调用链通知
return chian.proeccd();
}
}
テスト
public static void main(String[] args) throws Throwable {
List<BaseAdvice> adviceList = new ArrayList<>();
adviceList.add(new BeforeAdvice());
Chian chian = new Chian(adviceList);
chian.proeccd();
}
結果は以前のプロキシ方法の結果と一致しており、チェーン呼び出し + 再帰によってターゲットの分離が完了し、柔軟性が向上していることがわかります。
AOPの実装
強化された実装
サラウンドは他の拡張の組み合わせと同等であるため、4 つの拡張はここではサラウンド拡張を実装しません。
基本クラス
public abstract class BaseAdvice {
public abstract Object execute(Chian chian) throws Throwable;
}
4種類の強化
強化前
public class BeforeAdvice extends BaseAdvice{
@Override
public Object execute(Chian chian) throws Throwable {
/*
* 只做逻辑增强
* 如果还有继续调用链的下一个通知
* */
System.out.println("前置通知(责任链)");
//调用链通知
return chian.proeccd();
}
}
強化後
public class AfterAdvice extends BaseAdvice{
@Override
public Object execute(Chian chian) throws Throwable {
try {
return chian.proeccd();
} finally {
System.out.println("后置增强");
}
}
}
例外処理の強化
public class ThrowAdvice extends BaseAdvice{
@Override
public Object execute(Chian chian) throws Throwable {
try {
return chian.proeccd();
} catch (Throwable e) {
System.out.println("异常通知");
throw new RuntimeException(e);
}
}
}
拡張通知の処理に戻る
public class ReturnAdvice extends BaseAdvice{
@Override
public Object execute(Chian chian) throws Throwable {
//如果没有异常就走返回通知
Object value = chian.proeccd();
System.out.println("返回通知");
return value;
}
}
責任連鎖の実装
リンク リスト + 再帰を使用して責任の連鎖を実装し、リンク リスト データ構造の特性を使用してノード調整ポイントの実行を強化します。
public class Chian {
//记录index下标
private int index= -1;
private List<BaseAdvice> adviceList;
//目标方法
private Method method;
//方法参数
private Object[] args;
//目标对象
private Object target;
public Chian(List<BaseAdvice> adviceList) {
this.adviceList = adviceList;
}
public Chian(List<BaseAdvice> adviceList, Method method, Object[] args, Object target) {
this.adviceList = adviceList;
this.method = method;
this.args = args;
this.target = target;
}
public Object proeccd() throws Throwable{
if(index == adviceList.size()-1){
return method.invoke(args,target);
}
return adviceList.get(++index).execute(this);
}
}
エージェントクラスの実装
public class ProxyFactoryAddChian implements MethodInterceptor {
private Object target;
private List<BaseAdvice> adviceList;
public ProxyFactoryAddChian() {
adviceList = new ArrayList<>();
adviceList.add(new BeforeAdvice());
adviceList.add(new ReturnAdvice());
adviceList.add(new AfterAdvice());
adviceList.add(new ThrowAdvice());
}
public UserService getProxy(Object target){
//被代理对象
this.target = target;
//cglib 生成代理对象
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置回调
enhancer.setCallback(this);
//设置类加载器
enhancer.setClassLoader(target.getClass().getClassLoader());
//生成代理对象
return (UserService)enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//在生产代理的时候就把链设置好
Chian chian = new Chian(adviceList,method,objects,target);
return chian.proeccd();
}
}
テスト
public class Run {
public static void main(String[] args) throws Throwable {
UserService userService = new UserService();
//userService.insert();
UserService userService1 = new ProxyFactoryAddChian().getProxy(userService);
userService1.insert("编程导航小冷Demo");
}
}
要約する
拡張機能を実装するには、出力ステートメントの位置を実装したいコードに置き換えるだけです。少し疑わしいように思えるかもしれません。これは Spring の AOP とまったく同じではありません。AOP の一部には IOC が含まれるためです。しかし、それは以前にiocを実装したことがあるのは偶然です
このシリーズがうまく更新されれば、後で小さな Spring を作成してみることができます。Xiao Lengと一緒にSpringのソースコードを読み、自分のアイデアで実装する方法を考えてください。
では、この実践的な責任連鎖の実践から私たちは何を学んだのでしょうか?
- 責任連鎖モデルの適用
- 再帰の使用
- 優れたフレームワークのソースコードのアイデアを学ぶ
- 中途半端な AOP デモを入手する
皆様もこれからもシャオ・レンの技術記事を読んで、一緒に進歩していきたいと思います。
ご覧いただきありがとうございます、次の記事もお楽しみに