第1章 使用动态代理解决网站的字符集编码
1.1 介绍
学习过滤器时,我们使用“装饰者”对request进行增强,从而使get和post使用 request.getParameter()获得的数据都没有乱码。本案例我们将使用一个全新的技术—动态代理,对“统一GET和POST乱码”案例进行重写。
//创建一个与代理对象相关联的InvocationHandler InvocationHandler stuHandler = new MyInvocationHandler<Person>(stu); //创建一个代理对象stuProxy,代理对象的每个执行方法都会替换执行Invocation中的invoke方法 Person stuProxy= (Person) Proxy.newProxyInstance(Person.class.getClassLoader(), new Class<?>[]{Person.class}, stuHandler);
1.2 相关知识点:Proxy
l Proxy.newProxyInstance 三个参数
n 参数1:loader ,类加载器,动态代理类运行时创建,任何类都需要类加载器将其加载到内存。
u 一般情况:当前类.class.getClassLoader();
n 参数2:Class[] interfaces 代理类需要实现的所有接口
u 方式1:目标类实例.getClass().getInterfaces();
注意:只能获得自己接口,不能获得父元素接口
u 方式2:new Class[]{UserService.class}
例如:jdbc 驱动 --> DriverManager 获得接口 Connection
n 参数3:InvocationHandler 处理类,接口,必须进行实现类,一般采用匿名内部
u 提供 invoke 方法(以下三个参数),代理类的每一个方法执行时,都将调用一次invoke
l 参数31:Object proxy :代理对象
l 参数32:Method method : 代理对象当前执行的方法的描述对象(反射)
执行方法名:method.getName()
执行方法:method.invoke(对象,实际参数)
l 参数33:Object[] args :方法实际参数
1.1 案例实现
@WebFilter("/*")
public class EncodingFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
@Override
public void doFilter(ServletRequest req, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
HttpServletRequest requestProxy = (HttpServletRequest)Proxy.newProxyInstance(
EncodingFilter.class.getClassLoader(),
new Class[]{HttpServletRequest.class},
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("get".equals(request.getMethod())) {
//对指定方法进行增强
if("getParameter".equals(method.getName())){
// 执行方法获得返回值
String value = (String) method.invoke(request, args);
return new String(value.getBytes("UTF-8") , "UTF-8");
}
}
//放行
return method.invoke(request, args);
}
});
//放行
chain.doFilter(requestProxy, response);
}
@Override
public void destroy() {
}
}
l 使用 类.class.getClassLoader() 获得加载自己的类加载器
l 类加载器加载机制:全盘负责委托机制
全盘负责:A类如果要使用B类(不存在),A类加载器C必须负责加载B类。
委托机制:A类加载器如果要加载资源B,必须询问父类加载是否加载。
如果加载,将直接使用。
如果没有机制,自己再加载。
l 采用 全盘负责委托机制 保证 一个class文件 只会被加载一次,形成一个Class对象。
l 注意:
如果一个class文件,被两个类加载器加载,将是两个对象。
提示 com.itheima.Hello 不能强制成 com.itheima.Hello
h.getClass() -->A h.getClass() -->B
自定义类加载,可以将一个class文件加载多次