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的反射和动态代理机制,从而在实际的开发工作中更好地理解它。