您的位置:首页 > 编程语言 > Java开发

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

2009-03-20 15:11 399 查看
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)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: