代理机制可以提高程序的灵活性,我们可以为具有相同接口的目标的方法进行拦截,并加上相应的处理,返回给客户端。
代理类的好处:生成代理类后但你想要改变程序是不需要改变源程序。
静态代理模式在现实编程中的弊端:
它的特征是代理类和目标对象的类都是在编译期间确定下来的,不利于程序上的扩展,上面示例中,如果客户还想找一个“生产一批鞋子”的工厂,那么还需要新增加一个代理类和一个目标类。如果客户还需要很多其他的服务,就必须一一的添加代理类和目标类。那就需要写很多的代理类和目标类。
动态代理:
动态代理的原理就是,在程序运行时根据需要,动态创建目标类的代理对象。动态代理对客户隐藏了目标,客户不知道为他服务的是代理,还是目标。
动态代理原理:
利用反射机制在运行时动态创建目标对象的代理对象。
编码实现:
Advice接口:定义相应的方法
import java.lang.reflect.Method;
public interface Advice {
void beforeMethod(Method method);
void afterMethod(Method method);
}
import java.lang.reflect.Method;
public class MyAdvice implements Advice {
long startTime = 0;
@Override
public void afterMethod(Method method) {
System.out.println("走了");
long endTime = System.currentTimeMillis();
System.out.println(method.getName()+" running time of "+(endTime - startTime));
}
@Override
public void beforeMethod(Method method) {
System.out.println("来了");
startTime = System.currentTimeMillis();
}
}
Proxy代理类:动态创建一个代理,代理类的每个方法调用目标类的相同方法,并加上Advice提供的方法代码块;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;
public class ProxyTest {
public static void main(String[] args) throws Exception {
//创建一个实现了Collection接口的代理
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
System.out.println("---------------begin contructors list");
Constructor[] constructors = clazzProxy1.getConstructors();
for(Constructor constructor : constructors){
String name = constructor.getName();
StringBuilder sb = new StringBuilder(name);
sb.append('(');
Class[] clazzParams = constructor.getParameterTypes();
for(Class clazzParam : clazzParams){
sb.append(clazzParam.getName()+',');
}
if(clazzParams != null && clazzParams.length > 0)
sb.delete(sb.length()-1, sb.length());
sb.append(')');
System.out.println(sb);
}
System.out.println("---------------begin methods list");
Method[] methods = clazzProxy1.getMethods();
for(Method method : methods){
String name = method.getName();
StringBuilder sb = new StringBuilder(name);
sb.append('(');
Class[] clazzParams = method.getParameterTypes();
for(Class clazzParam : clazzParams){
sb.append(clazzParam.getName()+',');
}
if(clazzParams != null && clazzParams.length > 0)
sb.delete(sb.length()-1, sb.length());
sb.append(')');
System.out.println(sb);
}
System.out.println("---------------begin creat instance object list");
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
class MyInvocationHander1 implements InvocationHandler{
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// TODO Auto-generated method stub
return null;
}
}
//使用得到的有参构造方法来创建一个实例对象
Collection proxy1 = (Collection) constructor.newInstance(new MyInvocationHander1());
System.out.println(proxy1.toString());
proxy1.clear();
//proxy1.size();
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});
ArrayList target = new ArrayList();
final Collection proxy3 = (Collection)getproxy(target,new MyAdvice());
/*
//生成的Collection接口中的方法的运行原理
int size()
{
retunr handler.invoke(this,this.getClass().getMethod("size"),null);
}
void clear()
{
retunr handler.invoke(this,this.getClass().getMethod("clear"),null);
}
*/
proxy3.add("zxx");
proxy3.add("lhm");
proxy3.add("bxd");
System.out.println(proxy3.size());
//只有hashCode(),equas(),toString()这3个从Object继承的方法被指派到调用处理程序的 invoke 方法
//而其他的继承自Object的方法如getClass()则没有被动态代理指派到相应的invoke方法中去
System.out.println(proxy3.getClass().getName());
}
private static Object getproxy(final Object target,final Advice advice) {
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
/*new Class[]{Collection.class}, */
target.getClass().getInterfaces(),
new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
advice.beforeMethod(method);
Object retVal = method.invoke(target, args);
advice.afterMethod(method);
return retVal;
}
});
return proxy3;
}
}