但行好事
莫论前程❤

java基础学习总结-特性-动态代理

简介

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用

优点:

  • 职责清晰

    真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务, 通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。

  • 代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了的作用和保护了目标对象的作用。

  • 高扩展性

    结构 一个是真正的你要访问的对象(目标类),另一个是代理对象, 真正对象与代理对象实现同一个接口,由代理控制目标对象的一切方法。

创建动态代理的步骤

  • 目标对象必须要实现一个接口,代理对象实现这个接口从而能够实现这些方法。
  • 创建动态代理对象,传入三个参数。
参数1:加载目标类的类加载器。web工程发布后由类加载器web-inf的classes中,从而能够找到该目标类 。
参数2:目标对象实现的接口。
参数3:代理类对目标对象方法的控制器。new InvocationHandler(proxy,method,args);
  • new InvocationHandler(Object proxy,Method method,Parameter args)对目标对象方法的控制。在这里可以进行方法增强等操作。
1. 参数1: proxy,当前代理对象的引用。一般不使用它
2. 参数2: method,调用方法时该方法的字节码对象。
3. 参数3: args,调用方法时传递进来的实际参数  

例:

1. 要实现的共同接口:
public interface TargetInterface {
    public abstract void method1();
    public abstract String method2();
    public abstract int method3(int num);
}
2. 被代理的目标类
//代理对象和目标对象必须实现同一个接口,即动态代理对象必须成为共同接口的实现类对象,这样就具备了共同的方法
//在jdk中,动态代理和目标对象必须共同实现一个接口,才能实现动态代理
public class Target implements TargetInterface {

    public void method1() {
        System.out.println("method1");
    }

    public String method2() {
        System.out.println("method2");
        return "method2";
    }

    public int method3(int num) {
        System.out.println("method3");
        return num;
    }

}
3. 代理类并测试
public class ProxyTest {
    public static void main(String[] args) {

        final Target target = new Target();

        TargetInterface proxy = (TargetInterface) Proxy.newProxyInstance(//
                target.getClass().getClassLoader(), // 要代理的目标对象的类加载器
                target.getClass().getInterfaces(), // 和目标对象实现共同的接口
                new InvocationHandler() { // 调用目标对象的某个方法
                    // 参数1:proxy : 动态代理对象
                    // 参数2:method : 要调用的目标对象的方法的字节码对象
                    // 参数3:args : 调用目标对象的方法时传递的参数
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 动态代理调用目标函数的方法
                        Object invoke = method.invoke(target, args);
                        return invoke;// 返回调用目标函数方法后的返回值
                    }
                });

        // 使用动态代理对象调用方法
        proxy.method1();// 使用目标函数对象,需要将动态代理的类型从Object强转为接口对象的实现子类(多态)
        String method2 = proxy.method2();
        int method3 = proxy.method3(100);

        System.out.println(method2);
        System.out.println(method3);
    }
}
1.3 使用动态代理解决全站编码问题
1. 分析
  • 首先创建一个表单页面和一个servlet小程序用于测试。
  • 要对全站编码进行控制,需要经过Filter过滤器进行控制,过滤路径url-pattern设为/*即对所有请求进行拦截。
  • 需求:我们解决的是servlet中获取参数的getParameter()方法时及servlet写回数据到客户端时的乱码问题。
  • 使用动态代理解决,首先找到需要被代理的对象是HttpServletRequest的实现类对象.
    • 创建一个动态代理。
    • 获取目标对象的类加载器,与目标对象实现同一个接口HttpServletRequest。
    • 在new InvocationHandler()方法控制器中找到getParameter()方法进行增强,在这里面解决乱码逻辑。
    • 对于其他无需改变的方法,不进行改变,按原来的逻辑返回。
    • 放行(这里的参数request要改为动态代理对象proxy了,这样servlet调用getParameter方法才是增强后的)。

2. 代码实现

这里省略jsp页面和servlet程序的代码,就是一个简单的jsp表单提交和回写数据

Filter的动态代理代码这里省略jsp页面和servlet程序的代码,就是一个简单的jsp表单提交和回写数据
Filter的动态代理代码
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain)
        throws IOException, ServletException {
    // 需求: 使用动态代理解决全站编码问题

    // 1. 强制转换
    final HttpServletRequest request = (HttpServletRequest) req;
    HttpServletResponse response = (HttpServletResponse) resp;
    response.setContentType("text/html;charset=UTF-8");// 设置服务器写回客户端的编码格式

    // 2. 业务逻辑 : 使用动态代理解决全站编码问题
    // 2.1 创建动态代理对象,返回的是和目标对象实现了同一接口的动态代理对象
    HttpServletRequest proxy = (HttpServletRequest) Proxy.newProxyInstance( //
            request.getClass().getClassLoader(), // 参数1:加载目标对象的类加载器
            request.getClass().getInterfaces(), // 参数2:与目标对象实现相同的接口
            new InvocationHandler() {// 参数3:目标对象的方法控制器,即如何代理?

                // 参数1:proxy:就是当前的动态代理对象
                // 参数2:method:代理对象调用目标对象的某个方法的字节码对象
                // 参数3:args:调用某个方法时传递的参数
                public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                    // 判断找出getParameter()方法进行方法曾倩
                    if ("getParameter".equals(method.getName())) {
                        // 解决编码集的代码
                        // 获取表单提交的方式
                        String requestMethod = request.getMethod();
                        if ("GET".equalsIgnoreCase(requestMethod)) { // 如果是get方式提交数据
                            // 获取提交的数据
                            String parameter = (String) method.invoke(request, args);
                            // 对获取的数据重新编解码
                            parameter = new String(parameter.getBytes("ISO-8859-1"), "UTF-8");
                            return parameter;
                        } else if ("POST".equalsIgnoreCase(requestMethod)) {
                            request.setCharacterEncoding("UTF-8");
                        }
                    }
                    // 对于不需增强的方法,按原来的逻辑执行后返回,不做任何修改
                    return method.invoke(request, args);
                }
            });

    // 3. 放行(将与request实现了同一接口的动态代理作为参数传递放行)
    chain.doFilter(proxy, response);
}
赞(0) 打赏
未经允许不得转载:刘鹏博客 » java基础学习总结-特性-动态代理
分享到: 更多 (0)

评论 抢沙发

评论前必须登录!

 

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏