Java动态代理类使用

Java动态代理类使用

Java动态代理类位于Java.lang.reflect包下,一般主要涉及到以下两个类:

一、Interface InvocationHandler:该接口中仅定义了一个方法Object invoke(Object obj,Method method,Object[] args)。在实际使用时,第一个参数obj一般是指代理类,method是被代理的方法,args为该方法的参数数组。这个抽象方法在代理类中动态实现。

二、Proxy:该类即为动态代理类,其中主要包含以下内容:

Protected Proxy(InvocationHandler h):构造函数,用于给内部的h赋值。

static Class getProxyClass (ClassLoader loader,Class[] interfaces):获得一个代理类,其中loader是类装载器,interfaces是真实类所拥有的全部接口的数组。

static Object newProxyInstance(ClassLoader loader,Class[] interfaces,InvocationHandler h):返回代理类的一个实例,返回后的代理类可以当作被代理类使用(可使用被代理类的在Subject接口中声明过的方法)。

所谓Dynamic Proxy是这样一种class:它是在运行时生成的class,在生成它时你必须提供一组interface给它,然后该class就宣称它实现了这些 interface。你当然可以把该class的实例当作这些interface中的任何一个来用。当然啦,这个Dynamic Proxy其实就是一个Proxy,它不会替你作实质性的工作,在生成它的实例时你必须提供一个handler,由它接管实际的工作。在使用动态代理类时,我们必须实现InvocationHandler接口.

代理机制及特点

通过实现 InvocationHandler 接口创建自己的调用处理器;

通过为 Proxy 类指定 ClassLoader 对象和一组 interface 来创建动态代理类;

通过反射机制获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型;

通过构造函数创建动态代理类实例,构造时调用处理器对象作为参数被传入。

——参考《百度百科》

Proxy类

一般使用Proxy.newProxylnstance(ClassLoader loader,Class[] interfaces,InvocationHandler invocationHandler)来创建代理对象

  • 参数1: loader , 类加载器, 动态代理类运行时创建, 任何类都需要类加载器将其加载到内存。
    • 一般情况: 被代理类.class.getClassLoader()或者被代理类实例.getClass().getClassLoader()
  • 参数2: interfaces代理类需要实现的所有接口。
    • 方式1: 被代理类实例.getClass().getInterfaces()
      • 注意: 只能获得自己接口, 不能获得父元素接口
    • 方式2: new Class[]{ 被代理类.class }
      • 例如:jdbc驱动 –> DriverManager 获得接口 Connection
  • 参数3: invocationHandler处理接口, 一般采用匿名内部类实现。
    • 提供invoke方法,代理类的每一个方法执行时, 都将调用一次invoke方法
    • Object invoke(Object obj,Method method,Object[] args)
      • 参数1: proxy : 代理对象
      • 参数2: method: 代理对象当前执行的方法的描述对象(反射)
        • 获取方法名: method.getName()
        • 执行方法: method.invoke(对象, 实际参数)
      • 参数3: args : 方法实际参数

使用步骤

  1. 创建 被增强对象【被代理对象】
  2. 创建 增强对象 【代理对象】
    1. 通过被代理对象获取类加载器
      被代理对象.getClass().getClassLoader()
    2. 通过被代理对象获取其所有的接口
      被代理对象.getClass().getInterfaces()
    3. 创建一个处理类 【专门用来增强方法】

PS:动态代理技术实现的是接口中方法的代理,如果接口中没有的方法,动态代理是没法增强的!

案例:编码问题动态代理解决

index.jsp

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta charset="UTF-8">
        <title>首页</title>
    </head>
    <body>
        <h1>get请求</h1>
        <form action="${pageContext.request.contextPath}/EncodingServlet" method="get">
            <input type="text" name="username" /><br/>
            <input type="submit" value="提交"/>
        </form>
        <br/>
        <h1>post请求</h1>
        <form action="${pageContext.request.contextPath}/EncodingServlet" method="post">
            <input type="text" name="username" /><br/>
            <input type="submit" value="提交"/>
        </form>
    </body>
</html>

EncodingFilter.java

package com.pc.web.filter;

import java.io.IOException;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import javax.servlet.Filter;
import javax.servlet.FilterChain;

import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 编码过滤器,使用动态代理解决编码问题
 * 
 * @author Switch
 * @data 2016年10月25日
 * @version V1.0
 */
public class EncodingFilter implements Filter {
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        final HttpServletRequest req = (HttpServletRequest) request;
        HttpServletResponse res = (HttpServletResponse) response;

        // 处理POST乱码问题
        req.setCharacterEncoding("utf-8");

        // 处理GET乱码问题
        // 创建HttpServletRequest代理对象
        // 参数1:ClassLoader loader 该代理类的类加载器
        // 参数2:Class<?>[] interfaces 该代理类的接口
        // 参数3:InvocationHandler h 代理实例的调用处理程序 实现的接口
        HttpServletRequest reqProxyInstance = (HttpServletRequest) Proxy.newProxyInstance(
                req.getClass().getClassLoader(), req.getClass().getInterfaces(), new InvocationHandler() {
                    // 参数1:Object proxy 代理实例
                    // 参数2:Method method 某一方法
                    // 参数3:Object[] args 参数列表
                    @Override
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 当当前方法是"getParameter"时,增强该方法
                        if ("getParameter".equals(method.getName())) {
                            // 反射获取"getParameter"方法的返回值
                            String value = (String) method.invoke(req, args);
                            // GET请求方式则处理乱码问题
                            if ("GET".equalsIgnoreCase(req.getMethod())) {
                                value = new String(value.getBytes("iso8859-1"), "utf-8");
                            }
                            // 返回该值
                            return value;
                        }
                        // 返回其他方法的值,并没有进行处理(增强)
                        return method.invoke(req, args);
                    }
                });

        // 放行,使用动态代理对象
        chain.doFilter(reqProxyInstance, res);
    }

    public void init(FilterConfig fConfig) throws ServletException {

    }

    public void destroy() {

    }
}

EncodingServlet.java

package com.pc.web.servlet;

import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * 编码测试Servlet
 * 
 * @author Switch
 * @data 2016年10月25日
 * @version V1.0
 */
public class EncodingServlet extends HttpServlet {

    public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String username = request.getParameter("username");
        System.out.println(username);
    }

    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("text/html;charset=utf-8");
        String username = request.getParameter("username");
        System.out.println(username);
    }

}

PS:编码问题的装饰者解决:过滤器Filter

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值