商讯信箱
用户名: @
密  码:   注册|忘记密码
登录
个人用户经销商
您的位置:首页 > 技术频道 > 正文


三.Spring中AOP的模拟实现
       在学习了Java的动态代理机制后,我们在本节中将学习Java的动态代理机制在Spring中的应用。首先我们创建一个名为AopHandler的类,该类可生成代理对象,同时可以根据设置的前置或后置处理对象分别在方法执行前后执行一些另外的操作,该类的内容如下所示:

package org.amigo.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /** * AOP处理器. * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a> * Creation date: 2007-10-7 - 上午10:13:28 */ public class AopHandler implements InvocationHandler { //需要代理的目标对象 private Object target; //方法前置顾问 Advisor beforeAdvisor; //方法后置顾问 Advisor afterAdvisor; /** * 设置代理目标对象,并生成动态代理对象. * @param target 代理目标对象 * @return 返回动态代理对象 */ public Object setObject(Object target) { //设置代理目标对象 this.target = target; //根据代理目标对象生成动态代理对象 Object obj = Proxy.newProxyInstance( target.getClass().getClassLoader(), target.getClass().getInterfaces(), this); return obj; } /** * 若定义了前置处理,则在方法执行前执行前置处理, * 若定义了后置处理,则在方法调用后调用后置处理. * @param proxy 代理对象 * @param method 调用的业务方法 * @param args 方法的参数 * @return 返回结果信息 * @throws Throwable */ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //进行业务方法的前置处理 if (beforeAdvisor != null) { beforeAdvisor.doInAdvisor(proxy, method, args); } //执行业务方法 Object result = method.invoke(target, args); //进行业务方法的后置处理 if (afterAdvisor != null) { afterAdvisor.doInAdvisor(proxy, method, args); } //返回结果对象 return result; } /** * 设置方法的前置顾问. * @param advisor 方法的前置顾问 */ public void setBeforeAdvisor(Advisor advisor) { this.beforeAdvisor = advisor; } /** * 设置方法的后置顾问. * @param advisor 方法的后置顾问 */ public void setAfterAdvisor(Advisor advisor) { this.afterAdvisor = advisor; } }
    在上类中,前置和后置顾问对象都继承Advisor接口,接下来让我们来看看顾问接口类的内容,该类定义了doInAdvisor(Object proxy, Method method, Object[] args)方法,如下所示:
package org.amigo.proxy; import java.lang.reflect.Method; /** * * 顾问接口类. * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a> * Creation date: 2007-10-7 - 上午10:21:18 */ public interface Advisor { /** * 所做的操作. */ public void doInAdvisor(Object proxy, Method method, Object[] args); } BeforeMethodAdvisor和AfterMethodAdvisor都实现了Advisor接口,分别为方法的前置顾问和后置顾问类。 BeforeMethodAdvisor.java文件(前置顾问类)的内容如下所示: package org.amigo.proxy; import java.lang.reflect.Method; /** * * 方法前置顾问,它完成方法的前置操作. * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a> * Creation date: 2007-10-7 - 上午10:19:57 */ public class BeforeMethodAdvisor implements Advisor { /** * 在方法执行前所进行的操作. */ public void doInAdvisor(Object proxy, Method method, Object[] args) { System.out.println("before process " + method); } } AfterMethodAdvisor.java文件(后置顾问类)的内容如下所示: package org.amigo.proxy; import java.lang.reflect.Method; /** * * 方法的后置顾问,它完成方法的后置操作. * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a> * Creation date: 2007-10-7 - 上午10:20:43 */ public class AfterMethodAdvisor implements Advisor { /** * 在方法执行后所进行的操作. */ public void doInAdvisor(Object proxy, Method method, Object[] args) { System.out.println("after process " + method); } }
这两个类分别在方法执行前和方法执行后做一些额外的操作。
       对于在配置文件中对某个bean配置前置或后置处理器,我们可以在bean中增加两个属性aop和aopType,aop的值为对应的前置顾问类或后置顾问类的名称,aopType用于指明该顾问类为前置还是后置顾问,为before时表示为前置处理器,为after时表示为后置处理器,这时候我们需要修改上一篇文章中的BeanFactory.java这个文件,添加其对aop和aopType的处理,修改后的该文件内容如下:

package org.amigo.proxy; import java.io.InputStream; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; import org.dom4j.Attribute; import org.dom4j.Document; import org.dom4j.Element; import org.dom4j.io.SAXReader; /** * bean工厂类. * @author <a href="mailto:xiexingxing1121@126.com">AmigoXie</a> * Creation date: 2007-10-7 - 下午04:04:34 */ public class BeanFactory { private Map<String, Object> beanMap = new HashMap<String, Object>(); /** * bean工厂的初始化. * @param xml xml配置文件 */ public void init(String xml) { try { //读取指定的配置文件 SAXReader reader = new SAXReader(); ClassLoader classLoader = Thread.currentThread().getContextClassLoader(); InputStream ins = classLoader.getResourceAsStream(xml); Document doc = reader.read(ins); Element root = doc.getRootElement(); Element foo; //创建AOP处理器 AopHandler aopHandler = new AopHandler(); //遍历bean for (Iterator i = root.elementIterator("bean"); i.hasNext();) { foo = (Element) i.next(); //获取bean的属性id、class、aop以及aopType Attribute id = foo.attribute("id"); Attribute cls = foo.attribute("class"); Attribute aop = foo.attribute("aop"); Attribute aopType = foo.attribute("aopType"); //配置了aop和aopType属性时,需进行拦截操作 if (aop != null && aopType != null) { //根据aop字符串获取对应的类 Class advisorCls = Class.forName(aop.getText()); //创建该类的对象 Advisor advisor = (Advisor) advisorCls.newInstance(); //根据aopType的类型来设置前置或后置顾问 if ("before".equals(aopType.getText())) { aopHandler.setBeforeAdvisor(advisor); } else if ("after".equals(aopType.getText())) { aopHandler.setAfterAdvisor(advisor); } } //利用Java反射机制,通过class的名称获取Class对象 Class bean = Class.forName(cls.getText()); //获取对应class的信息 java.beans.BeanInfo info = java.beans.Introspector.getBeanInfo(bean); //获取其属性描述 java.beans.PropertyDescriptor pd[] = info.getPropertyDescriptors(); //设置值的方法 Method mSet = null; //创建一个对象 Object obj = bean.newInstance(); //遍历该bean的property属性 for (Iterator ite = foo.elementIterator("property"); ite.hasNext();) { Element foo2 = (Element) ite.next(); //获取该property的name属性 Attribute name = foo2.attribute("name"); String value = null; //获取该property的子元素value的值 for(Iterator ite1 = foo2.elementIterator("value"); ite1.hasNext();) { Element node = (Element) ite1.next(); value = node.getText(); break; } for (int k = 0; k < pd.length; k++) { if (pd[k].getName().equalsIgnoreCase(name.getText())) { mSet = pd[k].getWriteMethod(); //利用Java的反射极致调用对象的某个set方法,并将值设置进去 mSet.invoke(obj, value); } } } //为对象增加前置或后置顾问 obj = (Object) aopHandler.setObject(obj); //将对象放入beanMap中,其中key为id值,value为对象 beanMap.put(id.getText(), obj); } } catch (Exception e) { System.out.println(e.toString()); } } /** * 通过bean的id获取bean的对象. * @param beanName bean的id * @return 返回对应对象 */ public Object getBean(String beanName) { Object obj = beanMap.get(beanName); return obj; } /** * 测试方法. * @param args */ public static void main(String[] args) { BeanFactory factory = new BeanFactory(); factory.init("config.xml"); BusinessObj obj = (BusinessObj) factory.getBean("businessObj"); obj.process(); } }
    观察此类我们可以发现,该类添加了对bean元素的aop和aopType属性的处理。编写完该文件后,我们还需要修改src目录下的配置文件:config.xml文件,在该文件中添加名为businessObj的bean,我们为其配置了aop和aopType属性,增加了方法的前置顾问。增加的部分为:

<bean id="businessObj" class="org.amigo.proxy.BusinessObjImpl" aop="org.amigo.proxy.BeforeMethodAdvisor" aopType="before"/>
       此时运行BeanFactory.java这个类文件,运行结果如下:
before process public abstract void org.amigo.proxy.BusinessObj.process()
执行业务逻辑
       由运行结果可以看出,前置处理已经生效。
       本节中的例子只是实现了Spring的AOP一小部分功能,即为某个bean添加前置或后置处理,在Spring中,考虑的比这多很多,例如,为多个bean配置动态代理等等。但是究其根源,Spring中AOP的实现,是基于Java中无比强大的反射和动态代理机制。
 
四.总结
       本文讲述了AOP的概念等信息,并详细讲解了Java的动态代理机制,接着又通过一个简单的实例讲解了Spring中AOP的模拟实现,使得读者能够更好地学习Java的反射和代理机制。
通过这两篇文章,使得我们能够更加深入地理解Java的反射和动态代理机制,同时对Spring中盛行的IOC和AOP的后台实现原理有了更加清晰的理解,Java的反射和动态代理机制的强大功能在这两篇文章中可见一斑。有兴趣的朋友可以通过学习Spring框架的源码来进一步的理解Java的反射和动态代理机制,从而在实际的开发工作中更好地理解它。
1 2 3
©版权所有。未经许可,不得转载。
[责任编辑:李宁]
[an error occurred while processing this directive]