在Java中,动态代理是指代理类的生成发生在程序运行时期,根据被代理类动态生成代理类的字节码文件(class文件),并且装载到运行环境中,像其他的类一样使用,该字节码文件的生存期随着运行环境的关闭而消失。
首先来一些接口的说明:
[b]InvocationHandler接口[/b]
它定义了唯一的方法invoke,该方法的参数为代理对象proxy,截获的方法对象method,和方法调用的参数,返回方法执行的结果。
开发者需要实现该接口,在invoke方法中添加对截获的方法的代理操作,并调用被代理对象的方法。
[b]Proxy类[/b]
该类是生成代理类的帮助类,它的几个主要方法如下:
public Static Class getProxyClass (ClassLoader loader, Class[] interfaces):根据指定的类加载器和接口获得一个代理类,其中,loader是类加载器,interfaces是被代理类所拥有的接口。
public Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):根据指定的类加载器、接口以及截获器,返回代理类的一个实例对象。
如下写了一个小例子:
一个空的Bean:
一个接口:
一个接口的实现:
一个ProxyFactory:
最后是客户端调用:
最后总结一下:
分析JDK提供的帮助类Proxy,可以发现,它只支持实现接口方式的代理,不支持继承超类方式的代理,这就意味着,被代理的类必须要有接口,并且需要拦截的方法必须都在接口中进行声明。在本例中,通过截获帮助类Proxy生成的代理类的字节码文件,反编译之后,发现,其类的声明如下:
public final class proxy0 extends Proxy implements Command
其中,proxy0就是动态生成的代理类的名字,在该类的方法中,都会将调用委托到拦截器的invoker方法。
因为JDK提供的动态代理仅支持接口方式的代理,那么如果被代理的类没有实现任何接口,如何处理呢?后续将探讨基于CGLib的动态代理,它同时也支持继承超类的方式的代理。
[color=red]
注:文字部分转自互联网[/color]
首先来一些接口的说明:
[b]InvocationHandler接口[/b]
它定义了唯一的方法invoke,该方法的参数为代理对象proxy,截获的方法对象method,和方法调用的参数,返回方法执行的结果。
开发者需要实现该接口,在invoke方法中添加对截获的方法的代理操作,并调用被代理对象的方法。
[b]Proxy类[/b]
该类是生成代理类的帮助类,它的几个主要方法如下:
public Static Class getProxyClass (ClassLoader loader, Class[] interfaces):根据指定的类加载器和接口获得一个代理类,其中,loader是类加载器,interfaces是被代理类所拥有的接口。
public Static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h):根据指定的类加载器、接口以及截获器,返回代理类的一个实例对象。
如下写了一个小例子:
一个空的Bean:
package com.jzkangta.demo.bean;
public class Person {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
一个接口:
package com.jzkangta.demo.dao;
import com.jzkangta.demo.bean.Person;
public interface PersonDao {
public void savePerson();
public void updatePerson();
public void deletePerson();
public Person findPerson();
}
一个接口的实现:
package com.jzkangta.demo.dao.impl;
import com.jzkangta.demo.bean.Person;
import com.jzkangta.demo.dao.PersonDao;
public class PersonDaoImpl implements PersonDao {
@Override
public void deletePerson() {
// TODO Auto-generated method stub
System.out.println("删除用户了........");
}
@Override
public Person findPerson() {
// TODO Auto-generated method stub
System.out.println("查找用户了........");
return null;
}
@Override
public void savePerson() {
// TODO Auto-generated method stub
System.out.println("添加用户了........");
}
@Override
public void updatePerson() {
// TODO Auto-generated method stub
System.out.println("修改用户了........");
}
}
一个ProxyFactory:
package com.jzkangta.demo.aop;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyFactory implements InvocationHandler {
private Object targetObject; // 需要代理的目标对象
//创建代理对象 也可以用构造方法来做
public Object createProxyIntance(Object targetObject) {
this.targetObject = targetObject;
return Proxy.newProxyInstance(this.targetObject.getClass()
.getClassLoader(),// 第一个参数为代理目标对象的类装载器
this.targetObject.getClass().getInterfaces(), // 第二个参数为代理目标对象的所有接口,Proxy会为该目标类实现其下所有的接口
this); // 第三个参数是当拦截到代理请求的时候,使用哪个来处理代理 一般为代理的类 当前类 该类必须实现implements
// InvocationHandler接口,然后执行invoke方法
}
@Override
public Object invoke(Object arg0, Method method, Object[] arg2)
throws Throwable {
testFunction();
//此处可以加逻辑判断,只有正确才执行method.invoke方法
Object result = method.invoke(targetObject, arg2); //这里是指需要调用目标代理对象的最终方法
return result;
}
public void testFunction(){
System.out.println("执行额外的功能方法.........");
}
}
最后是客户端调用:
package com.jzkangta.demo;
import com.jzkangta.demo.aop.ProxyFactory;
import com.jzkangta.demo.dao.PersonDao;
import com.jzkangta.demo.dao.impl.PersonDaoImpl;
public class Test {
/**
* @param args
*/
public static void main(String[] args) {
// TODO Auto-generated method stub
ProxyFactory proxyFactory = new ProxyFactory();
PersonDao personDao = (PersonDao)proxyFactory.createProxyIntance(new PersonDaoImpl());
personDao.savePerson();
}
}
最后总结一下:
分析JDK提供的帮助类Proxy,可以发现,它只支持实现接口方式的代理,不支持继承超类方式的代理,这就意味着,被代理的类必须要有接口,并且需要拦截的方法必须都在接口中进行声明。在本例中,通过截获帮助类Proxy生成的代理类的字节码文件,反编译之后,发现,其类的声明如下:
public final class proxy0 extends Proxy implements Command
其中,proxy0就是动态生成的代理类的名字,在该类的方法中,都会将调用委托到拦截器的invoker方法。
因为JDK提供的动态代理仅支持接口方式的代理,那么如果被代理的类没有实现任何接口,如何处理呢?后续将探讨基于CGLib的动态代理,它同时也支持继承超类的方式的代理。
[color=red]
注:文字部分转自互联网[/color]