Sun River
Topics about Java SE, Servlet/JSP, JDBC, MultiThread, UML, Design Pattern, CSS, JavaScript, Maven, JBoss, Tomcat, ...
posts - 78,comments - 0,trackbacks - 0

Spring 中的 AOP 简单使用

   

    AOP 作为 Spring 这个轻量级的容器中很重要的一部分,得到越来越多的关注, Spring Transaction 就是用 AOP 来管理的,今天就通过简单的例子来看看 Spring 中的 AOP 的基本使用方法。

 

  首先确定将要 Proxy 的目标,在 Spring 中默认采用 JDK 中的 dynamic proxy ,它只能够实现接口的代理,如果想对类进行代理的话,需要采用 CGLIB proxy 。显然,选择 编程到接口 是更明智的做法。

 

下面是将要代理的接口:

public interface FooInterface {
    public void printFoo();
    public void dummyFoo();
}

以及其一个简单的实现:
public class FooImpl implements FooInterface {
    public void printFoo() {
        System.out.println("In FooImpl.printFoo");

    }

    public void dummyFoo() {
        System.out.println("In FooImpl.dummyFoo");
    }
}
 
接下来创建一个 Advice ,在 Spring 中支持 Around,Before,After returning Throws 四种 Advice ,这里就以简单的 Before Advice 举例:
 
public class PrintBeforeAdvice implements MethodBeforeAdvice {
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("In PrintBeforeAdvice");
    }

}
 
有了自己的 business interface advice ,剩下的就是如何去装配它们了,首先利用 ProxyFactory 以编程方式实现,如下:
 

public class AopTestMain {
    public static void main(String[] args) {
        FooImpl fooImpl = new FooImpl();
        PrintBeforeAdvice myAdvice = new PrintBeforeAdvice();
     
        ProxyFactory factory = new ProxyFactory(fooImpl);
        factory.addBeforeAdvice(myAdvice);
        FooInterface myInterface = (FooInterface)factory.getProxy();

        myInterface.printFoo();
        myInterface.dummyFoo();
    }

}
 
 
现在执行程序,神奇的结果就出现了:
 
  In PrintBeforeAdvice
  In FooImpl.printFoo
  In PrintBeforeAdvice
  In FooImpl.dummyFoo
 
  
虽然这样能体会到 Spring AOP 的用法,但这决不是值得推荐的方法,既然使用了 Spring ,在 ApplicationContext 中装配所需要 bean 才是最佳策略,实现上面的功能只需要写个简单的 applicationContext 就可以了,如下:
 
  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "
http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <description>The aop application context</description>
    <bean id="fooTarget" class="FooImpl"/>
    <bean id="myAdvice" class="PrintBeforeAdvice"/>
    <bean id="foo" class="org.springframework.aop.framework.ProxyFactoryBean">
     <property name="proxyInterfaces">
       <value>FooInterface</value>
     </property>
     <property name="target">
       <ref local="fooTarget"/>
     </property>
     <property name="interceptorNames">
       <list>
         <value>myAdvice</value>
       </list>
     </property>
    </bean>

</beans>

 

   当然, main 中的代码也要进行相应的修改:
    
public static void main(String[] args) {
    ClassPathXmlApplicationContext context = new 
             ClassPathXmlApplicationContext("applicationContext.xml");
    FooInterface foo = (FooInterface)context.getBean("foo");
    foo.printFoo();
    foo.dummyFoo();
}
 
  
现在运行一下,结果将和上面的运行结果完全一样,这样是不是更优雅?当需要更改实现时,只需要修改配置文件就可以了,程序中的代码不需任何改动。
 
  
但是,这时候会发现被 proxy object 中的所有方法调用时都将运行 advice 中的 before ,这显然不能满足绝大多数情况下的需要,此时,只 需借用 Advisor 就可以了,当然要在 Advisor 中利用 pattern 设置好哪些方法需要 advice ,更改 applicationContext 如下:
 
  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
    "
http://www.springframework.org/dtd/spring-beans.dtd">

<beans>
    <description>The springeva application context</description>
    <bean id="fooTarget" class="FooImpl"/>
    <bean id="printBeforeAdvice" class="PrintBeforeAdvice"/>
    <bean id="myAdvisor"
          class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
      <property name="advice">
        <ref local="printBeforeAdvice"/>
      </property>
      <property name="pattern">
        <value>.*print.*</value>
      </property>
    </bean>
    <bean id="foo" class="org.springframework.aop.framework.ProxyFactoryBean">
      <property name="proxyInterfaces">
        <value>FooInterface</value>
      </property>
      <property name="target">
        <ref local="fooTarget"/>
      </property>
      <property name="interceptorNames">
        <list>
          <value>myAdvisor</value>
        </list>
      </property>
    </bean>
</beans>

 

    主程序不需进行任何修改,运行结果已经变样了

   In PrintBeforeAdvice
    In FooImpl.printFoo
    In FooImpl.dummyFoo
 
  
至此,应该已经理解了 Spring AOP 的使用方法,当然 Spring AOP 最重要的应用是 Transaction Manager ,举个这方面的 applicationContext 例子看看:
 
  <?xml version="1.0" encoding="UTF-8"?>
  <!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN" "spring-beans.dtd">

<beans>
    <bean id="propertyConfigurer"   
         class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
      <property name="location">
        <value>/WEB-INF/jdbc.properties</value>
      </property>
    </bean>
    <bean id="dataSource"
          class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      <property name="driverClassName">
        <value>${jdbc.driverClassName}</value>
      </property>
      <property name="url">
        <value>${jdbc.url}</value>
      </property>
      <property name="username">
        <value>${jdbc.username}</value>
      </property>
      <property name="password">
        <value>${jdbc.password}</value>
      </property>
    </bean>
    <bean id="sessionFactory"
          class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
      <property name="dataSource">
        <ref local="dataSource"/>
      </property>
      <property name="mappingResources">
        <value>smartmenu.hbm.xml</value>
      </property>
      <property name="hibernateProperties">
        <props>
          <prop key="hibernate.dialect">${hibernate.dialect}</prop>
        </props>
      </property>
    </bean>
 
    <bean id="transactionManager"       
          class="org.springframework.orm.hibernate.HibernateTransactionManager">
      <property name="sessionFactory">
        <ref local="sessionFactory"/>
      </property>
    </bean>
    <bean id="smartmenuTarget" class="SmartMenuHibernate">
      <property name="sessionFactory">
        <ref local="sessionFactory"/>
      </property>
    </bean>
    <bean id="smartMenu"
        class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
      <property name="transactionManager">
        <ref local="transactionManager"/>
      </property>
      <property name="target">
        <ref local="smartmenuTarget"/>
      </property>
      <property name="transactionAttributes">
        <props>
          <prop key="get*">PROPAGATION_REQUIRED,readOnly</prop>
          <prop key="find*">PROPAGATION_REQUIRED,readOnly</prop>
        </props>
      </property>
    </bean>
  </beans>
 
 
要想彻底理解 Spring AOP ,最好还是多看看源码,开源就是好啊!

 

 

 

posted on 2006-11-16 13:29 Sun River 阅读(282) 评论(0)  编辑  收藏 所属分类: AOP