http://www.javaworld.com/javaworld/jw-01-2007/jw-0105-aop.html

<div class="note"> crosscutting concerns : 횡단 관심사 </div>

Spring 2.0 AOP를 사용하여 횡단 관심사 구현하기#

Spring 2.0은 멋지고 사용자에게 친숙한 AOP기능을 제공한다.
  • 2007년 1월 5일
  • 글쓴이 Ganesh Ghag

Most developers will acknowledge how implementing crosscutting concerns such as logging, auditing, security and transactionality can adversely affect business logic implementation. Such concerns "seem" to increase the complexity of existing business logic, at times making it difficult if not impossible to clearly distinguish business logic from the crosscutting concern implementation.

I had been hearing about aspect-oriented programming (AOP) being a solution for implementing crosscutting concerns. But having read through early AOP tools documentation, I was dissuaded from using AOP in my projects' recommendations, primarily because of a concern that average developers might not "get" AOP concepts, and the overall ability to debug applications, and maintain them, might be restricted to those few who understood AOP.

최근에 릴리즈된 Spring 2.0가 제공하는 AOP기능은 멋지고 사용하기 쉽다. Spring AOP는 객체지향 프로그래밍을 할수있는 평균적인 수준의 자바 개발자들이 사용하기에 충분히 쉽다. 지금부터 하는 이야기는 대개의 소프트웨어 프로젝트에서 crosscutting concerns를 구현하기 위해 Spring 2.0을 효과적으로 사용하는 방법을 보여준다. 다음의 요건을 처리하는 crosscutting concerns을 구현할것이다.

  • 보안
  • 로깅
  • 트랜잭션

예제 코드를 조각을 보자.

 public String doSomething(String input)
{
      //Logging
        System.out.println("entering business method with:"+input);
        
        //Security check for authorization of action (business-method) 
        
        //transactionality
        try
        {
            //Start new session and transaction
            
            //Some business logic
            
            //Commit transaction
        }
        catch(Exception e)
        {
            //Rollback transaction 
        }
        finally
        {
            //Close session
        }
        
        //Logging
        System.out.println("exiting business method with:"+input);

      return input;
}

비즈니스 메소드에서 실제 비즈니스 로직은 보안, 트랜잭션 그리고 로깅을 위한 횡단 관심사 코드를 뺄수있다. 가능한한 비즈니스 로직에서 명확히 분리된 관심사를 구현하는 것을 보여주도록 할것이다. 시작하기전에, 관점지향 프로그래밍에서 사용되는 몇가지 기본적인 정의와 Spring AOP에서의 구현물을 잠시 보도록 하자.

AOP 기본 개념#

  • Aspect: A modularized implementation of a software concern that cuts across various objects in a software implementation. Logging is a good example of an aspect. In Spring AOP, aspects are nothing more than regular Spring beans, which themselves are plain-old Java objects (POJO) registered suitably with the Spring Inversion of Control container. The core advantage in using Spring AOP is its ability to realize the aspect as a plain Java class.
  • Join point: A point during program execution, such as a method executing or an exception being handled. In Spring AOP, a join point exclusively pertains to method execution only, which could be viewed as a limitation of Spring AOP. However, in reality, it is enough to handle most common cases of implementing crosscutting concerns.
  • Advice: Information about "when" an aspect is to be executed with respect to the join point. Examples of types of advice are "around," "before," and "after." They specify when the aspect's code will execute with respect to a particular join point.
  • Pointcut: A declarative condition that identifies the join points for consideration during an execution run. Pointcut is specified as an expression. Spring AOP uses the AspectJ pointcut expression syntax. An example pointcut expression is: execution(* com.myorg.springaop.examples.MyService*.*(..)). Asterisks in the expression refer to wildcards, as is conventional.

Spring 2.0 AOP를 사용하여 이러한 관심사를 구현하도록 해보자. 노트 : 아래의 예제는 기본적인 Spring 설정에 친숙하다고 가정하고 작성되었다. 전체 Spring설정파일은 관련자원 부분[1]에서 다운로드가능하다.

로깅#

로깅은 구현하기에 가장 쉬운 관심사다. 필요한 것은 다음의 코드처럼 로깅 관심사를 Spring AOP aspect로 구현한 자바 클래스뿐이다.

package com.myorg.springaop.examples;

import org.aspectj.lang.ProceedingJoinPoint;

public class MyLoggingAspect
{
    public Object log(ProceedingJoinPoint callthrows Throwable
    {
        System.out.println("from logging aspect: entering method [" + call.toShortString()
                            +"] with param:"+call.getArgs()[0] );

        Object point =  call.proceed();

        System.out.println("from logging aspect: exiting method [" + call.toShortString()   
                            "with return as:" +point);        

        return point;
    }

}

위 LoggingAspect 클래스는 Spring bean처럼 Spring 2.0에 등록될 필요가 있다. The above LoggingAspect class merely needs to be registered with Spring 2.0 as a regular Spring bean. Further, we need to register the LoggingAspect bean in the Spring configuration file as a Spring AOP aspect. This includes specifying the pointcut expression and the aspect's advice type. The configuration for the pointcut, including the pointcut expression "execution(* com.myorg.springaop.examples.MyService*.*(..))" , is shown in the listing below. The advice configuration, also shown below, specifies "around" as the advice type. Other advice types, such as before and after, are also possible. The advice specification also includes the Java aspect class's method to which the aspect will be applied. In this case it is the method log.

The code below is the Spring configuration for registering a logging aspect using Spring AOP:

<bean id="LoggingAspect"  class "com.myorg.springaop.examples.MyLoggingAspect"/>
<aop:config>
      ...
      ...
      ...
      <aop:aspect ref="LoggingAspect">
         <aop:pointcut id="myCutLogging"
                    expression="execution(* com.myorg.springaop.examples.MyService*.*(..))"/>
         <aop:around pointcut-ref="myCutLogging" method="log"/>
      </aop:aspect>
</aop:config>

Having implemented the above class and Spring configuration, effectively, we have instructed Spring AOP to execute the code present in the MyLoggingAspect class's log( ) method dynamically around the business logic represented by the method doSomething( ).

Security#

To implement security, specifically authorization, we will use Acegi. Acegi is a popular and flexible security framework that can be used in enterprise applications. Acegi integrates well with Spring and uses Spring application contexts for all configurations. Using Acegi Security greatly simplifies implementing authorization in our application in a flexible manner.

To start, we need a POJO class that will implement the security concern as a Spring AOP aspect. As can be seen in the listing below, the implementation of method checkSecurity(…) involves using Acegi APIs and classes such as SecurityContextHolder for retrieving the authenticated user and the user's role. Using the user and his role, an application-specific authorization can be implemented:

package com.myorg.springaop.examples;

import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.userdetails.UserDetails;
import org.aspectj.lang.ProceedingJoinPoint;

public class MySecurityAspect
{
    public Object checkSecurity(ProceedingJoinPoint callthrows Throwable
    {
        System.out.println("from security aspect: checking method call for " 
    + call.toShortString());

    Object obj = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

        String username = "";
        if (obj instanceof UserDetails
          username = ((UserDetails)obj).getUsername();
        else 
          username = obj.toString();

        //Do authorization check here
        
        System.out.println("from security aspect: authenticated user is "+username);
        return call.proceed();
    }

}

The important thing to note is the entire authorization check lies in a separate aspect (POJO class), which is distinct from the business logic code. This security aspect can be effectively applied to our business logic method using the following Spring configuration:

  • First, we register the regular Java class SecurityAspect with Spring 2.0 as a Spring bean
  • Next, we specify the pointcut and advice:
    1. The pointcut expression is execution(*com.myorg.springaop.examples.MyService*.*(..))
    2. The advice type is "around," and the aspect method name is checkSecurity

The Spring configuration for the security aspect:

 <bean id="SecurityAspect" class="com.myorg.springaop.examples.MySecurityAspect"/>

<aop:config>
      <aop:aspect ref="SecurityAspect">
         <aop:pointcut id="myCutSecurity"
                expression="execution(* com.myorg.springaop.examples.MyService*.*(..))"/>
         <aop:around pointcut-ref="myCutSecurity" method="checkSecurity"/>
      </aop:aspect>

      ...
      ...
      ...
</aop:config>

Additionally, a Spring configuration is needed for configuring Acegi with Spring. The configuration uses an in-memory data access object (DAO) provider, in which case, the developer specifies the potential users and roles in the application as simple name-value pairs, as a part of the static Spring configuration file. This can easily be inferred from the following Spring configuration:

 <bean id="authenticationManager" class="org.acegisecurity.providers.ProviderManager">
  <property name="providers">
    <list>
      <ref local="daoAuthenticationProvider"/>
    </list>
  </property>
</bean>

<bean id="daoAuthenticationProvider" 
   class="org.acegisecurity.providers.dao.DaoAuthenticationProvider">
  <property name="userDetailsService"><ref bean="inMemoryDaoImpl"/></property>
</bean> 

<bean id="inMemoryDaoImpl" class="org.acegisecurity.userdetails.memory.InMemoryDaoImpl">
  <property name="userMap">
    <value>
      ganesh=mypassword,ROLE_TELLER
      laura=mypassword,disabled,ROLE_TELLER
    </value>
  </property>
</bean>

Transactionality#

We will implement the transactionality concern in a declarative fashion, using Spring 2.0, instead of programmatic transactionality APIs.

Spring 2.0 has rich support for declarative transactionality using Spring AOP. We need to first declare an appropriate data source in the Spring configuration. Then we declare a transaction manager in the configuration. Next, we specify the transactionality advice, which includes fine-grained details such as specifying method names (with wild card support) and the corresponding transactionality characteristics like propagation mode, isolation, timeout, read-only, and rollbackFor (exception-based rollback specification). Finally, we specify the AOP configuration as follows:

  • Pointcut: this includes the pointcut expression execution(* com.myorg.springaop.examples.MyService*.*(..))
  • Advice: this is the transactionality advice, which specifies that default transactionality characteristics be applied to all methods, as specified by the pointcut — except the methods starting with "get" which should be treated with the transactionality attribute of read-only

Spring configuration:

 <bean id="txManager"       
    class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="myDataSource"/>
</bean>

<tx:advice id="txAdvice" transaction-manager="txManager">
    <tx:attributes>
        <tx:method name="get*" read-only="true"/>
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<aop:config>
    <aop:pointcut id="myCutTx" expression="execution(*                
        com.myorg.springaop.examples.MyService*.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="myCutTx"/>
</aop:config>

The above AOP code can be easily compiled with the Java 5.0 compiler. There is no need for a separate AOP compiler. Spring uses Java 5.0 dynamic proxies to implement Spring AOP. Needless to say, the weaving of Spring AOP aspects into the application code occurs at runtime, because of the use of dynamic proxies.

Summarizing, we have so far implemented the concerns of logging and security in plain Java classes and implemented declarative transactionality using Spring configurations alone. The business logic in our application Java class has not been tampered with. As a result, the business logic code has now been reduced to:

 public String doSomething(String input)
{
            
     //some business logic

      return input;
}

We can invoke the business logic code using unit test code as follows:

 ApplicationContext context 
    new ClassPathXmlApplicationContext(new String[] {"my-spring-config.xml"});

((MyService)context.getBean("MyService")).doSomething("hi and hello"));

Conclusion#

This story has shown that logging, security and transactionality concerns can be easily implemented without cluttering the business logic code with details of the crosscutting concerns. The concerns can be selectively applied to business logic by a mere tweak to the Spring configuration. And best of all, your development team doesn't need to learn new AOP language syntax. Implementing the concerns is all possible with just Java and some Spring configurations.

There are several other intricacies with respect to implementing AOP in a full-fledged project: ordering concerns, exception management, parameterizing the concerns with execution context data, just to name a few. As this article's intent was to jumpstart your interest in using Java-based AOP techniques in your respective projects, I did not include coverage of those subjects here.

Author Bio#

Ganesh Ghag is an enterprise architect with more than 11 years of experience in Java-based software development design and architecture, including four years of technology consulting on Wall Street. He is currently employed as an enterprise architect with IT solutions company Mastek. Current professional interests include software design, Java EE, SOA, and EDA.

참고[#1]#

  • 이 아티클을 실행하는 소스코드 다운로드:
http://www.javaworld.com/javaworld/jw-01-2007/aop/jw-01-aop.zip
  • Spring AOP를 사용하는 포괄적인 튜토리얼은 Spring문서에서 볼수 있다:
http://static.springframework.org/spring/docs/2.0.x/reference/aop.html#aop-schema
  • 프로그램으로 처리하는 것에 더해 선언적으로 Spring트랜잭션을 사용하는 간단하고 포괄적인 튜토리얼은 다음의 Spring문서에서 볼수 있다:
http://static.springframework.org/spring/docs/2.0.x/reference/transaction.html#transaction-declarative
  • AspectJ AOP 표현언어를 위한 포괄적인 가이드: http://www.eclipse.org/aspectj/doc/released/progguide/index.html]
  • Acegi 보안 웹 사이트:
http://www.acegisecurity.org/
  • AOP를 소개하기 위해, Ramnivas Laddad의 "나는 AOP를 원해" 를 읽으라.
o Part 1. Separate software concerns with aspect-oriented programming (January 2002): http://www.javaworld.com/javaworld/jw-01-2002/jw-0118-aspect.html o Part 2. Learn AspectJ to better understand aspect-oriented programming (March 2002): http://www.javaworld.com/javaworld/jw-03-2002/jw-0301-aspect2.html o Part 3. Use AspectJ to modularize crosscutting concerns in real-world problems (April 2002): http://www.javaworld.com/javaworld/jw-04-2002/jw-0412-aspect3.html
  • For more articles on developing Web applications, browse through the articles in JavaWorld's Web Development Frameworks Research Center:
http://www.javaworld.com/channel_content/jw-webdev-index.html
  • Keep up with what's new at JavaWorld! Sign up for our free Enterprise Java newsletter:
http://www.javaworld.com/newsletter/

Add new attachment

Only authorized users are allowed to upload new attachments.
« This page (revision-6) was last changed on 21-Jun-2007 23:20 by DongGukLee