❶代理的作用
为了便于在目标类的方法之前和之后加上一些系统功能而存在
(如:异常处理、日志、计算方法的运行时间、事务管理),当调用
代理类方法的时候它会调用目标类里面的相同方法
❷代理的运用场景
比方说客户端想要调用调用有记录日志的功能的相关方法那么就在
配置文件里面配置代理类,当不需要日志功能的时候则配置目标类,
这样,增加系统功能很方便,以后运行一段时间后,又想去掉系统功能也
很方便AOP:(切面编程)就运用了代理,其要领就是在要调用的方法功能之
前或之后添加其他功能方法
❸JVM生成的动态类必须实现一个或多个接口
JVM生成的动态类只能用具有相同接口目标类的代理,如果该类没有接口
可以使用CGLIB库可以动态生成一个类的动态代理子类
❹以被代理对象转发被InvocationHandler.invoke()处理的方法有
①类中继承下来的除了hashCode、equals 或 toString,
② 代理对象需要实现的接口方法;然而其他的方法都有它们自己的实现如getClass();
❺动态代理的工作原理
客户端调用代理,代理对象的构造方法接受一个handler对象,客户端调用代理的
各个方法,各个方法会把调用请求转发给通过构造方法传递进来的那个handler
对象handler对象再通过method(客户端调用的那个方法)调用目标类的相应方法
❻JVM生成动态代理类的两种方法
①第一种方式
//1.获得代理类的Class类
Class clazzProxy1 = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
//2.从class类中得到构造器类
Constructor constructor = clazzProxy1.getConstructor(InvocationHandler.class);
//3.通过构造器类对象实例化一个代理类
Collection proxy2 = (Collection)constructor.newInstance(new InvocationHandler(){
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
});System.out.println(proxy3);
proxy3.clear();
proxy3.size();
//target为目标代理类
Object proxy3 = Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
new InvocationHandler(){ //参数分别是:代理的对象,代理调用的方法,调用方法时传递的参数
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return null;
}
}
);
❼遇到的问题
在6点的①中System.out.println(proxy3);打印结果为null
proxy3.clear();
proxy3.size();而这句执行的时候报错
①解释以上原因
打印proxy3的时候由于invoke返回的是null,而System.out.println(proxy3);相当于执行的是System.out.println(proxy3.toString);前面第四点我们就说toString可以被invoke()处理所以返回结果是null那么就打印出null字符串
②proxy3.size()这句出错的原因
是因为代理类是这样的
Class Proxy$ {
int size() {
//因为size()方法需要返回的值是int型而返回的值却是null所以报错
return handler.invoke(Object proxy, Method method, Object[] args);
}
❽为了更加的面向对象和更好的编码常常把目标类和系统功能类抽取出来
/**
* @param target传递目标的类
* @param advice传递系统功能
* @return动态生成的代理类
*/
private static Object getProxy(final Object target, final Advice advice)
{
Object proxy3 = Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), new InvocationHandler()
{
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;
}
❾零散知识点
每一个class要加载到内存来必须要有一个类加载器
StringBuilder不考虑多线程其效率比StringBuffer高
可变参数只能用于最后
-----------------------------------------android培训、java培训、java学习型技术博客、期待与您交流! --------------------------
详情请查看:http://edu.csdn.net/heima