在Spring的IoC容器中装配AOP代理

Spring 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)

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值