zoukankan      html  css  js  c++  java
  • JAVA动态代理详解

    1.什么是代理

    代理模式是常用的Java 设计模式,它的特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。

    2.什么是动态代理

    在程序运行时,运用反射机制动态创建代理实例对象。JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理。

    相关类与接口

    java.lang.reflect.Proxy:这是 Java 动态代理机制的主类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。 
    
    // 方法:该方法用于为指定类装载器、一组接口及调用处理器生成动态代理类实例
    static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
    
    java.lang.reflect.InvocationHandler:这是调用处理器接口,它自定义了一个 invoke 方法,用于集中处理在动态代理类对象上的方法调用,通常在该方法中实现对委托类的代理访问。 
    
    //方法:调用处理器根据这三个参数进行预处理或分派到委托类实例上发射执行
    Object invoke(Object proxy, Method method, Object[] args)

    3.动态代理示例

    代理类
    public class LogHandler implements InvocationHandler {
        
        private Object targetObject;
        
        public Object newProxyInstance(Object targetObject) {
            this.targetObject = targetObject;
            return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
                                   targetObject.getClass().getInterfaces(), this);
        }
        
        public Object invoke(Object proxy, Method method, Object[] args)
                throws Throwable {
            System.out.println("start-->>" + method.getName());
            for (int i=0; i<args.length; i++) {
                System.out.println(args[i]);
            }
            Object ret = null;
            try {
                //调用目标方法
                ret = method.invoke(targetObject, args);
                System.out.println("success-->>" + method.getName()); 
            }catch(Exception e) {
                e.printStackTrace();
                System.out.println("error-->>" + method.getName());
                throw e;
            }
            return ret;
        }
    
    }
    接口类
    public interface UserManager {
    
        public void addUser(String userId, String userName);
    }
    目标类
    package com.bjpowernode.pattern;
    
    public class UserManagerImpl implements UserManager {
    
        public void addUser(String userId, String userName) {
            //System.out.println("start-->>addUser() userId-->>" + userId);
            try {
                System.out.println("AddUser" );
    }
        }
    }
    客户端
    public class Client {
    
        /**
         * @param args
         */
        public static void main(String[] args) {
            LogHandler logHandler = new LogHandler();
            UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());
            userManager.addUser("0001","张三");    }
    
    }

    4.动态代理类与静态代理的区别:

    由程序员创建或由特定工具自动生成源代码,再对其编译。在程序运行前,代理类的.class文件就已经存在了。动态代理类:在程序运行时,运用反射机制动态创建而成。无需程序员手工编写它的源代码。动态代理类不仅简化了编程工作,而且提高了软件系统的可扩展性,因为Java 反射机制可以生成任意类型的动态代理类。

    5.动态类的应用场景

    不允许直接访问某些类;对访问要做特殊处理等。或者,要对原方法进行统一的扩展,例如加入日志记录。

    6.什么是CGLIB动态代理

    JDK的动态代理机制只能代理实现了接口的类,而不能实现接口的类就不能实现JDK的动态代理,cglib是针对类来实现代理的,他的原理是对指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。

    7.CGLIB示例

    委托类:

    package com.orient.cglib;
    
    public class BookFacadeImpl1 {  
        public void addBook() {  
            System.out.println("增加图书的普通方法...");  
        }  
    }

    代理类

    package com.orient.cglib;
    
    import java.lang.reflect.Method;
    
    import net.sf.cglib.proxy.Enhancer;
    import net.sf.cglib.proxy.MethodInterceptor;
    import net.sf.cglib.proxy.MethodProxy;
    
    public class BookFacadeCglib implements MethodInterceptor {  
        private Object target;  
      
        /** 
         * 创建代理对象 
         *  
         * @param target 
         * @return 
         */  
        public Object getInstance(Object target) {  
            this.target = target;  
            Enhancer enhancer = new Enhancer();  
            enhancer.setSuperclass(this.target.getClass());  
            // 回调方法  
            enhancer.setCallback(this);  
            // 创建代理对象  
            return enhancer.create();  
        }  
      
        @Override  
        // 回调方法  
        public Object intercept(Object obj, Method method, Object[] args,  
                MethodProxy proxy) throws Throwable {  
            System.out.println("事物开始");  
            proxy.invokeSuper(obj, args);  
            System.out.println("事物结束");  
            return null;  
      
      
        }  
      
    }

    测试类

    package com.orient.cglib;
    
    public class TestCglib {
        public static void main(String[] args) {  
            BookFacadeCglib cglib=new BookFacadeCglib();  
            BookFacadeImpl1 bookCglib=(BookFacadeImpl1)cglib.getInstance(new BookFacadeImpl1());  
            bookCglib.addBook();  
        }  
    }

    这个工程依赖于cglib.jar 和asm.jar

  • 相关阅读:
    linux下安装mysql
    简单理解:使用linux的ip地址访问Java项目
    上传项目到github完整步骤及如何删除项目
    解决service iptables save出错please try to use systemctl.
    PCI1255信号采集板卡的干扰来源和解决办法
    L298N驱动的再利用
    千里狼-高速采集相机试用记录
    调试研华PCI1245E记录
    超大型的迷宫
    labview实现模拟python微信模块
  • 原文地址:https://www.cnblogs.com/zhulongchao/p/4581943.html
Copyright © 2011-2022 走看看