如果需要为许多方法添加额外的操作,就如数据库的事务日志,你需要对数据库的每一项操作都做个记录,
那么多的方法,如果手工编写的话,不仅费时,而且臃肿不堪。这时候java代理技术就起作用了,通过java的动态代理可以非常方便的为一个类的多种方法添加额外的操作。
在java中有一个类是 java.lang.reflect.Proxy;他的一个方法可以非常方便的创建代理对象
Objectjava.lang.reflect.Proxy.newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) throwsIllegalArgumentException
它接收三个参数:
1.loader 代理目标类用哪个加载器加载,
2.interfaces 需要为目标类的哪些方法添加操作,通过传入目标类所实现的接口而获取
3.InvocationHandler 这是一个抽象类,你需要实现它的invoke() 方法用来添加额外的操作
在添加额外的操作时可以通过传入通告对象,执行通告对象的方法来实现。
有了这三样东西,就可以动态构建一个为目标类生产的代理对象了。
那么,为了将这些操作构建为一个框架,我们需要下面2个元素:
1. 代理目标:要为哪个类构建代理 (什么来加载器,接口,都可以通过反射反射该类得到)
2. 通告对象:所有的额外操作都可以通过调用该对象的方法实现
现在这些元素写在一个配置文件中,以便于更改 如下
-----------------------------
config.propertice
className=java.util.ArrayList
class.Advice=MyAdvice
----------------------------
还可以直接指定目标类,和通告对象
-----------------------------
setTarget(Object target)
setAdvice(Object advice)
-------------------------------
有了这些元素,就可以开始编写代理类了
类结构上图
其中的方法getProxy()内部就是调用的newProxyInstance
=============分割线,下面是源代码=============================================
package zhangweiocng.autoProxy;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Properties;
import java.util.ArrayList;
/**
*
* 要想获得一个代理类,必须先传入一个配置好的文件,或者指定目标类和通告类
* @author weicong
*
*/
public class AutoProxy {
private Object target;
private Advice advice;
private Properties properties;
public Object getProxy(){
Object clazz = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforeMethod(method);
Object returnValue =method.invoke(target, args);
System.out.println("--executeMethod--"+method.getName());
advice.afterMethod(method);
return returnValue;
}
}
);
return clazz;
}
public void setProperties(InputStream inStream){
this.properties=new Properties();
try {
properties.load(inStream);
target=getTarget();
advice=getAdvice();
} catch (IOException e) {
System.out.println("未成功加载配置文件");
e.printStackTrace();
}
}
public Object getTarget() {
String targetName = properties.getProperty("className.target");
Object target = null;
try {
Class clazz = Class.forName(targetName);
target = clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException e) {
System.out.println("target类加载出错");
e.printStackTrace();
}
return target;
}
public void setTarget(Object target) {
this.target = target;
}
public Advice getAdvice() {
String adviceName = properties.getProperty("className.advice");
Advice advice = null;
try {
Class clazz = Class.forName(adviceName);
advice = (Advice)clazz.newInstance();
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException e) {
System.out.println("advice类加载出错");
e.printStackTrace();
}
return advice;
}
public void setAdvice(Advice advice) {
this.advice = advice;
}
}
-----------------文件分割标记-----------------------------------------------------------
package zhangweiocng.autoProxy;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collection;
public class AutoProxyTest {
public static void main(String[] args) {
AutoProxy autoProxy=new AutoProxy();
Advice advice=new MyAdvice();
ArrayList arrayList=new ArrayList();
InputStream inStream=null;
Collection proxy=null;
/*
* 通过配置文件指定目标类和通告类
* try{
inStream=new FileInputStream("config.properties");
autoProxy.setProperties(inStream);
proxy=( Collection )autoProxy.getProxy();
proxy.add("123");
proxy.add("456");
System.out.println(arrayList.toString());
System.out.println(arrayList.size());
}catch(IOException e){
System.out.println("文件不存在");
e.printStackTrace();
}*/
/*显式指定目标类和通告类*/
autoProxy.setTarget(arrayList);
autoProxy.setAdvice(advice);
proxy=(Collection )autoProxy.getProxy();
proxy.add("123");
proxy.add("456");
System.out.println(arrayList.toString());
System.out.println(arrayList.size());
}
}