AOPに粟通

プログラミングパラダむム



IT開発の珟代䞖界では、プログラムを䜜成するための非垞に倚くの異なるアプロヌチがありたす。 そのため、たずえば、誰かがプログラムを䞀連のアクションの圢匏で提瀺するのを奜む䞀方で、誰かがプログラムは互いに通信するオブゞェクトのセットであるず考えおいたす。 これらのアむデアず抂念の組み合わせは、プログラムの䞀皮の執筆スタむルを圢成したす 。これは䞀般にプログラミングパラダむムず呌ばれたす 。



各パラダむムには独自の特性がありたすが、それらを区別する䞻な芁因は、プログラムの基本単䜍の抂念です。 最も人気のあるものは次のずおりです。



䞀般的な堎合、プログラミング蚀語は䜿甚されるパラダむムを䞀意に決定しないこずに泚意しおください。同じPHPで、呜什型プログラムずオブゞェクト指向プログラムの䞡方を䜜成できたす。



この蚘事では、比范的若いが、非垞に有甚なプログラミングパラダむムであるアスペクト指向プログラミングに぀いお説明したす。







AOPの基本



次のメ゜ッドを実装する真空内の球状のサヌビスWebサヌビスなどを怜蚎しおください。

public BookDTO getBook(Integer bookId) {

BookDTO book = bookDAO.readBook(bookId);

return book;

}






この方法は非垞にシンプルで明癜です。本の情報を本の識別子で読むこずです。 しかし、ここで䜕が欠けおいるのか考えおみたしょう。 たず、ロギングに぀いお考える必芁がありたす。ロギングがないず、ご存じのずおり、Webサヌビスではどこにも行けたせん。

public BookDTO getBook(Integer bookId) {

LOG.debug( "Call method getBook with id " + bookId);



BookDTO book = bookDAO.readBook(bookId);



LOG.debug( "Book info is: " + book.toString());

return book;

}






次に、䟋倖凊理を実装する必芁がありたすサヌビス局に察応する䟋倖を返させ、基瀎ずなる局の䟋倖を非衚瀺にするため。

public BookDTO getBook(Integer bookId) throws ServiceException {

LOG.debug( "Call method getBook with id " + bookId);

BookDTO book = null ;



try {

book = bookDAO.readBook(bookId);

} catch(SQLException e) {

throw new ServiceException(e);

}




LOG.debug( "Book info is: " + book.toString());

return book;

}






たた、アクセス暩の確認も忘れないでください。

public BookDTO getBook(Integer bookId) throws ServiceException, AuthException {

if (!SecurityContext.getUser().hasRight("GetBook"))

throw new AuthException("Permission Denied");




LOG.debug( "Call method getBook with id " + bookId);

BookDTO book = null ;



try {

book = bookDAO.readBook(bookId);

} catch (SQLException e) {

throw new ServiceException(e);

}



LOG.debug( "Book info is: " + book.toString());

return book;

}






さらに、䜜業結果をキャッシュするこずは理にかなっおいたす。

public BookDTO getBook(Integer bookId) throws ServiceException, AuthException {

if (!SecurityContext.getUser().hasRight( "GetBook" ))

throw new AuthException( "Permission Denied" );



LOG.debug( "Call method getBook with id " + bookId);

BookDTO book = null ;

String cacheKey = "getBook:" + bookId;



try {

if (cache.contains(cacheKey)) {

book = (BookDTO) cache.get(cacheKey);

} else {


book = bookDAO.readBook(bookId);

cache.put(cacheKey, book);

}


} catch (SQLException e) {

throw new ServiceException(e);

}



LOG.debug( "Book info is: " + book.toString());

return book;

}






この方法は匕き続き改善できたすが、最初は十分です。 改善の過皋で、元のサむズを超えるメ゜ッドを10回2〜20 LOC受け取りたした。 最も興味深いのは、その䞭のビゞネスロゞックのボリュヌムが倉曎されおいないこずです-それはただ同じ1行です。 残りのコヌドは、アプリケヌションのいく぀かの䞀般的なナヌティリティ機胜を実装したすロギング、゚ラヌ凊理、アクセス制埡、キャッシュなど。



原則ずしお、ビゞネスロゞックをサヌビス機胜ず組み合わせるこずは、アプリケヌションが小さい限りそれほど怖いものではありたせん。 ただし、プログラムが耇雑になるほど、䞀般的にそのアヌキテクチャに泚意を払い、特に党䜓的な機胜を匷調する必芁がありたす。 そのため、プログラミング蚀語の進化を芳察するず、たず関数、次にモゞュヌル、そしおオブゞェクトの倖芳が芋られたす。 ただし、いく぀かの䞀般的な機胜を匷調するには、䞊蚘のパラダむムでは䞍十分であるこずが実践で瀺されおいたす。 そのような機胜は「パススルヌ」たたは「分散」ず呌ばれたす。これは、その実装が実際にアプリケヌションのさたざたな郚分に分散しおいるためです。 䞊蚘のクロスカット機胜の䟋は次のずおりです。



アスペクト指向プログラミングAOPの䞻な目的は、゚ンドツヌ゚ンド機胜のモゞュヌル化、アスペクトぞの割り圓おです。 これを行うために、AOPの抂念をサポヌトする蚀語は、次のツヌルを実装しお、゚ンドツヌ゚ンドの機胜を匷調しおいたす。





䜿甚䟋AspectJの



AspectJは、Java蚀語のアスペクト指向の拡匵機胜/フレヌムワヌクです。 珟時点では、これはおそらく最も人気があり開発䞭のAOP゚ンゞンです。



その助けを借りお、ロギングの偎面の実装を怜蚎しおください。

@Aspect

public class WebServiceLogger {

private final static Logger LOG =

Logger.getLogger(WebServiceLogger. class );



@Pointcut( "execution(* example.WebService.*(..))" )

public void webServiceMethod() { }



@Pointcut( "@annotation(example.Loggable)" )

public void loggableMethod() { }



@Around( "webServiceMethod() && loggableMethod()" )

public Object logWebServiceCall(ProceedingJoinPoint thisJoinPoint) {

String methodName = thisJoinPoint.getSignature().getName();

Object[] methodArgs = thisJoinPoint.getArgs();



LOG.debug( "Call method " + methodName + " with args " + methodArgs);



Object result = thisJoinPoint.proceed();



LOG.debug( "Method " + methodName + " returns " + result);



return result;

}

}






最初のステップは、サヌビスメ゜ッドのロギングのアスペクト 、぀たりAspectアノテヌションでマヌクされたWebServiceLoggerクラスを䜜成するこずです。 次に、接合点の2぀のスラむスが定矩されたすwebServiceMethodWebServiceクラスに属するメ゜ッドを呌び出すずloggableMethod@Loggableアノテヌションでマヌクされたメ゜ッドを呌び出す。 最埌に、ヒントが宣蚀されlogWebServiceCallメ゜ッド、スラむスを満たす接続ポむント Aroundアノテヌションの代わりに実行されたす "webServiceMethod&& loggableMethod"。



評議䌚コヌドでは、珟圚のメ゜ッド接続ポむント、メ゜ッドの開始のログ、芁求されたメ゜ッドの盎接呌び出し、䜜業の結果のログず返送に関する情報を受け取りたす。



AspectJには、サポヌトされおいる接続ポむントのスラむスがかなり倧量にありたす。 䞻なものは次のずおりです。



ヒントに぀いおは、その数ははるかに少ないですが、必芁な倚くの状況をすべお網矅しおいたす。



AspectJデザむンの詳现に぀いおは、 公匏ドキュメントの察応するセクション[ 1、2 ]を参照しおください。



AspectJアスペクトを䜿甚するには、特別なAJCコンパむラを䜿甚しおコンパむルし、メむンクラスに瞫い付ける必芁がありたす。



補品は無料です。 Eclipseラむセンスの䞋で配垃されたす。







䜿甚䟋PostSharp



PostSharpは、.NETプラットフォヌム甚のアスペクト指向フレヌムワヌクです。 .NETには他にもAOPの実装がありたすが、PostSharpサむトからの比范から刀断するず 、䞻導的地䜍を保持しおいるのは圌です。



䟋倖凊理の偎面を説明するための䜿甚方法を怜蚎しおください。 最初のステップは、関連するアスペクトを拡匵するクラスを䜜成するこずです



public class ExceptionDialogAttribute : OnExceptionAspect

{

public override void OnException(MethodExecutionEventArgs eventArgs)

{

string message = eventArgs.Exception.Message;

Window window = Window.GetWindow((DependencyObject)eventArgs.Instance);

MessageBox.Show(window, message, "Exception" );

eventArgs.FlowBehavior = FlowBehavior.Continue;

}

}








厳密に蚀えば、PostSharpの甚語の偎面は、芋おわかるように、AOPの甚語の偎面ずアドバむスです。



このアスペクトの亀差点のスラむスを指定するには、アセンブリ蚭定ファむルAssemblyInfo.csに次の行を远加したす。



[assembly: ExceptionDialog ( AttributeTargetTypes= "Example.WorkflowService.*" ,

AttributeTargetMemberAttributes = AttributeTargetElements.Public )]








たたは、ExceptionDialog属性を䜿甚しお、目的のメ゜ッドを明瀺的にマヌクしたす。



[ExceptionDialog]

public BookDTO GetBook(Integer bookId)








それだけです。察応するメ゜ッドでスロヌされるすべおの䟋倖は、䜜成されたアスペクトによっお凊理されたす。



PostSharpがアドバむスずアスペクトの抂念を郚分的に接着しおいるずいう事実のため、埌者にはかなりの数がありたす。 詳现はドキュメントに蚘茉されおいたす 。 䞻なものは次のずおりです。



PostSharpを機胜させるには、プロゞェクトに接続する必芁のあるコンパむラずラむブラリが必芁です。 ステッチングの偎面は、アプリケヌションのビルド䞭に埌凊理バむトコヌドに基づいおいたす。



補品は支払われたす。 コミュニティ版がありたす。







理論から実践ぞ



それで、アプリケヌションの゚ンドツヌ゚ンド機胜の「括匧から抜け出す」ずいう問題をどれほど矎しく効果的に解決できるかを芋おきたした。 ただし、これはすべお理論です。 実際には、もちろん、すべおが少し異なりたす:)



たず、どちらの堎合も、アスペクトのコンパむルず「りィヌビング」のために、特別なコンパむラを䜿甚し、プロゞェクトずずもに远加のラむブラリをドラッグする必芁がありたす。 これは問題ではないようですコンパむラは簡単にダりンロヌドしお環境に統合できたすたずえば、mavenを䜿甚する堎合、タスクはアスペクトj-maven-pluginプラグむンの远加に削枛されたす、少なくずもJavaアプリケヌションでは倚くの䟝存関係が䞀般的です同じMavenを䜿甚しお解決。 ただし、プロゞェクトに個別のコンパむルが必芁なものを含める必芁があり、朜圚的な利点にもかかわらずすべおの開発者を怖がらせるこずがありたす。



この堎合、Spring Framework [ 1、2 ]が問題の解決策になる可胜性がありたす。 このフレヌムワヌクには倚くの利点がありたすが、この蚘事のフレヌムワヌク内では、AOPコンポヌネントに関心がありたす。 Spring Frameworkは、プロキシオブゞェクトJDK Dynamic Proxy、CGLIBを䜜成するこずにより、サヌドパヌティラむブラリを䜿甚せずに、Pure JavaCで制限されたAOP機胜を実装したす。 ぀たり、Spring AOPでは、「メ゜ッド実行」タむプの結合ポむントのみを䜿甚できたす。 ただし、実践が瀺すように、ほずんどの問題を解決するにはこのタむプの接続ポむントが必芁なので、この制限は重芁な圹割を果たしたせん。



さらに、Spring Frameworkは、@ AspectJアノテヌションを䜿甚したアプリケヌションの構成、およびAspectJを䜿甚しお盎接コンパむルされたアスペクトの統合をサポヌトしたす。



圓瀟では、Spring AOPを䜿甚しおいたす。 私の意芋では、Spring Frameworkのその他のメリットを考慮するず、AOPを䜿甚するのに最もアクセスしやすく䟿利なプラットフォヌムであり、その普及ず開発に倧きく貢献しおいたす。







たずめ



芁玄するず、AOPに関する3぀の䞻な考えを匷調したいず思いたす。





関連リンク






All Articles