代理

优秀文章

博客:
ykzhen2015 > MyBATIS插件原理第一篇——技术基础(反射和JDK动态代理)
ITEYE:
layznet > java静态代理和动态代理
zheng12tian > java 动态代理学习(Proxy,InvocationHandler)——自己的理解


说明
  • 代理是对真实对象的代表;
  • 代理通常使用接口来规范(JDK动态代理必须满足该条件);

PS:下文中RealSubject为实际类,RealProxy为代理类,首字母小写为各自实例对象。


代理模式
为对象提供一个专用于访该对象的代理对象,外部通过访问代理对象实现对该对象的访问。

静态代理
  1. 设计接口:
    设计接口的目的是为RealSubject与RealProxy规范代理方法,并为两者提供共同的引用;
    public interface Subject {
        public void func1();
        public void func2(String str);
    }
  1. 编写RealSubject类:
    类需实现Subject接口;
    public class RealSubject implements Subject {
        
        public void func1() {
            System.out.println("RealSubject类的func1方法被调用了。");
        }
    
        public void func2(String str) {
            System.out.println("RealSubject类的func2方法被调用了,参数是"+str+"。");
        }
        
    }
  1. 编写Proxy类:
    实现Subject接口并设置被代理对象RealSubject的引用;
    public class RealProxy implements Subject {
        // 在代理对象内声明被代理对象的引用,此处使用接口则可以接收任何实现该接口的代理对象;
        private Subject subject;
        
        // 设置被代理对象实例;
        public void setSubject(Subject subject){
            this.subject = subject;
        }
        
        // 对代理对象的方法代理;
        public void func1() {
            System.out.println("RealProxy类的func1方法被调用了。");
            subject.func1();
        }
        
        public void func2(String str) {
            System.out.println("RealProxy类的func2方法被调用了,参数是"+str+"。");
            subject.func2(str);
        }
        
    }
  1. 实现:
    利用Proxy完成对RealSubject的代理;
    public static void main(String[] args) {
        RealProxy realProxy = new RealProxy();
        realProxy.setSubject(new RealSubject());
        realProxy.func1();
        realProxy.func2("demo");
    }

结果

RealProxy类的func1方法被调用了。
RealSubject类的func1方法被调用了。
RealProxy类的func2方法被调用了,参数是demo。
RealSubject类的func2方法被调用了,参数是demo。


动态代理

动态代理与静态代理不同点在于静态代理需要在RealProxy类中手动对RealSubject类的代理方法进行设置,而动态代理则是通过Java的反射(此处链接我的另一篇文章:反射)机制来实现对RealSubject类的全部代理方法进行设置,这里所指的全部代理方法是通过RealSubject类实现的Subject接口来判定的,因此,要实现动态代理,就必须使用接口规范代理方法,且RealProxy类在动态代理中不需要实现Subject接口而必须实现InvocationHandler接口;

  • 关键接口:InvocationHandler
  • 所有实现动态代理的代理对象都必须实现这个接口;
  • 实现该接口后,所有代理方法都是在invoke()方法中实现,故可以在此方法内设置额外的代理内容;
  • 关键方法:
    Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(), realProxy);
  • 获取具备RealSubject信息的RealProxy对象;
  • 修改RealProxy类:
    public class RealProxy implements InvocationHandler {
        // 在代理对象内声明被代理对象的引用,此处使用接口则可以接收任何实现该接口的代理对象;
        private Subject subject;
        
        // 设置被代理对象实例;
        public void setSubject(Subject subject){
            this.subject = subject;
        }
        
        // 对代理对象的方法代理;
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            Object result = null;
            // 获取参数;
            String str = "";
            if(args!=null && args.length>0){
                for(Object obj : args){
                    String s = (String) obj;
                    str = str + ",参数是" + s;
                }
            }
            System.out.println("RealProxy类的"+method.getName()+"方法被调用了"+str+"。");
            result = method.invoke(subject, args);
            return result;
        }

    }
  • 实现
    public static void main(String[] args) {
        
        RealProxy realProxy = new RealProxy();
        RealSubject realSubject = new RealSubject();
        realProxy.setSubject(realSubject);
        // 获取动态代理对象;
        Subject subject = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(),realSubject.getClass().getInterfaces(), realProxy);
        subject.func1();
        subject.func2("demo");
    }
  • 结果

RealProxy类的func1方法被调用了。
RealSubject类的func1方法被调用了。
RealProxy类的func2方法被调用了,参数是demo。
RealSubject类的func2方法被调用了,参数是demo。


CGLib

CGLib(Code Generation Library)是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。——CGLib百度百科

使用CGLib,可以对未实现接口的代理对象进行代理,其原理是根据代理对象生成新的子类对象,通过拦截子类对象的所有方法来实现动态的代理,使用者所得到的代理对象实质是原代理对象的子类对象。

  • CGLib的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。
  • 由于CGLib由于是采用动态创建子类的方法,对于final方法,无法进行代理。

最后

  • 动态代理是很多框架的基础实现技术,常见的就有Spring的AOP和MaBatis的Mapper;

你可能感兴趣的:(代理)