您的位置:首页 > 编程语言 > Java开发

深入理解JAVA JDK动态代理机制

2014-09-26 14:21 1081 查看

一、现实生活中的代理?

在现实生活中,我们常见的有服务器代理商、联想PC代理商、百事可乐、火车票、机票等代理商,为什么会有这些个代理商呢?设想以买火车票为场景,如果我要买一张从广州去长沙的火车票,就必须去火车站排队购票,如果排队的人比较多的话,非常的耽误时间。但有了火车票代理商之后,我就可以直接去找个离我最近的代理商买票,因为这样的代理商不止一个二个,遍布全市各地。 所以代理商的出现不但减轻了火车站售票员的工作压力,同时也为市民购票提供了许多方便。只是代理商会收5块的手续费。从这个示例中可以发现和买票有关的一些名词:火车站、售票、代理商?解释这些名词在程序中代理的含义:火车站:称为目标,售票:目标的最终行为,代理商:和火车站具有同样售票行为的代理商,不过代理商在售票前和售票后会做一些操作,比如查询余票、售票后收取手续费等操作。

二、JDK中的代理

1、特征:
1)、jdk中代理的一个很重要的特征:代理类和目标类都拥有相同的接口,所以它们都拥有相同的行为。代理类的对象本身并不真正提供服务,而是调用目标类对象的相关方法,来提供特定的服务。如:火车票代理商自己并不提供火车票销售的服务,而是调用火车站的售票服务。为顾客提供查询余票信息、火车的运营时间、火车票的销售等服务,这些服务都是来自火车站(目标类)。代理类主要负责为目标类预处理消息(如:身份证信息是否正确)、过滤消息(如:该顾客是否为通缉犯,是否公安监视的人),并把这些消息转发给目标类,以及事后处理消息(收取顾客的手续费)等。
2)、必须实现一个或多个接口

2、代理种类:

1)、静态代理,示例:以销售火车票为例

a、定义一个火车站售票的接口

[java] view
plaincopyprint?

package proxy;

public interface Ticket
{

public void ticket();

}

[java] view
plaincopyprint?

package proxy;

public interface Ticket {

public void ticket();

}

b、售票接口的实现类

[java] view
plaincopyprint?

package proxy;

public class TicketImpl implements Ticket
{

@Override

public void ticket()
{

System.out.println("成功售出一张火车票!");

}

}

[java] view
plaincopyprint?

package proxy;

public class TicketImpl implements Ticket {

@Override

public void ticket() {

System.out.println("成功售出一张火车票!");

}

}

c、火车票销售的代理类,与目标类实现了相同的接口

[java] view
plaincopyprint?

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("售票后收取顾客的手续费…………");

}

}

[java] view
plaincopyprint?

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、测试类:

[java] view
plaincopyprint?

package proxy;

public class StaticProxyTest
{

public static void main(String[]
args) throws Exception {

TicketImpl ticketImpl = new TicketImpl(); //要代理的目标

TicketImplProxy staticProxy = new TicketImplProxy(ticketImpl);

staticProxy.ticket();

}

}

[java] view
plaincopyprint?

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代理类的字节码文件

[java] view
plaincopyprint?

Class clazzProxy = Proxy.getProxyClass(ArrayList.class.getClassLoader(),
ArrayList.class.getInterfaces());

[java] view
plaincopyprint?

Class clazzProxy = Proxy.getProxyClass(ArrayList.class.getClassLoader(), ArrayList.class.getInterfaces());

2、打印代理类的结构信息
获得这个Class对象的字节码文件之后,我们打印出来看看这个类的名字叫什么?

[java] view
plaincopyprint?

System.out.println("代理类名称:" +
clazzProxy.getName());

[java] view
plaincopyprint?

System.out.println("代理类名称:" + clazzProxy.getName());

代理类名称:$Proxy0
通过JDK反射机制,获代理类的结构,比如:它的父类是谁?实现了哪些接口?有哪些个构造方法?有哪些个成员方法?等。。。
下面将通反射机制,获取这个代理类的组织结构信息:

[java] view
plaincopyprint?

System.out.println("代理类" +
clazzProxy.getName() + "的父类:" + clazzProxy.getSuperclass().getName());

[java] view
plaincopyprint?

System.out.println("代理类" + clazzProxy.getName() + "的父类:" + clazzProxy.getSuperclass().getName());

代理类$Proxy0的父类:java.lang.reflect.Proxy

[java] view
plaincopyprint?

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);

[java] view
plaincopyprint?

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

[java] view
plaincopyprint?

System.out.println("代理类" +
clazzProxy.getName() + "的访问修饰符:" + clazzProxy.getModifiers());

[java] view
plaincopyprint?

System.out.println("代理类" + clazzProxy.getName() + "的访问修饰符:" + clazzProxy.getModifiers());

代理类$Proxy0的访问修饰符:17

由访问修饰符的值可得知代理类的修饰符为:代理类的访问修饰符为:public final,由clazzProxy.getModifiers();得知为17,其中public代表1,final代表16,相加得17。参考java.lang.reflect.Modifier

[java] view
plaincopyprint?

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());

}

[java] view
plaincopyprint?

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)

[java] view
plaincopyprint?

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());

}

[java] view
plaincopyprint?

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());

}

打印结果:

[java] view
plaincopyprint?

-------------打印代理类$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()

[java] view
plaincopyprint?

-------------打印代理类$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类,因为代理类会自动实现目标类相同的接口。

[java] view
plaincopyprint?

//由上述信息可推断出代理类的文件结构(程序中只实现打印代理类的声明部份)

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);

[java] view
plaincopyprint?

//由上述信息可推断出代理类的文件结构(程序中只实现打印代理类的声明部份)

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 { }

由上述信息可推断出代理类的文件结构:

[java] view
plaincopyprint?

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;

}

}

[java] view
plaincopyprint?

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参数的构造方法,现在我们来生成这个代理类的实例对象:

[java] view
plaincopyprint?

//方式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());

[java] view
plaincopyprint?

//方式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

[java] view
plaincopyprint?

//方式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;

}}

);

[java] view
plaincopyprint?

//方式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;

}}

);

[java] view
plaincopyprint?

//方式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());

[java] view
plaincopyprint?

//方式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

*通过以上代码的分析,可将生成代理类的代码,抽取成一个生成代理的通用方法,并将功能代码用一个对象封装起来(如:测试方法的运行时间,方法运行前或运行后需要做的事情)

[java] view
plaincopyprint?

/**

* 获得代理对象

* @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;

}}

);

}

[java] view
plaincopyprint?

/**

* 获得代理对象

* @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;

}}

);

}

封装功能的对象:

[java] view
plaincopyprint?

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);

}

[java] view
plaincopyprint?

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,用于测试:

[java] view
plaincopyprint?

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...");

}

}

[java] view
plaincopyprint?

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...");

}

}

测试生成代理的通用方法:

[java] view
plaincopyprint?

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

[java] view
plaincopyprint?

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

输出结果:

[java] view
plaincopyprint?

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...

[java] view
plaincopyprint?

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思想。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: