JavaEE学习日志持续更新----> 必看!JavaEE学习路线(文章总汇)
动态代理
装饰者设计模式
装饰者设计模式(静态代理)和动态代理的目的:增强原有对象的功能(连接池方法close)
设计模式基于面向对象思想
装饰思想在IO中大量应用,所有的缓冲流、打印流都叫装饰流
Reader(原始流) BufferedReader(装饰流)
如:地暖,就是地面的装饰者,保留地面原有的承重功能,添加了取暖效果
使用IO流时,new BufferedReader(原始流)
实现装饰者模式的步骤:
- 被装饰者和装饰者必须拥有相同的父类,或者实现相同的接口
- 使用装饰者的同时,必须提供被装饰者,new 装饰者(被装饰者)
- 方法如果不需要增强,直接使用。需要增强,定义或重写
自定义装饰流MyBufferedReader
自定义一个装饰类
模拟方法readLine()
package com.itheima.decoration;
import java.io.IOException;
import java.io.Reader;
/*
自定义一个装饰类
模拟方法readLine()
*/
public class MyBufferedReader extends Reader {
private Reader r;
//new MyBufferedReader(FileReader())
public MyBufferedReader(Reader r){
this.r = r;
}
/*
实现读取文本一行的功能
原有的功能不能破坏,read()可以读取一个字符
利用原有功能read(),实现读取一行
*/
public String readLine() throws IOException{
int len = 0;
StringBuilder sb = new StringBuilder();
//read()返回-1,文件结束
while ((len = r.read())!= -1){
//判断读取到的字符是不是\r, int和char做运算,char自动变成int
if(len == '\r'){
continue;
}
//判断读取到的字符是不是\n
if(len == '\n'){
//这一行读取结束
//从容器中,取出字符串返回
return sb.toString();
}
//有效的字符,追加缓冲区
sb.append((char)len);
}
//文件读取结束,判断缓冲区中是否还有内容
if(sb.length()>0){
return sb.toString();
}
return null;
}
@Override
public int read(char[] chars, int i, int i1) throws IOException {
return 0;
}
@Override
public void close() throws IOException {
r.close();
}
}
测试类
public class Demo {
public static void main(String[] args) throws IOException {
FileReader fr = new FileReader("d:\\1.txt");
//创建自定义的装饰类,传递原始流
MyBufferedReader my = new MyBufferedReader(fr);
String line = null;
while((line=my.readLine())!=null){
System.out.println(line);
}
my.close();
}
}
类加载器
类加载器(ClassLoader)
作用:加载运行的class文件进入内存,并创建class对象。
动态代理原理
Proxy工具类
实现动态代理
- 被代理对象 :ArrayList (方法:add,size,get,remove)
- 代理对象,只要使用被代理对象的方法,通过代理对象
如:代理对象让别人只能用ArrayList的size方法
Proxy类的方法
static Object newProxyInstance(ClassLoader loader, 类<?>[] interfaces, InvocationHandler h)
返回指定接口的代理实例,该接口将方法调用分派给指定的调用处理程序。
方法参数:
- 传递被代理对象的加载器
ArrayList.class.getClassLoader
- 被代理对象实现的所有接口ArrayList.class.getInterfaces
- InvocationHandler接口实现类,代理对象执行的方法
返回值Object:被代理后的对象
InvocationHandler接口方法:
Object invoke(Object proxy, 方法 method, Object[] args)
处理代理实例上的方法调用并返回结果。
方法参数:
proxy
: 被代理的对象ArrayListmethod
:被代理对象的方法,如:add,size,get,removeargs
:被代理对象的方法的实际参数
返回值Objec
t:执行被代理对象的方法的返回值。如:被代理对象的size() 返回长度
实现动态代理:让被代理对象ArrayList只能调用size()方法
public class Demo {
public static void main(String[] args) {
ArrayList<String> list = new ArrayList<>();
list.add("1");
list.add("2");
list.add("3");
//方法getProxy,返回被代理后的对象
List<String> proxyList = getProxy(list);
System.out.println(proxyList.size());//3
System.out.println(proxyList.get(0));//java.lang.RuntimeException: 禁止调用该方法
}
/*
定义方法,实现ArrayList对象的动态代理
生成被代理的对象,执行集合的方法size被允许
传递被代理的对象,返回代理后的对象
*/
public static List<String> getProxy(ArrayList<String> list){
//传递被代理对象的加载器
//传递被代理对象实现的接口
//传递InvocationHandler接口的实现类
//返回值:被代理后的对象
return (List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() {
/*
被代理对象执行的方法
调用集合的任意方法,都会执行invoke
proxy:被代理的对象
method:被代理对象调用的方法
objects:调用方法传递的实际参数
返回值:被调用方法的返回值
Method类方法:getName()获取执行的方法名
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//不是size方法,就不让调用
String name = method.getName();
if("size".equals(name)){
//是size,允许调用方法,size()返回长度
return method.invoke(list,args);
}else {
throw new RuntimeException("禁止调用该方法");
}
}
});
}
}