不管是使用Java的动态代理还是使用CGLIB代理,虽然功能很强大,但是对于每一个类,都要在Spring的配置文档中建立相应的代理,如果只是一个很小的应用系统,还看不出来工作量有多大,但对于一个大型的企业应用来说,工作量就太大了,而且重复性的工作很多,幸好Spring提供了一种自动代理的方式,可以减轻这部分工作。要使用Spring中的动态代理,org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator包是必需的。下面就讲解一下怎么来实现自动代理。
这个例子是所有类中以do开头的方法,在被调用时,都要进行日志输出。实现思路是:首先在接口TimeBookInterface中增加一个方法doCheck(),在其实现类TimeBook中实现这个方法,接着使用前面示例中的Before、After通知,然后修改配置文档,定义自动代理,最后编写测试程序,查看输出结果。具体步骤如下所示:
(1)在com.gc.impl包的接口TimeBookInterface中增加一个方法doCheck()。Time-
BookInterface.java的示例代码如下:
//******* TimeBookInterface.java**************
package com.gc.impl;
import org.apache.log4j.Level;
public interface TimeBookInterface {
public void doAuditing(String name);
public void doCheck(String name);
}
(2)在com.gc.action包的类TimeBook中增加一个方法doCheck(),doCheck()方法中编写财务关账的代码。TimeBook.java的示例代码如下:
//******* TimeBook.java**************
package com.gc.action;
import com.gc.impl.TimeBookInterface;
public class TimeBook implements TimeBookInterface {
public void doAuditing(String name) {
//审核数据的相关程序
System.out.println ("审核数据的相关程序正在执行...");
}
public void doCheck(String name) {
//关账的相关程序
System.out.println ("财务关账的相关程序正在执行...");
}
}
(3)使用前面示例中负责输出日志信息的类LogBefore,该类实现了接口Method-
BeforeAdvice,重写了before()方法。LogBefore.java的示例代码如下:
//******* LogBefore.java**************
package com.gc.action;
import java.lang.reflect.Method;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.aop.MethodBeforeAdvice;
public class LogBefore implements MethodBeforeAdvice {
private Logger logger = Logger.getLogger(this.getClass().getName());
//用于在执行审核程序前调用该方法
public void before(Method method, Object[] args, Object target) throws Throwable {
logger.log(Level.INFO, args[0] + " 开始审核数据...");
}
}
(4)使用前面示例中负责输出日志信息的类LogAfter,该类实现了接口AfterReturning-
Advice,重写了afterReturning()方法。LogAfter.java的示例代码如下:
//******* LogAfter.java**************
package com.gc.action;
import java.lang.reflect.Method;
import org.apache.log4j.Level;
import org.apache.log4j.Logger;
import org.springframework.aop.AfterReturningAdvice ;
public class LogAfter implements AfterReturningAdvice {
private Logger logger = Logger.getLogger(this.getClass().getName());
//用于在执行审核程序后调用该方法
public void afterReturning(Object object, Method method, Object[ ] args, Object target) throws Throwable {
logger.log(Level.INFO, args[0] + " 审核数据完成...");
}
}
(5)修改配置文档config.xml,增加一个负责自动代理的Bean。config.xml的示例代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="HelloWorld" class="com.gc.action.HelloWorld" depends-on="date">
<property name="msg">
<value>HelloWorld</value>
</property>
<property name="date">
<ref bean="date"/>
</property>
</bean>
<bean id="date" class="java.util.Date"/>
<!--以下是使用Spring AOP实现日志输出的Bean-->
<bean id="log" class="com.gc.action.LogAop"/>
<bean id="timeBook" class="com.gc.action.TimeBook"/>
<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<!--以下是实现Before通知-->
<bean id="logBefore" class="com.gc.action.LogBefore"/>
<bean id="logBeforeAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="logBefore"/>
</property>
<!--指定以do开头的方法-->
<property name="patterns">
<value>.*do.* </value>
</property>
</bean>
<!--以下是实现After通知-->
<bean id="logAfter" class="com.gc.action.LogAfter"/>
<bean id="logAfterAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="logAfter"/>
</property>
<!--指定以do开头的方法-->
<property name="patterns">
<value>.*do.* </value>
</property>
</bean>
</beans>
(6)修改测试代码TestHelloWorld,调用doCheck()方法。TestHelloWorld.java的示例代码如下:
//******* TestHelloWorld.java**************
package com.gc.test;
import com.gc.action.TimeBook;
import com.gc.action.TimeBookProxy;
import com.gc.impl.TimeBookInterface;
public class TestHelloWorld {
public static void main(String[] args) {
//通过ApplicationContext获取配置文档
ApplicationContext actx=new FileSystemXmlApplicationContext("config.xml");
TimeBookInterface timeBookProxy = (TimeBookInterface)actx.getBean("timeBook");
timeBookProxy.doCheck("张三");
}
}
(7)运行测试程序,可以看到调用doCheck()方法和LogBefore、LogAfter通知的日志信息输出,如图5.12所示。
图5.12 调用doCheck()方法和LogBefore、LogAfter通知的日志信息输出
(8)修改测试代码TestHelloWorld,调用doAuditing()方法。TestHelloWorld.java的示例代码如下:
//******* TestHelloWorld.java**************
package com.gc.test;
import com.gc.action.TimeBook;
import com.gc.action.TimeBookProxy;
import com.gc.impl.TimeBookInterface;
public class TestHelloWorld {
public static void main(String[ ] args) {
//通过ApplicationContext获取配置文档
ApplicationContext actx=new FileSystemXmlApplicationContext("config.xml");
TimeBookInterface timeBookProxy = (TimeBookInterface)actx.getBean("timeBook");
timeBookProxy.doAuditing("张三");
}
}
(9)运行测试程序,可以看到调用doAuditing()方法和LogBefore、LogAfter通知的日志信息输出,如图5.13所示。
图5.13 调用doAuditing()方法和LogBefore、LogAfter通知的日志信息输出
(10)修改配置文档config.xml,把LogBefore通知定义为指定doCheck()方法,把LogAfter通知定义为指定doAuditing()方法。config.xml的示例代码如下:
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"
"http://www.springframework.org/dtd/spring-beans.dtd">
<beans>
<bean id="HelloWorld" class="com.gc.action.HelloWorld" depends-on="date">
<property name="msg">
<value>HelloWorld</value>
</property>
<property name="date">
<ref bean="date"/>
</property>
</bean>
<bean id="date" class="java.util.Date"/>
<!--以下是使用Spring AOP实现日志输出的Bean-->
<bean id="log" class="com.gc.action.LogAop"/>
<bean id="timeBook" class="com.gc.action.TimeBook"/>
<bean id="autoProxyCreator" class="org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator"/>
<!--以下是实现Before通知-->
<bean id="logBefore" class="com.gc.action.LogBefore"/>
<bean id="logBeforeAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="logBefore"/>
</property>
<!--指定对doCheck 方法有效-->
<property name="patterns">
<value>.*doCheck.* </value>
</property>
</bean>
<!--以下是实现After通知-->
<bean id="logAfter" class="com.gc.action.LogAfter"/>
<bean id="logAfterAdvisor"class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
<property name="advice">
<ref bean="logAfter"/>
</property>
<!--指定对doAuditing方法有效-->
<property name="patterns">
<value>.*doAuditing.* </value>
</property>
</bean>
</beans>
(11)修改测试代码TestHelloWorld,调用doCheck()方法。TestHelloWorld.java的示例代码如下:
//******* TestHelloWorld.java**************
package com.gc.test;
import com.gc.action.TimeBook;
import com.gc.action.TimeBookProxy;
import com.gc.impl.TimeBookInterface;
public class TestHelloWorld {
public static void main(String[ ] args) {
//通过ApplicationContext获取配置文档
ApplicationContext actx=new FileSystemXmlApplicationContext("config.xml");
TimeBookInterface timeBookProxy = (TimeBookInterface)actx.getBean("timeBook");
timeBookProxy.doCheck("张三");
}
}
(12)运行测试程序,可以看到调用doCheck()方法和LogBefore通知的日志信息输出,如图5.14所示。
图5.14 调用doCheck()方法和LogBefore通知的日志信息输出
(13)修改测试代码TestHelloWorld,调用doAuditing()方法。TestHelloWorld.java的示例代码如下:
//******* TestHelloWorld.java**************
package com.gc.test;
import com.gc.action.TimeBook;
import com.gc.action.TimeBookProxy;
import com.gc.impl.TimeBookInterface;
public class TestHelloWorld {
public static void main(String[ ] args) {
//通过ApplicationContext获取配置文档
ApplicationContext actx=new FileSystemXmlApplicationContext("config.xml");
TimeBookInterface timeBookProxy = (TimeBookInterface)actx.getBean("timeBook");
timeBookProxy.doAuditing("张三");
}
}
(14)运行测试程序,可以看到调用doAuditing()方法和LogAfter通知的日志信息输出,如图5.15所示。
图5.15 调用doAuditing()方法和LogAfter通知的日志信息输出
上面的示例展示了Spring的自动代理,并接着展示了利用正则表达式进行方法的匹配,由此可以看出使用自动代理的简便。