一、现实生活中的代理?
在现实生活中,我们常见的有服务器代理商、联想PC代理商、百事可乐、火车票、机票等代理商,为什么会有这些个代理商呢?设想以买火车票为场景,如果我要买一张从广州去长沙的火车票,就必须去火车站排队购票,如果排队的人比较多的话,非常的耽误时间。但有了火车票代理商之后,我就可以直接去找个离我最近的代理商买票,因为这样的代理商不止一个二个,遍布全市各地。 所以代理商的出现不但减轻了火车站售票员的工作压力,同时也为市民购票提供了许多方便。只是代理商会收5块的手续费。从这个示例中可以发现和买票有关的一些名词:火车站、售票、代理商?解释这些名词在程序中代理的含义:火车站:称为目标,售票:目标的最终行为,代理商:和火车站具有同样售票行为的代理商,不过代理商在售票前和售票后会做一些操作,比如查询余票、售票后收取手续费等操作。
二、JDK中的代理
1、特征:
1)、jdk中代理的一个很重要的特征:代理类和目标类都拥有相同的接口,所以它们都拥有相同的行为。代理类的对象本身并不真正提供服务,而是调用目标类对象的相关方法,来提供特定的服务。如:火车票代理商自己并不提供火车票销售的服务,而是调用火车站的售票服务。为顾客提供查询余票信息、火车的运营时间、火车票的销售等服务,这些服务都是来自火车站(目标类)。代理类主要负责为目标类预处理消息(如:身份证信息是否正确)、过滤消息(如:该顾客是否为通缉犯,是否公安监视的人),并把这些消息转发给目标类,以及事后处理消息(收取顾客的手续费)等。
2)、必须实现一个或多个接口
2、代理种类:
1)、静态代理,示例:以销售火车票为例
a、定义一个火车站售票的接口
- package proxy;
- public interface Ticket {
- public void ticket();
- }
package proxy;
public interface Ticket {
public void ticket();
}
b、售票接口的实现类
- package proxy;
- public class TicketImpl implements Ticket {
- @Override
- public void ticket() {
- System.out.println("成功售出一张火车票!");
- }
- }
package proxy;
public class TicketImpl implements Ticket {
@Override
public void ticket() {
System.out.println("成功售出一张火车票!");
}
}
c、火车票销售的代理类,与目标类实现了相同的接口
- package proxy;
- /**
- * 火车票销售代理类
- */
- public class TicketImplProxy implements Ticket {
- private TicketImpl ticketImpl; //目标类
- public TicketImplProxy(TicketImpl ticketImpl) {
- this.ticketImpl = ticketImpl;
- }
- @Override
- public void ticket() {
- System.out.println("售票前验证顾客的身份信息…………");
- ticketImpl.ticket();
- System.out.println("售票后收取顾客的手续费…………");
- }
- }
package proxy;
/**
* 火车票销售代理类
*/
public class TicketImplProxy implements Ticket {
private TicketImpl ticketImpl; //目标类
public TicketImplProxy(TicketImpl ticketImpl) {
this.ticketImpl = ticketImpl;
}
@Override
public void ticket() {
System.out.println("售票前验证顾客的身份信息…………");
ticketImpl.ticket();
System.out.println("售票后收取顾客的手续费…………");
}
}
d、测试类:
- package proxy;
- public class StaticProxyTest {
- public static void main(String[] args) throws Exception {
- TicketImpl ticketImpl = new TicketImpl(); //要代理的目标
- TicketImplProxy staticProxy = new TicketImplProxy(ticketImpl);
- staticProxy.ticket();
- }
- }
package proxy;
public class StaticProxyTest {
public static void main(String[] args) throws Exception {
TicketImpl ticketImpl = new TicketImpl(); //要代理的目标
TicketImplProxy staticProxy = new TicketImplProxy(ticketImpl);
staticProxy.ticket();
}
}
运行结果:
静态代理的缺陷:
一个代理类只能代理一个目标类,如果在一个系统中想代理多个目标类的话,就得写多个代理类,这将是一件很繁琐的工作。所以在JDK1.3之后,引出了动态代理的概念,动态代理可以在程序运行的时候,通过反射机制动态的生成一个类的字节码文件,并实现目标类相同的接口。
2)、动态代理
1)、介绍:
jdk中的动态代理,主要用到了java.lang.reflect包中的两个类:Proxy类和InvocationHandler接口,Proxy类用于生成代理类,InvocationHandler接口用于调用目标类的方法之前或之后,做一些处理。比如:记录日志、事务处理、效率测试等,均在该接口的invoke方法中实现。传说中AOP思想的原理就是从这里开始扩展的。
2)、动态代理机制深入分析(以ArrayList为代理目标类为例):
1、使用Proxy类的getProxyClass方法,获得ArrayList代理类的字节码文件
- Class clazzProxy = Proxy.getProxyClass(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces());
Class clazzProxy = Proxy.getProxyClass(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces());
2、打印代理类的结构信息
获得这个Class对象的字节码文件之后,我们打印出来看看这个类的名字叫什么?
- System.out.println("代理类名称:" + clazzProxy.getName());
System.out.println("代理类名称:" + clazzProxy.getName());
代理类名称:$Proxy0
通过JDK反射机制,获代理类的结构,比如:它的父类是谁?实现了哪些接口?有哪些个构造方法?有哪些个成员方法?等。。。
下面将通反射机制,获取这个代理类的组织结构信息:
- System.out.println("代理类" + clazzProxy.getName() + "的父类:" + clazzProxy.getSuperclass().getName());
System.out.println("代理类" + clazzProxy.getName() + "的父类:" + clazzProxy.getSuperclass().getName());
代理类$Proxy0的父类:java.lang.reflect.Proxy
- Class[] clazzInterfaces = clazzProxy.getInterfaces();
- StringBuilder sbInterfaces = new StringBuilder();
- for (Class clazzInterface : clazzInterfaces) {
- sbInterfaces.append(clazzInterface.getName()).append(",");
- }
- sbInterfaces.deleteCharAt(sbInterfaces.length()-1);
- System.out.println("代理类" + clazzProxy.getName() + "所实现的接口:" + sbInterfaces);
Class[] clazzInterfaces = clazzProxy.getInterfaces();
StringBuilder sbInterfaces = new StringBuilder();
for (Class clazzInterface : clazzInterfaces) {
sbInterfaces.append(clazzInterface.getName()).append(",");
}
sbInterfaces.deleteCharAt(sbInterfaces.length()-1);
System.out.println("代理类" + clazzProxy.getName() + "所实现的接口:" + sbInterfaces);
代理类$Proxy0所实现的接口:java.util.List,java.util.RandomAccess,java.lang.Cloneable,java.io.Serializable
- System.out.println("代理类" + clazzProxy.getName() + "的访问修饰符:" + clazzProxy.getModifiers());
System.out.println("代理类" + clazzProxy.getName() + "的访问修饰符:" + clazzProxy.getModifiers());
代理类$Proxy0的访问修饰符:17
由访问修饰符的值可得知代理类的修饰符为:代理类的访问修饰符为:public final,由clazzProxy.getModifiers();得知为17,其中public代表1,final代表16,相加得17。参考java.lang.reflect.Modifier
- System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的构造方法列表-------------");
- Constructor[] constructors = clazzProxy.getConstructors();
- for (Constructor constructor : constructors) {
- System.out.println("访问修饰符:" + constructor.getModifiers());
- String name = constructor.getName();
- int modifiers = constructor.getModifiers();
- StringBuilder sb = new StringBuilder(name);
- sb.append('(');
- Class[] clazzParameters = constructor.getParameterTypes();
- for (Class clazzParameter : clazzParameters) {
- sb.append(clazzParameter.getName()).append(",");
- }
- if (clazzParameters != null && clazzParameters.length != 0) {
- sb.deleteCharAt(sb.length()-1);
- }
- sb.append(')');
- System.out.println(sb.toString());
- }
System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的构造方法列表-------------");
Constructor[] constructors = clazzProxy.getConstructors();
for (Constructor constructor : constructors) {
System.out.println("访问修饰符:" + constructor.getModifiers());
String name = constructor.getName();
int modifiers = constructor.getModifiers();
StringBuilder sb = new StringBuilder(name);
sb.append('(');
Class[] clazzParameters = constructor.getParameterTypes();
for (Class clazzParameter : clazzParameters) {
sb.append(clazzParameter.getName()).append(",");
}
if (clazzParameters != null && clazzParameters.length != 0) {
sb.deleteCharAt(sb.length()-1);
}
sb.append(')');
System.out.println(sb.toString());
}
-------------打印代理类$Proxy0的构造方法列表-------------
访问修饰符:
1
$Proxy0(java.lang.reflect.InvocationHandler)
$Proxy0(java.lang.reflect.InvocationHandler)
- System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的方法列表-------------");
- Method[] methods = clazzProxy.getMethods();
- for (Method method : methods) {
- String name = method.getName();
- StringBuilder sb = new StringBuilder(name);
- sb.append('(');
- Class[] clazzParameters = method.getParameterTypes();
- for (Class clazzParameter : clazzParameters) {
- sb.append(clazzParameter.getName()).append(",");
- }
- if (clazzParameters != null && clazzParameters.length != 0) {
- sb.deleteCharAt(sb.length()-1);
- }
- sb.append(')');
- System.out.println(sb.toString());
- }
System.out.println("\n-------------打印代理类" + clazzProxy.getName() + "的方法列表-------------");
Method[] methods = clazzProxy.getMethods();
for (Method method : methods) {
String name = method.getName();
StringBuilder sb = new StringBuilder(name);
sb.append('(');
Class[] clazzParameters = method.getParameterTypes();
for (Class clazzParameter : clazzParameters) {
sb.append(clazzParameter.getName()).append(",");
}
if (clazzParameters != null && clazzParameters.length != 0) {
sb.deleteCharAt(sb.length()-1);
}
sb.append(')');
System.out.println(sb.toString());
}
打印结果:
- -------------打印代理类$Proxy0的方法列表-------------
- add(java.lang.Object)
- add(int,java.lang.Object)
- get(int)
- equals(java.lang.Object)
- toString()
- hashCode()
- indexOf(java.lang.Object)
- clear()
- contains(java.lang.Object)
- isEmpty()
- lastIndexOf(java.lang.Object)
- addAll(java.util.Collection)
- addAll(int,java.util.Collection)
- iterator()
- size()
- toArray()
- toArray([Ljava.lang.Object;)
- remove(java.lang.Object)
- remove(int)
- set(int,java.lang.Object)
- containsAll(java.util.Collection)
- removeAll(java.util.Collection)
- retainAll(java.util.Collection)
- subList(int,int)
- listIterator()
- listIterator(int)
- isProxyClass(java.lang.Class)
- getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
- getInvocationHandler(java.lang.Object)
- newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
- wait(long)
- wait()
- wait(long,int)
- getClass()
- notify()
- notifyAll()
-------------打印代理类$Proxy0的方法列表-------------
add(java.lang.Object)
add(int,java.lang.Object)
get(int)
equals(java.lang.Object)
toString()
hashCode()
indexOf(java.lang.Object)
clear()
contains(java.lang.Object)
isEmpty()
lastIndexOf(java.lang.Object)
addAll(java.util.Collection)
addAll(int,java.util.Collection)
iterator()
size()
toArray()
toArray([Ljava.lang.Object;)
remove(java.lang.Object)
remove(int)
set(int,java.lang.Object)
containsAll(java.util.Collection)
removeAll(java.util.Collection)
retainAll(java.util.Collection)
subList(int,int)
listIterator()
listIterator(int)
isProxyClass(java.lang.Class)
getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
getInvocationHandler(java.lang.Object)
newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
wait(long)
wait()
wait(long,int)
getClass()
notify()
notifyAll()
这些方法分别来自List接口、Proxy和Object类,因为代理类会自动实现目标类相同的接口。
- //由上述信息可推断出代理类的文件结构(程序中只实现打印代理类的声明部份)
- StringBuilder sbProxyClassStruct = new StringBuilder("public final class ");
- sbProxyClassStruct.append(clazzProxy.getName())
- .append(" extends ").append(clazzProxy.getSuperclass().getName())
- .append(" implements ").append(sbInterfaces).append(" { } ");
- System.out.println("代理类的结构:" + sbProxyClassStruct);
//由上述信息可推断出代理类的文件结构(程序中只实现打印代理类的声明部份)
StringBuilder sbProxyClassStruct = new StringBuilder("public final class ");
sbProxyClassStruct.append(clazzProxy.getName())
.append(" extends ").append(clazzProxy.getSuperclass().getName())
.append(" implements ").append(sbInterfaces).append(" { } ");
System.out.println("代理类的结构:" + sbProxyClassStruct);
程序中只打印了代理类的声明部份,结果:
代理类声明部份的结构:public final class $Proxy0 extends java.lang.reflect.Proxy implements java.util.List,java.util.RandomAccess,java.lang.Cloneable,java.io.Serializable { }
由上述信息可推断出代理类的文件结构:
- package proxy;
- import java.lang.reflect.InvocationHandler;
- import java.util.Collection;
- import java.util.Iterator;
- import java.util.List;
- import java.util.ListIterator;
- public final class $Proxy0 extends java.lang.reflect.Proxy implements java.util.List,
- java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
- public $Proxy0(InvocationHandler h) {
- super(h);
- // TODO Auto-generated constructor stub
- }
- @Override
- public boolean add(Object e) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public void add(int index, Object element) {
- // TODO Auto-generated method stub
- }
- @Override
- public boolean addAll(Collection c) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean addAll(int index, Collection c) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public void clear() {
- // TODO Auto-generated method stub
- }
- @Override
- public boolean contains(Object o) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean containsAll(Collection c) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public Object get(int index) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int indexOf(Object o) {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public boolean isEmpty() {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public Iterator iterator() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int lastIndexOf(Object o) {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public ListIterator listIterator() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public ListIterator listIterator(int index) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public boolean remove(Object o) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public Object remove(int index) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public boolean removeAll(Collection c) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public boolean retainAll(Collection c) {
- // TODO Auto-generated method stub
- return false;
- }
- @Override
- public Object set(int index, Object element) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public int size() {
- // TODO Auto-generated method stub
- return 0;
- }
- @Override
- public List subList(int fromIndex, int toIndex) {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Object[] toArray() {
- // TODO Auto-generated method stub
- return null;
- }
- @Override
- public Object[] toArray(Object[] a) {
- // TODO Auto-generated method stub
- return null;
- }
- }
package proxy;
import java.lang.reflect.InvocationHandler;
import java.util.Collection;
import java.util.Iterator;
import java.util.List;
import java.util.ListIterator;
public final class $Proxy0 extends java.lang.reflect.Proxy implements java.util.List,
java.util.RandomAccess, java.lang.Cloneable, java.io.Serializable {
public $Proxy0(InvocationHandler h) {
super(h);
// TODO Auto-generated constructor stub
}
@Override
public boolean add(Object e) {
// TODO Auto-generated method stub
return false;
}
@Override
public void add(int index, Object element) {
// TODO Auto-generated method stub
}
@Override
public boolean addAll(Collection c) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean addAll(int index, Collection c) {
// TODO Auto-generated method stub
return false;
}
@Override
public void clear() {
// TODO Auto-generated method stub
}
@Override
public boolean contains(Object o) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean containsAll(Collection c) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object get(int index) {
// TODO Auto-generated method stub
return null;
}
@Override
public int indexOf(Object o) {
// TODO Auto-generated method stub
return 0;
}
@Override
public boolean isEmpty() {
// TODO Auto-generated method stub
return false;
}
@Override
public Iterator iterator() {
// TODO Auto-generated method stub
return null;
}
@Override
public int lastIndexOf(Object o) {
// TODO Auto-generated method stub
return 0;
}
@Override
public ListIterator listIterator() {
// TODO Auto-generated method stub
return null;
}
@Override
public ListIterator listIterator(int index) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean remove(Object o) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object remove(int index) {
// TODO Auto-generated method stub
return null;
}
@Override
public boolean removeAll(Collection c) {
// TODO Auto-generated method stub
return false;
}
@Override
public boolean retainAll(Collection c) {
// TODO Auto-generated method stub
return false;
}
@Override
public Object set(int index, Object element) {
// TODO Auto-generated method stub
return null;
}
@Override
public int size() {
// TODO Auto-generated method stub
return 0;
}
@Override
public List subList(int fromIndex, int toIndex) {
// TODO Auto-generated method stub
return null;
}
@Override
public Object[] toArray() {
// TODO Auto-generated method stub
return null;
}
@Override
public Object[] toArray(Object[] a) {
// TODO Auto-generated method stub
return null;
}
}
由上述信息得知该代理类只有一个带InvocationHandler参数的构造方法,现在我们来生成这个代理类的实例对象:
- //方式1,创建一个内部类,并实现InvocationHandler接口
- Constructor proxy1 = clazzProxy.getConstructor(InvocationHandler.class);
- System.out.println("------------创建代理类实例,方式1--------------------");
- class MyInvocationHandler implements InvocationHandler {
- ArrayList target = new ArrayList();
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- String name = method.getName();
- System.out.println(name + "方法调用前...");
- Object retVal = method.invoke(target, args);
- System.out.println(name + "方法调用后的返回结果为:" + retVal);
- System.out.println(name + "方法调用后...\n");
- return retVal;
- }
- }
- List list1 = (List)proxy1.newInstance(new MyInvocationHandler());
- list1.add("zhangsan");
- list1.add("lisi");
- System.out.println(list1.size());
//方式1,创建一个内部类,并实现InvocationHandler接口
Constructor proxy1 = clazzProxy.getConstructor(InvocationHandler.class);
System.out.println("------------创建代理类实例,方式1--------------------");
class MyInvocationHandler implements InvocationHandler {
ArrayList target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
String name = method.getName();
System.out.println(name + "方法调用前...");
Object retVal = method.invoke(target, args);
System.out.println(name + "方法调用后的返回结果为:" + retVal);
System.out.println(name + "方法调用后...\n");
return retVal;
}
}
List list1 = (List)proxy1.newInstance(new MyInvocationHandler());
list1.add("zhangsan");
list1.add("lisi");
System.out.println(list1.size());
调用List接口的add方法和size方法后的输出结果:
---------------------创建代理类$Proxy0的实例对象----------------------
------------创建代理类实例,方式1--------------------
add方法调用前...
add方法调用后的返回结果为:true
add方法调用后...
add方法调用前...
add方法调用后的返回结果为:true
add方法调用后...
size方法调用前...
size方法调用后的返回结果为:2
size方法调用后...
2
------------创建代理类实例,方式1--------------------
add方法调用前...
add方法调用后的返回结果为:true
add方法调用后...
add方法调用前...
add方法调用后的返回结果为:true
add方法调用后...
size方法调用前...
size方法调用后的返回结果为:2
size方法调用后...
2
- //方式2
- Constructor prox2 = clazzProxy.getConstructor(InvocationHandler.class);
- List list2 = (List)prox2.newInstance(new InvocationHandler() {
- List target = new ArrayList();
- @Override
- public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
- Object retVal = method.invoke(target, args);
- return retVal;
- }}
- );
//方式2
Constructor prox2 = clazzProxy.getConstructor(InvocationHandler.class);
List list2 = (List)prox2.newInstance(new InvocationHandler() {
List target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object retVal = method.invoke(target, args);
return retVal;
}}
);
- //方式3(匿名类),将创建代理类和创建代理类实例对象的步聚合二为一
- System.out.println("------------创建代理类实例,方式3--------------------");
- List list3 = (List)Proxy.newProxyInstance(
- ArrayList.class.getClassLoader(),
- ArrayList.class.getInterfaces(),
- new InvocationHandler() {
- ArrayList target = new ArrayList();
- @Override
- public Object invoke(Object proxy, Method method,
- Object[] args) throws Throwable {
- //测试方法的运行效率
- long beginTime = System.currentTimeMillis();
- Object retVal = method.invoke(target, args);
- long endTime = System.currentTimeMillis();
- System.out.println(method.getName() + " 方法运行时长为:" + (endTime - beginTime));
- return retVal;
- }}
- );
- list3.add("hy");
- list3.add("yangxin");
- System.out.println(list3.size());
//方式3(匿名类),将创建代理类和创建代理类实例对象的步聚合二为一
System.out.println("------------创建代理类实例,方式3--------------------");
List list3 = (List)Proxy.newProxyInstance(
ArrayList.class.getClassLoader(),
ArrayList.class.getInterfaces(),
new InvocationHandler() {
ArrayList target = new ArrayList();
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
//测试方法的运行效率
long beginTime = System.currentTimeMillis();
Object retVal = method.invoke(target, args);
long endTime = System.currentTimeMillis();
System.out.println(method.getName() + " 方法运行时长为:" + (endTime - beginTime));
return retVal;
}}
);
list3.add("hy");
list3.add("yangxin");
System.out.println(list3.size());
输出结果:
------------创建代理类实例,方式3--------------------
add 方法运行时长为:0
add 方法运行时长为:0
size 方法运行时长为:0
2
add 方法运行时长为:0
add 方法运行时长为:0
size 方法运行时长为:0
2
*通过以上代码的分析,可将生成代理类的代码,抽取成一个生成代理的通用方法,并将功能代码用一个对象封装起来(如:测试方法的运行时间,方法运行前或运行后需要做的事情)
- /**
- * 获得代理对象
- * @param target 目标(被代理的对象)
- * @param advice 目标对象中的方法被调用前要执行的功能
- * @return 目标的代理对象
- */
- private static Object getProxy(final Object target,final Advice advice) {
- return Proxy.newProxyInstance(
- target.getClass().getClassLoader(),
- target.getClass().getInterfaces(),
- new InvocationHandler() {
- @Override
- public Object invoke(Object proxy, Method method,
- Object[] args) throws Throwable {
- Object retVal = null;
- try {
- advice.doBefore(target, method, args);//方法执行前
- retVal = method.invoke(target, args);
- advice.doAfter(target, method, args, retVal);//方法执行后
- } catch (Exception e) {
- advice.doThrow(target, method, args, e);//方法抛出异常
- } finally {
- advice.doFinally(target, method, args);//方法最终执行代码(用于释放数据资源、关闭IO流等操作)
- }
- return retVal;
- }}
- );
- }
/**
* 获得代理对象
* @param target 目标(被代理的对象)
* @param advice 目标对象中的方法被调用前要执行的功能
* @return 目标的代理对象
*/
private static Object getProxy(final Object target,final Advice advice) {
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method,
Object[] args) throws Throwable {
Object retVal = null;
try {
advice.doBefore(target, method, args);//方法执行前
retVal = method.invoke(target, args);
advice.doAfter(target, method, args, retVal);//方法执行后
} catch (Exception e) {
advice.doThrow(target, method, args, e);//方法抛出异常
} finally {
advice.doFinally(target, method, args);//方法最终执行代码(用于释放数据资源、关闭IO流等操作)
}
return retVal;
}}
);
}
封装功能的对象:- package proxy;
- import java.lang.reflect.Method;
- /**
- * aop接口,提供方法运行前、方法运行后、方法运行中产生Exception、方法最终运行代码
- *
- */
- public interface Advice {
- /**
- * 方法运行前
- * @param target 被代理的目标对象
- * @param method 被调用的方法
- * @param args 方法的参数
- */
- public void doBefore(Object target, Method method, Object[] args);
- /**
- * 方法运行后
- * @param target 被代理的目标对象
- * @param method 被调用的方法对象
- * @param args 方法的参数
- * @param retVal 方法的返回值
- */
- public void doAfter(Object target, Method method, Object[] args, Object retVal);
- /**
- * 方法运行时产生的异常
- * @param target 被代理的目标对象
- * @param method 被调用的方法
- * @param args 方法参数
- * @param e 运行时的异常对象
- */
- public void doThrow(Object target, Method method, Object[] args, Exception e);
- /**
- * 最终要执行的功能(如释放数据库连接的资源、关闭IO流等)
- * @param target 被代理的目标对象
- * @param method 被调用的方法
- * @param args 方法参数
- */
- public void doFinally(Object target, Method method, Object[] args);
- }
package proxy;
import java.lang.reflect.Method;
/**
* aop接口,提供方法运行前、方法运行后、方法运行中产生Exception、方法最终运行代码
*
*/
public interface Advice {
/**
* 方法运行前
* @param target 被代理的目标对象
* @param method 被调用的方法
* @param args 方法的参数
*/
public void doBefore(Object target, Method method, Object[] args);
/**
* 方法运行后
* @param target 被代理的目标对象
* @param method 被调用的方法对象
* @param args 方法的参数
* @param retVal 方法的返回值
*/
public void doAfter(Object target, Method method, Object[] args, Object retVal);
/**
* 方法运行时产生的异常
* @param target 被代理的目标对象
* @param method 被调用的方法
* @param args 方法参数
* @param e 运行时的异常对象
*/
public void doThrow(Object target, Method method, Object[] args, Exception e);
/**
* 最终要执行的功能(如释放数据库连接的资源、关闭IO流等)
* @param target 被代理的目标对象
* @param method 被调用的方法
* @param args 方法参数
*/
public void doFinally(Object target, Method method, Object[] args);
}
再建一个日志功能的实现类LogAdvice,用于测试:
- package proxy;
- import java.lang.reflect.Method;
- import java.util.Arrays;
- /**
- * 日志功能切入类
- * @author 杨信
- *
- */
- public class LogAdvice implements Advice {
- long beginTime = System.currentTimeMillis();
- @Override
- public void doBefore(Object target, Method method, Object[] args) {
- System.out.println(target.getClass().getSimpleName() +
- "." + method.getName() + "方法被调用,参数值:" + Arrays.toString(args));
- }
- @Override
- public void doAfter(Object target, Method method, Object[] args, Object retVal) {
- long endTime = System.currentTimeMillis();
- System.out.println(target.getClass().getSimpleName() +
- "." + method.getName() + "方法运行结束,返回值:" + retVal + ",耗时" + (endTime - beginTime) + "毫秒。");
- }
- @Override
- public void doThrow(Object target, Method method, Object[] args,
- Exception e) {
- System.out.println("调用" + target.getClass().getSimpleName() +
- "." + method.getName() + "方法发生异常,异常消息:");
- e.printStackTrace();
- }
- @Override
- public void doFinally(Object target, Method method, Object[] args) {
- System.out.println("doFinally...");
- }
- }
package proxy;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 日志功能切入类
* @author 杨信
*
*/
public class LogAdvice implements Advice {
long beginTime = System.currentTimeMillis();
@Override
public void doBefore(Object target, Method method, Object[] args) {
System.out.println(target.getClass().getSimpleName() +
"." + method.getName() + "方法被调用,参数值:" + Arrays.toString(args));
}
@Override
public void doAfter(Object target, Method method, Object[] args, Object retVal) {
long endTime = System.currentTimeMillis();
System.out.println(target.getClass().getSimpleName() +
"." + method.getName() + "方法运行结束,返回值:" + retVal + ",耗时" + (endTime - beginTime) + "毫秒。");
}
@Override
public void doThrow(Object target, Method method, Object[] args,
Exception e) {
System.out.println("调用" + target.getClass().getSimpleName() +
"." + method.getName() + "方法发生异常,异常消息:");
e.printStackTrace();
}
@Override
public void doFinally(Object target, Method method, Object[] args) {
System.out.println("doFinally...");
}
}
测试生成代理的通用方法:
- ArrayList target = new ArrayList();
- List list4 = (List)getProxy(target,new LogAdvice());
- list4.add("张三");
- list4.add("李四");
- list4.add("王五");
- System.out.println(list4.size());
- list4.get(3); //演示异常advice
ArrayList target = new ArrayList();
List list4 = (List)getProxy(target,new LogAdvice());
list4.add("张三");
list4.add("李四");
list4.add("王五");
System.out.println(list4.size());
list4.get(3); //演示异常advice
输出结果:
- ArrayList.add方法被调用,参数值:[张三]
- ArrayList.add方法运行结束,返回值:true,耗时0毫秒。
- doFinally...
- ArrayList.add方法被调用,参数值:[李四]
- ArrayList.add方法运行结束,返回值:true,耗时0毫秒。
- doFinally...
- ArrayList.add方法被调用,参数值:[王五]
- ArrayList.add方法运行结束,返回值:true,耗时0毫秒。
- doFinally...
- ArrayList.size方法被调用,参数值:null
- ArrayList.size方法运行结束,返回值:3,耗时0毫秒。
- doFinally...
- 3
- ArrayList.get方法被调用,参数值:[3]
- 调用ArrayList.get方法发生异常,异常消息:
- java.lang.reflect.InvocationTargetException
- at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
- at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
- at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
- at java.lang.reflect.Method.invoke(Method.java:597)
- at proxy.DynamicProxyTest$3.invoke(DynamicProxyTest.java:163)
- at $Proxy0.get(Unknown Source)
- at proxy.DynamicProxyTest.main(DynamicProxyTest.java:143)
- Caused by: java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
- at java.util.ArrayList.RangeCheck(ArrayList.java:547)
- at java.util.ArrayList.get(ArrayList.java:322)
- ... 7 more
- doFinally...
ArrayList.add方法被调用,参数值:[张三]
ArrayList.add方法运行结束,返回值:true,耗时0毫秒。
doFinally...
ArrayList.add方法被调用,参数值:[李四]
ArrayList.add方法运行结束,返回值:true,耗时0毫秒。
doFinally...
ArrayList.add方法被调用,参数值:[王五]
ArrayList.add方法运行结束,返回值:true,耗时0毫秒。
doFinally...
ArrayList.size方法被调用,参数值:null
ArrayList.size方法运行结束,返回值:3,耗时0毫秒。
doFinally...
3
ArrayList.get方法被调用,参数值:[3]
调用ArrayList.get方法发生异常,异常消息:
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at proxy.DynamicProxyTest$3.invoke(DynamicProxyTest.java:163)
at $Proxy0.get(Unknown Source)
at proxy.DynamicProxyTest.main(DynamicProxyTest.java:143)
Caused by: java.lang.IndexOutOfBoundsException: Index: 3, Size: 3
at java.util.ArrayList.RangeCheck(ArrayList.java:547)
at java.util.ArrayList.get(ArrayList.java:322)
... 7 more
doFinally...
完毕,通过动态代理机制,实现了传说中的AOP思想。