在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)
关于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)
相关文章推荐
- JAVAWEB开发之Spring详解之——Spring的入门以及IOC容器装配Bean(xml和注解的方式)、Spring整合web开发、整合Junit4测试
- Spring IOC容器-自动装配
- Spring中的IOC(二):容器对bean属性的装配
- 第36天(就业班) spring引入、专业术语、spring六大模块、bean创建对象的细节、IOC容器、对象依赖关系、自动装配、注解方式
- Mike 企业级框架专题 Spring Ioc容器装配Bean
- Spring的IOC容器—Bean的自动装配
- Spring4学习:在Ioc容器中装配Bean
- Spring(三):IoC容器装配Bean(xml配置方式和注解方式)
- Spring学习-06:IOC容器装配Bean(xml配置方式)详解
- spring ioc 容器装配bean
- 学习《spring 3.x企业应用开发实战》之在IoC容器中装配Bean
- spring在IoC容器中装配Bean详解
- spring3.x第四章 在IOC容器中装配Bean
- Spring原理与源码分析系列(三)- Spring IoC容器启动过程分析(下)
- Spring-IOC容器的配置
- Spring之IoC容器解析(一)
- Spring源代码分析之(二):IOC容器在web容器中的启动
- Spring学习-- IOC 容器中 bean 的生命周期
- Spring核心框架之IoC容器 推荐
- Spring IoC容器-编码方式比较