ワン:はじめに
アスペクト指向プログラミングは、あなたが維持しやすいプログラムを書きたい、とAOPの実際のプログラミング合理的な使用でAOPを理解するように訓練することができ、非常に重要な概念の考えである必要であると考えています
2:AOPの基本的な考え方
基础概念:AOP中文翻译面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
3:動的なプロキシを介して達成するためにAOP
AOPを実現するために上記の概念を読んだ後、AOPが何であるかを知らないかもしれないが、我々は、上記の技術的基盤の概念から少しだけ知っている、プリコンパイルおよび実行時の動的ウェイエージェントその後、我々は実際のコードに来ては、動的プロキシを使用することによって実現され、簡単なプログラムも
私たちは、日常のオブジェクト指向プログラミングでは、このようなシーンが多いが発生します。
クラスB(ログクラスロガー)を呼び出す(にClassA以下)クラスメソッドの数が同じ時間になければならないのと同じ方法をされている
次のとおりです。
public class ClassA{
public Logger logger;
public ClassA(){
logger=new Logger();
}
public void AFuncA(){
//....做一些其他事情
System.out.println("AFuncA做一些其他事情");
//记录日志
logger.WriteLog();
}
public void AFuncB(){
//....做一些其他事情
System.out.println("AFuncB做一些其他事情");
//记录日志
logger.WriteLog();
}
public void AFuncC(){
//....做一些其他事情
System.out.println("AFuncC做一些其他事情");
//记录日志
logger.WriteLog();
}
}
/*
* 日志类
*/
public class Logger{
public void WriteLog(){
System.out.println("我是工具类Logger的WriteLog方法,我记录了日志"));
}
}
/*
*单元测试Main方法
*/
@Test
public void TestMain(){
ClassA classa=new ClassA();
classa.AFuncA();
classa.AFuncB();
classa.AFuncC();
}
出力
この単純なサンプルコードは、少し上のJava、C#とNengkanmingbaiの人々基づいて、他のオブジェクト指向言語で、私たちはクラスにClassA書いたことを信じて、その後にClassAの三つの方法がロガーのWRITELOGと呼ばれているユーティリティクラスClassBのは、カプセル化()メソッド。
私たちは地元のプロジェクトの数百人が、コードを変更し、すべてのログをキャンセルし、もはや私たちはこのロギングクラスを交換したいと、ログにこのWRITELOG()メソッドを使用したりしている持っていない場合は、この設計は、明らかに、欠陥があります非常に動揺され、明らかにClassAクラスLoggerクラスは、我々はアスペクト指向プログラミングを引く必要があり、この問題を解決するために、我々はロガー上でこのクラスにClassA依存性を最適化しないか、それを持ち上げるために、コードのカップリングに頼らなければなりませんでしたアイデアの(AOP)。
最適化のコードは次のとおりです。我々は、動的プロキシファクトリオブジェクトのDynAgentFactoryを作成することができ、その後、動的プロキシオブジェクトに基づくエンハンサーサブクラス(CGLIBの依存関係をインポートする必要がある)にClassAプロキシオブジェクトに、そのオブジェクトが使用中にClassAにClassAに直接インスタンス化されていませんが、ファクトリオブジェクトDynAgentFactoryにClassAクラスを呼び出すために、エージェントをコールします
特定の最適化のコードは次のとおりです。
public class ClassA{
public void AFuncA(){
//....做一些其他事情
System.out.println("AFuncA做一些其他事情");
}
public void AFuncB(){
//....做一些其他事情
System.out.println("AFuncB做一些其他事情");
}
public void AFuncC(){
//....做一些其他事情
System.out.println("AFuncC做一些其他事情");
}
//.....
}
/*
*动态代理工厂
*/
public class DynAgentFactory {
private ClassA proClassA;
private Logger logger;
public DynAgentFactory(){
AFunAgent();
GetLogger();
}
public ClassA GetClassA(){
return proClassA;
}
public Logger GetLogger(){
logger=new Logger();
return logger;
}
/*
*代理ClassA对象
*此处Enhancer类是基于子类的动态代理对象,需要导入cglib依赖(也可以定义一个接口,然后用Proxy实现基于接口的动态代理)
*/
public void AFunAgent(){
ClassA classA=new ClassA();
proClassA=(ClassA) Enhancer.create(classA.getClass(), new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object obj=method.invoke(classA);
logger.WriteLog();
return obj;
}
});
}
}
/*
* 日志类
*/
public class Logger
{
public void WriteLog(){
System.out.println("我是工具类Logger的WriteLog方法,我记录了日志");
}
}
/*
*单元测试Main方法
*/
@Test
public void TestMain(){
DynAgentFactory dynAgentFactory=new DynAgentFactory();
dynAgentFactory.GetClassA().AFuncA();
dynAgentFactory.GetClassA().AFuncB();
dynAgentFactory.GetClassA().AFuncC();
}
出力と前と同じ
我々は、我々は将来的には、削除したり、Loggerクラスのログを交換したい場合は、にClassAとロガークラスを切り離す達成した動的プロキシファクトリオブジェクトのDynAgentFactoryを通じて見ることができる、唯一の非常に、LoggerオブジェクトにDynAgentFactoryの統一事業に必要のにClassAの公開部分に引き出さこの概念は言った前:実行時の動的プロキシ
上記のコードは完璧されているかどうか?実際には、プロジェクトの緩やかな拡大に伴い、我々は新しいClassBの、クラスCを追加していく予定もしそうなら、いくつかの問題がにClassAの単にエージェントは、それが動的プロキシ工場を建設することであろうと、まだあります...このクラス統合ログを使用する必要がありますLoggerは、あなたがパンを使用することができ、我々はまた、このファクトリクラスDynAgentFactoryを最適化するために継続する必要があるので、それはAFunAgent、BFunAgentは、CFunAgentは、コード内で、まだ繰り返されていない上、それをログエージェントにBFunAgent、CFunAgentコードを書く繰り返す必要がありませんこの問題を解決するためのタイプ
/*
*ClassA代码同上,此处省略
*/
//....
/*
*新加入的ClassB
*/
public class ClassB{
public void BFuncA(){
//....做一些其他事情
System.out.println("BFuncA做一些其他事情");
}
public void BFuncB(){
//....做一些其他事情
System.out.println("BFuncB做一些其他事情");
}
public void BFuncC(){
//....做一些其他事情
System.out.println("BFuncC做一些其他事情");
}
//.....
}
/*
*泛型动态代理工厂
*/
public class DynAgentFactory<T> {
private Logger logger;
public DynAgentFactory(T _proClass){
TFunAgent(_proClass);
GetLogger();
}
private T proClass;
public T GetProClass(){
return proClass;
}
public Logger GetLogger(){
logger=new Logger();
return logger;
}
/*
*代理ClassA对象
*此处Enhancer类是基于子类的动态代理对象,需要导入cglib依赖(也可以定义一个接口,然后用Proxy实现基于接口的动态代理)
*T pro:传入依赖对象
*/
public void TFunAgent(T pro){
proClass=(T) Enhancer.create(pro.getClass(), new MethodInterceptor() {
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
Object obj=method.invoke(pro);
logger.WriteLog();
return obj;
}
});
}
}
/*
*日志类Logger代码同上,此处省略
*/
//...
/*
*单元测试Main方法
*/
@Test
public void TestMain(){
DynAgentFactory<ClassA> dynAgentFactory=new DynAgentFactory(new ClassA());
dynAgentFactory.GetProClass().AFuncA();
dynAgentFactory.GetProClass().AFuncB();
dynAgentFactory.GetProClass().AFuncC();
System.out.println("-------------------------------分割线------------------------------------------");
DynAgentFactory<ClassB> dynAgentFactory2=new DynAgentFactory(new ClassB());
dynAgentFactory2.GetProClass().BFuncA();
dynAgentFactory2.GetProClass().BFuncB();
dynAgentFactory2.GetProClass().BFuncC();
}
出力
あなたはLoggerクラスのロギングを使用する場合は、この更なる最適化の後、両方にClassA、ClassBのか、他のクラスは、DynAgentFactoryは、それに対応するプロキシオブジェクトを作成するために使用することができる
1時余談挿入こちら>:鍋にJava言語ので、型が完全にコンパイラによって実装され、JVMがここに任意のサポートを提供していませんC#は、この方法では、コンストラクタに注射によってインスタンス化オブジェクトに必要とされるたびに書かれたTトン=新しいT()をサポートしていますように、そうではありませんファクトリオブジェクトは、行くことにしました。
動的プロキシの概要
動的プロキシの技術では、より良い地球伐採上記に加えて、我々はまた、ユニバーサル・トランザクション機能のようないくつかの処理のフィルタを、行うためにそれを使用することができ、特異性を高めるために、コードの機能をコード間の結合を低減することができます動的プロキシを知るために、私たちは<AOP:{アドバイスNAME}>で見られる春のフレームワークを振り返ってみることができ、タグごとスプリングAOPのみ、動的プロキシであるとして、これらのタグは、より深い理解を持つことになりますされていませんしかし、次の<AOP:{アドバイスNAME}>で実行するプロキシの内訳は、後のばね要素はadivceで5のいずれかを宣言する
<aop:config>
<aop:aspect id="myAspect" ref="aBean">
<aop:pointcut id="businessService"
expression="execution(* com.xyz.myapp.service.*.*(..))"/>
<!-- a before advice definition -->
<aop:before pointcut-ref="businessService"
method="doRequiredTask"/>
<!-- an after advice definition -->
<aop:after pointcut-ref="businessService"
method="doRequiredTask"/>
<!-- an after-returning advice definition -->
<!--The doRequiredTask method must have parameter named retVal -->
<aop:after-returning pointcut-ref="businessService"
returning="retVal"
method="doRequiredTask"/>
<!-- an after-throwing advice definition -->
<!--The doRequiredTask method must have parameter named ex -->
<aop:after-throwing pointcut-ref="businessService"
throwing="ex"
method="doRequiredTask"/>
<!-- an around advice definition -->
<aop:around pointcut-ref="businessService"
method="doRequiredTask"/>
...
</aop:aspect>
</aop:config>
<bean id="aBean" class="...">
...
</bean>
3:拡張と要約
上記の単純な例では、我々が達成動的プロキシAOPを通じて学んだが、ここでは、AOPは、プログラミングのアイデアであることを、動的なAOPプロキシを介して達成されている知っている必要がありますが、我々はまた、AOPプリコンパイラによって達成することができ、達成するための唯一の方法でありますここでは、AspectJの直接コンパイル時にソースコード生成クラスを変更することができ、AspectJのアスペクト指向フレームワークについて言わなければなりません。
AspectJの?AspectJのもこの@AspectJことは何ですか
大いわゆるAspectJのの検索オンライン利用状況では、AspectJのは、実際に氷山AspectJのフレームワークの「文法セクション」先端あり、AspectJのは、プロジェクトのEclipseの春の打ち上げの存在を完全に独立している、AspectJの公式の説明は次のとおりです。
EclipseのAspectJのは、シームレスなアスペクト指向の拡張である Javaの™プログラミング言語。これは、習得しやすく使いやすい互換性のあるJavaプラットフォームです。
はい、AspectJのも独立した言語であると言うことができる、私たちはしばしば、この上で、ちょうどSpring2.0は依然として基本的に春のネイティブ実装のAspectJスタイル、それを使用した後@Aspect注釈と春に見ます春のポイントのマニュアルが記載されている:
Java 5のアノテーションを@AspectJの使用を、セクションでは、通常のJavaクラスとして宣言することができます。@AspectJスタイルは、AspectJの5リリースの一部としてのAspectJプロジェクトで導入されました。スプリング2.0とAspectJの5つの用途同じノート、ポイントカット解析及びマッチングのためのAspectJを使用します。しかし、実行時にAOPはまだ純粋な春AOPはAspectJのコンパイラやウィーバー(ウィーバー)に依存しない、です。
したがって、AspectJのは、ちょうどそれが物事の別のセットは完全に独立している、AspectJのスタイルだけでなく、AspectJのウィーバーの全範囲を使用し、当社の普通org.aspectj.lang.annotationパッケージにノートを関連しました。私はあまりにもプレーしていない再生する方法を特定については、Baiduのを所有することができ、小さな相手に興味を持っています