AOP的特色在于,使用依赖注入的方式来装配AOP代理。通过使用XML配置AOP代理,使得代码简洁清晰。
      关于AOP(Aspect Oriented Programming)的一些知识,可以查阅相关文档。
      使用AOP,可以对方法实现增强(Advice)。方法的调用之前之后,以及运行时都可以使用AOP织入(Weaving)增强。
      每个切面(Aspect)都是横跨多个核心逻辑的,为这些核心逻辑提供相应的服务。把这些切面从系统中分析出来,作为一个独立的关注点。
      运行环境
      开发IDE            :Eclipse 3.2 + MyEclipse 5.0
      数据库平台      :SQL Server 2000
      Spring版本     :Spring 1.x
      Hibernate版本 :Hibernate 3.0
      因为刚刚学习到这里,单独使用Hibernate 3.0作为持久层。
      准备工作
      新建数据库sphiperson,新建表account,表account只有两个字段name和pwd,其中name为主键;
      加载SQL Server JDBC驱动包,Spring 1.x JAR包,Hibernate 3.0 JAR包;
      生成POJO及其映射文件,创建HibernateSessionFactory;
      测试目标
      工程结构如图所示:

      对于用户登录系统,登录之前对其登录行为写入日志,登录过程中检测异常,登录之后成功与否写入日志。
      开发过程
      编写接口AccountServiceInterf:
      package org.shirdrn.interf;
      public interface AccountServiceInterf {
      public boolean login(String name,String pwd);   // 使用用户名和密码登录系统
      }
      因为登录过程要查询数据库,检测用户名和密码是否正确,所以Dao实现了查询的功能。AccountDao.java中的查询方法代码如下所示:
      public static List searchAccount(Account account){
         Session session = HibernateSessionFactory.getSession();
         Criteria c = session.createCriteria(Account.class);
         if(account.getName() != null){
          c.add(Restrictions.eq("name", account.getName()));
         }
         if(account.getPwd() != null){
          c.add(Restrictions.eq("pwd", account.getPwd()));
         }
         return c.list();
      }
      在Dao中在添加一个处理登录过程的方法:
      public boolean login(String name, String pwd) {
         Account account = new Account();
         account.setName(name);
         account.setPwd(pwd);
         List list = AccountDao.searchAccount(account);
         if(list.size()>0){
          return true;
         }
         else{
          throw new RuntimeException("登录失败。");
         }
      }
      而且,AccountServiceImpl类实现了AccountServiceInterf接口:
      package org.shirdrn.impl;
      import org.shirdrn.dao.AccountDao;
      import org.shirdrn.interf.AccountServiceInterf;
      public class AccountServiceImpl implements AccountServiceInterf {
      private AccountDao accountDao;

      public void setAccountDao(AccountDao accountDao){
         this.accountDao = accountDao;
      }

      public boolean login(String name, String pwd) {
         return(accountDao.login(name, pwd));
      }
      }
      在AccountServiceImpl实现类中注入Dao,并且在Spring的配置文件applicarionContext.xml中配置Bean如下:
      <bean id="accountServiceImpl" abstract="false" singleton="true"
         lazy-init="default" autowire="default" dependency-check="default"
         class="org.shirdrn.impl.AccountServiceImpl">
         <property name="accountDao">
          <bean class="org.shirdrn.dao.AccountDao" />
         </property>
      </bean>
      含义就是在AccountServiceInterf接口的具体实现类AccountServiceImpl中注入AccountDao。
      接着,对分离出来的切面进行AOP:
      调用login登录方法之前,实现LoginMethodBeforeAdvice类,该类继承了org.springframework.aop.MethodBeforeAdvice接口,同时需要实现继承的before方法。LoginMethodBeforeAdvice实现类的代码如下所示:
      package org.shirdrn.spring.aop;
      import java.lang.reflect.Method;
      import java.util.Date;
      import org.springframework.aop.MethodBeforeAdvice;
      public class LoginMethodBeforeAdvice implements MethodBeforeAdvice {
      public void before(Method arg0, Object[] arg1, Object arg2)throws
      Throwable {
         String date = (new Date()).toLocaleString();
         System.out.println("信息:["+date+"]用户 "+arg1[0]+" 正在尝试登录陆系统...");
      }
      }
      装配bean,注入,在XML配置文件中配置如下:
      <bean id="loginMethodBeforeAdvice"
         class="org.shirdrn.spring.aop.LoginMethodBeforeAdvice"
         abstract="false" singleton="true" lazy-init="default"
         autowire="default" dependency-check="default">
      </bean>
      同样,调用login登录方法之后,实现LoginAfterReturningAdvice类,该类继承了org.springframework.aop.AfterReturningAdvice接口,同时需要实现继承的afterReturning方法。LoginAfterReturningAdvice实现类的代码如下所示:
      package org.shirdrn.spring.aop;
      import java.lang.reflect.Method;
      import java.util.Date;
      import org.springframework.aop.AfterReturningAdvice;
      public class LoginAfterReturningAdvice implements AfterReturningAdvice {
      public void afterReturning(Object arg0, Method arg1, Object[] arg2,Object
      arg3) throws Throwable {
         String date = (new Date()).toLocaleString();
         System.out.println("信息:["+date+"]用户 "+arg2[0]+" 成功登录系统.");
      }
      }
      装配bean,注入,在XML配置文件中配置如下:
      <bean id="loginAfterReturningAdvice"
         class="org.shirdrn.spring.aop.LoginAfterReturningAdvice"
         abstract="false" singleton="true" lazy-init="default"
         autowire="default" dependency-check="default">
      </bean>
      然后,调用login方法登录过程中,对异常进行处理,实现LoginThrowsAdvice类,该类继承了org.springframework.aop.ThrowsAdvice接口,因为org.springframework.aop.ThrowsAdvice接口没有提供继承的方法,但是建议按照提示的方法实现,我们实现了如下方法,方法声明如下:
      public void afterThrowing(Method method, Object[] args, Object target,
      Throwable subclass)
      LoginThrowsAdvice实现类的代码如下所示:
      package org.shirdrn.spring.aop;
      import java.lang.reflect.Method;
      import org.springframework.aop.ThrowsAdvice;
      public class LoginThrowsAdvice implements ThrowsAdvice {
      public void afterThrowing(Method method, Object[] args, Object target,
      Throwable subclass){
         System.out.println("用户登录过程中发生异常:
"+subclass.getClass().getSimpleName());
      }
      }
      装配bean,注入,在XML配置文件中配置如下:
      <bean id="loginThrowsAdvice"
         class="org.shirdrn.spring.aop.LoginThrowsAdvice"
         abstract="false" singleton="true" lazy-init="default"
         autowire="default" dependency-check="default">
      </bean>
      最后,使用org.springframework.aop.framework.ProxyFactoryBean配置AOP代理服务,在XML中配置如下所示:
      <bean id="accountService"
         class="org.springframework.aop.framework.ProxyFactoryBean"
         abstract="false" singleton="true" lazy-init="default"
         autowire="default" dependency-check="default">
         <property name="target">
          <ref bean="accountServiceImpl" />
         </property>
         <property name="interceptorNames">
          <list>
           <value>loginMethodBeforeAdvice</value>
           <value>loginAfterReturningAdvice</value>
           <value>loginThrowsAdvice</value>
          </list>
         </property>
      </bean>
      测试过程
      启动SQL Server 2000数据库服务器。
      向数据库表account中添加一个用户:[name=shirdrn,pwd=830119]。
      编写测试主函数,代码非常简洁清晰,如下所示:
      package org.shirdrn.main;
      import org.shirdrn.interf.AccountServiceInterf;
      import org.springframework.context.ApplicationContext;
      import org.springframework.context.support.ClassPathXmlApplicationContext;
      public class Main {
      public static void main(String[] args) {
         String name = "shirdrn";
         String pwd = "830119";
         ApplicationContext ctx = new
      ClassPathXmlApplicationContext("applicationContext.xml");
         AccountServiceInterf asi =
      (AccountServiceInterf)ctx.getBean("accountService");
         asi.login(name, pwd);
      }
      }
      运行,测试输出结果,在控制台上显示如下所示:
      信息:[2008-3-21 18:20:49]用户 shirdrn 正在尝试登录陆系统...
      信息:[2008-3-21 18:20:52]用户 shirdrn 成功登录系统.
      如果我们使用一个数据库中不存在的用户去模拟登录过程,则在运行的过程中会抛出异常,异常抛出是在AccountDao类中实现登录过程的login方法中,抛出异常:
      throw new RuntimeException("登录失败。");
      测试代码,将用户名和密码修改为:
         String name = "Jessery";
         String pwd = "jessery";
      运行程序,则可以看到:
      信息:[2008-3-21 18:25:34]用户 Jessery 正在尝试登录陆系统...
      用户登录过程中发生异常: RuntimeException
      Exception in thread "main" java.lang.RuntimeException: 登录失败。
      at org.shirdrn.dao.AccountDao.login(AccountDao.java:33)
      at org.shirdrn.impl.AccountServiceImpl.login(AccountServiceImpl.java:14)
      at
      org.shirdrn.impl.AccountServiceImpl$$FastClassByCGLIB$$64a03a60.invoke(<generated>)
      at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:149)
      at
      org.springframework.aop.framework.Cglib2AopProxy$CglibMethodInvocation.invokeJoinpoint(Cglib2AopProxy.java:685)
      at
      org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:148)
      at
      org.springframework.aop.framework.adapter.ThrowsAdviceInterceptor.invoke(ThrowsAdviceInterceptor.java:118)
      at
      org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
      at
      org.springframework.aop.framework.adapter.AfterReturningAdviceInterceptor.invoke(AfterReturningAdviceInterceptor.java:51)
      at
      org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
      at
      org.springframework.aop.framework.adapter.MethodBeforeAdviceInterceptor.invoke(MethodBeforeAdviceInterceptor.java:53)
      at
      org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:170)
      at
      org.springframework.aop.framework.Cglib2AopProxy$DynamicAdvisedInterceptor.intercept(Cglib2AopProxy.java:623)
      at
      org.shirdrn.impl.AccountServiceImpl$$EnhancerByCGLIB$$32dd7c51.login(<generated>)
      at org.shirdrn.main.Main.main(Main.java:14)
      心得体会
      Spring所涉及到的东西太多了,有点让人头脑发胀。只有一点点地去阅读相关文档来加深自己对Spring的理解,在这个过程中,可能涉及到一些没有接触过的技术,可以查阅相关的文档,这样有助于深入学习Spring。
      如果单单是一味地只注重Spring框架的基础理论,也不会有太大的提高。因为在实际中,那些理论不是像想象中那样轻而易举地就能够做得到。通过实践来验证自己积累收获的理论知识,从而在此基础上理解Spring,尤其是它的原理机制。
      理论+实践,理论实践同步交叉融合,我认为这是一个比较好的学习方式。